AR7: core support
Subsystems (7)
PATCH 1/7 AR7: core support
In reply to a message not in the archiveSupport for memory mapping, clock and the vlynq bus
arch/mips/Kconfig +14 -0
@@ -15,6 +15,20 @@ choice prompt "System type" default SGI_IP22 +config AR7 + bool "Texas Instruments AR7" + select BOOT_ELF32 + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select SWAP_IO_SPACE + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_EARLY_PRINTK + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_KGDB + select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_GPIO + config MACH_ALCHEMY bool "Alchemy processor based machines"
arch/mips/Makefile +7 -0
@@ -161,6 +161,13 @@ libs-$(CONFIG_SIBYTE_CFE) += arch/mips/sibyte/cfe/ # # +# Texas Instruments AR7 +# +core-$(CONFIG_AR7) += arch/mips/ar7/ +cflags-$(CONFIG_AR7) += -Iinclude/asm-mips/ar7 +load-$(CONFIG_AR7) += 0xffffffff94100000 + +# # Acer PICA 61, Mips Magnum 4000 and Olivetti M700. # core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/
arch/mips/ar7/Makefile new file +13 -0
@@ -0,0 +1,13 @@ + +obj-y := \ + prom.o \ + setup.o \ + memory.o \ + irq.o \ + time.o \ + platform.o \ + gpio.o \ + clock.o \ + vlynq.o + +EXTRA_AFLAGS := $(CFLAGS)
arch/mips/ar7/clock.c new file +491 -0
491 lines not on this page · raw message
arch/mips/ar7/gpio.c new file +55 -0
55 lines not on this page · raw message
arch/mips/ar7/irq.c new file +203 -0
203 lines not on this page · raw message
arch/mips/ar7/memory.c new file +72 -0
72 lines not on this page · raw message
arch/mips/ar7/platform.c new file +408 -0
408 lines not on this page · raw message
arch/mips/ar7/prom.c new file +320 -0
320 lines not on this page · raw message
arch/mips/ar7/setup.c new file +119 -0
119 lines not on this page · raw message
arch/mips/ar7/time.c new file +46 -0
46 lines not on this page · raw message
arch/mips/ar7/vlynq.c new file +554 -0
554 lines not on this page · raw message
arch/mips/kernel/traps.c +14 -0
@@ -1075,9 +1075,23 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler;if (n ==0 && cpu_has_divec) { +#ifdef CONFIG_AR7 +/* lui k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x200 ) = +0x3c1a0000 | (handler >>16 ); +/* ori k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x204 ) = +0x375a0000 | (handler &0xffff ); +/* jr k0 */ + *(volatile u32 *)(CAC_BASE +0x208 ) =0x03400008 ; +/* nop */ + *(volatile u32 *)(CAC_BASE +0x20C ) =0x00000000 ; +flush_icache_range (CAC_BASE +0x200 ,CAC_BASE +0x210 ); +#else *(volatile u32 *)(ebase +0x200 ) =0x08000000 | (0x03ffffff & (handler >>2 ));flush_icache_range (ebase +0x200 , ebase +0x204 ); +#endif }return (void *)old_handler; }
include/asm-mips/ar7/ar7.h new file +168 -0
168 lines not on this page · raw message
include/asm-mips/ar7/gpio.h new file +120 -0
120 lines not on this page · raw message
include/asm-mips/ar7/mmzone.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* Copyright (C) 2007 Felix Fietkau, Eugene Konev +* +* 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 St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _ASM_MACH_MMZONE_H +#define _ASM_MACH_MMZONE_H + +extern pg_data_t __node_data[]; +#define NODE_DATA (nid) (&__node_data[nid]) +#define NODE_MEM_MAP (nid) (NODE_DATA(nid)->node_mem_map) +#define pa_to_nid (addr) (((addr) >= ARCH_PFN_OFFSET << PAGE_SHIFT) ? 0 : -1) + +#endif /* _ASM_MACH_MMZONE_H */
include/asm-mips/ar7/prom.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (C) 2006, 2007 Florian Fainelli <[email protected]> +* +* 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 St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __PROM_H__ +#define __PROM_H__ + +extern char *prom_getenv (char *name); +extern void prom_printf (char *fmt, ...); + +#endif /* __PROM_H__ */
include/asm-mips/ar7/spaces.h new file +32 -0
@@ -0,0 +1,32 @@ +/* +* 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. +* +* Copyright (C) 1994 - 1999, 2000, 03, 04 Ralf Baechle +* Copyright (C) 2000, 2002 Maciej W. Rozycki +* Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc. +*/ +#ifndef _ASM_AR7_SPACES_H +#define _ASM_AR7_SPACES_H + +#define CAC_BASE 0x80000000 +#define IO_BASE 0xa0000000 +#define UNCAC_BASE 0xa0000000 +#define MAP_BASE 0xc0000000 + +/* +* This handles the memory map. +* We handle pages at KSEG0 for kernels with 32 bit address space. +*/ +#define PAGE_OFFSET 0x94000000UL +#define PHYS_OFFSET 0x14000000UL + +/* +* Memory above this physical address will be considered highmem. +*/ +#ifndef HIGHMEM_START +#define HIGHMEM_START 0x40000000UL +#endif + +#endif /* __ASM_AR7_SPACES_H */
include/asm-mips/ar7/vlynq.h new file +90 -0
90 lines not on this page · raw message
PATCH 2/7 AR7: mtd partition map
In reply to a message not in the archivePartition map support
drivers/mtd/Kconfig +6 -0
@@ -150,6 +150,12 @@ config MTD_AFS_PARTS for your particular device. It won't happen automatically. The 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. +config MTD_AR7_PARTS + tristate "TI AR7 partitioning support" + depends on MTD_PARTITIONS + ---help--- + TI AR7 partitioning support + comment "User Modules And Translation Layers" config MTD_CHAR
drivers/mtd/Makefile +1 -0
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o +obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o # 'Users' - code which presents functionality to userspace. obj-$(CONFIG_MTD_CHAR) += mtdchar.o
drivers/mtd/ar7part.c new file +140 -0
140 lines not on this page · raw message
PATCH 3/7 AR7: gpio char device
In reply to a message not in the archiveChar device to access GPIO pins
drivers/char/Kconfig +9 -0
@@ -928,6 +928,15 @@ config MWAVE To compile this driver as a module, choose M here: the module will be called mwave. +config AR7_GPIO + tristate "TI AR7 GPIO Support" + depends on AR7 + help + Give userspace access to the GPIO pins on the Texas Instruments AR7 + processors. + + If compiled as a module, it will be called ar7_gpio. + config SCx200_GPIO tristate "NatSemi SCx200 GPIO Support" depends on SCx200
drivers/char/Makefile +1 -0
@@ -89,6 +89,7 @@ obj-$(CONFIG_COBALT_LCD) += lcd.o obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o +obj-$(CONFIG_AR7_GPIO) += ar7_gpio.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
drivers/char/ar7_gpio.c new file +158 -0
158 lines not on this page · raw message
PATCH 4/7 AR7: leds driver
In reply to a message not in the archiveSupport for the leds in front of the board usually used to show power status, network traffic, connected eth devices etc.
drivers/leds/Kconfig +6 -0
@@ -18,6 +18,12 @@ config LEDS_CLASS comment "LED drivers" +config LEDS_AR7 + tristate "LED Support for the TI AR7" + depends LEDS_CLASS && AR7 + help + This option enables support for the LEDs on TI AR7. + config LEDS_CORGI tristate "LED Support for the Sharp SL-C7x0 series" depends on LEDS_CLASS && PXA_SHARP_C7xx
drivers/leds/Makefile +1 -0
@@ -5,6 +5,7 @@ obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers +obj-$(CONFIG_LEDS_AR7) += leds-ar7.o obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o
drivers/leds/leds-ar7.c new file +130 -0
130 lines not on this page · raw message
PATCH 6/7 AR7: serial
In reply to a message not in the archiveSerial support, should not broke other archs
drivers/serial/8250.c +11 -0
@@ -267,6 +267,13 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO, }, + [PORT_AR7] = { + .name = "TI-AR7", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, };#if defined (CONFIG_SERIAL_8250_AU1X00 )
@@ -2453,7 +2460,11 @@ static void serial8250_console_putchar(struct uart_port *port, int ch) {struct uart_8250_port *up = (struct uart_8250_port *)port; +#ifdef CONFIG_AR7 +wait_for_xmitr (up,BOTH_EMPTY ); +#else wait_for_xmitr (up,UART_LSR_THRE ); +#endif serial_out (up,UART_TX , ch); }
include/linux/serialP.h +3 -0
@@ -135,6 +135,9 @@ struct rs_multiport_struct {* the interrupt line _up_ instead of down, so if we register the IRQ * while the UART is in that state, we die in an IRQ storm. */ #define ALPHA_KLUDGE_MCR (UART_MCR_OUT2) +#elif defined(CONFIG_AR7 ) +/* This is how it is set up by bootloader... */ +#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2|UART_MCR_OUT1|UART_MCR_RTS|UART_MCR_DTR)#else #define ALPHA_KLUDGE_MCR 0#endif
include/linux/serial_core.h +1 -0
@@ -40,6 +40,7 @@#define PORT_NS16550A 14#define PORT_XSCALE 15#define PORT_RM9000 16/* PMC-Sierra RM9xxx internal UART */ +#define PORT_AR7 16#define PORT_MAX_8250 16/* max port ID */ /*
PATCH 5/7 AR7: watchdog timer
In reply to a message not in the archiveDriver for the watchdog timer. It worked with 2.4, doesn't does with 2.6. Apart that it doesn't reboots the device it works :)
drivers/char/watchdog/Kconfig +6 -0
@@ -583,6 +583,12 @@ config SBC_EPX_C3_WATCHDOG # MIPS Architecture +config AR7_WDT + tristate "TI AR7 Watchdog Timer" + depends on WATCHDOG && AR7 + help + Hardware driver for the TI AR7 Watchdog Timer. + config INDYDOG tristate "Indy/I2 Hardware Watchdog" depends on SGI_IP22
drivers/char/watchdog/Makefile +1 -0
@@ -87,6 +87,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o # M68KNOMMU Architecture # MIPS Architecture +obj-$(CONFIG_AR7_WDT) += ar7_wdt.o obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
drivers/char/watchdog/ar7_wdt.c new file +346 -0
346 lines not on this page · raw message
PATCH 7/7 AR7: ethernet
In reply to a message not in the archiveDriver for the cpmac 100M ethernet driver.
It works fine disabling napi support, enabling it gives a kernel panic when the first IPv6 packet has to be forwarded.
Other than that works fine.
drivers/net/Kconfig +9 -0
@@ -1822,6 +1822,15 @@ config SC92031 To compile this driver as a module, choose M here: the module will be called sc92031. This is recommended. +config CPMAC + tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" + depends on NET_ETHERNET && EXPERIMENTAL && AR7 + select PHYLIB + select FIXED_PHY + select FIXED_MII_100_FDX + help + TI AR7 CPMAC Ethernet support + config NET_POCKET bool "Pocket and portable adapters" depends on PARPORT
drivers/net/Makefile +1 -0
@@ -156,6 +156,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_ZNET) += znet.o obj-$(CONFIG_LAN_SAA9730) += saa9730.o +obj-$(CONFIG_CPMAC) += cpmac.o obj-$(CONFIG_DEPCA) += depca.o obj-$(CONFIG_EWRK3) += ewrk3.o obj-$(CONFIG_ATP) += atp.o
drivers/net/cpmac.c new file +1194 -0
1,194 lines not on this page · raw message
Quoted 1 line · Matteo Croce
Support for memory mapping, clock and the vlynq bus
Just some random comments.
Quoted 9 lines
arch/mips/ar7/Makefile new file +3
-0@@ -0,0 +1,13 @@ + +obj-y := \ + prom.o \
arch/mips/ar7/Makefile line 13
Quoted 10 lines
arch/mips/ar7/Makefile new file +10
-0+ setup.o \ + memory.o \ + irq.o \ + time.o \ + platform.o \ + gpio.o \ + clock.o \ + vlynq.o + +EXTRA_AFLAGS := $(CFLAGS)
This EXTRA_AFLAGS line is redundant. You can drop it safely.
Quoted 5 lines
arch/mips/ar7/irq.c new file +0
-0
...
arch/mips/ar7/irq.c line 22
Quoted 4 lines
arch/mips/ar7/irq.c new file +4
-0+#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/irq.h>
No need to include <linux/irq.h>
Quoted 1 line
+#define REG(addr) (*(volatile u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr))
You can remove this "volatile" rewriting something like:
#define REG_RD(addr) \ readl((void __iomem *)(KSEG1ADDR(AR7_REGS_IRQ) + (addr))) #define REG_WR(val, addr) \ writel(val, (void __iomem *)(KSEG1ADDR(AR7_REGS_IRQ) + (addr)))
arch/mips/ar7/irq.c line 60
Quoted 2 lines
arch/mips/ar7/irq.c new file +2
-0+static struct irq_chip ar7_irq_type = { + .typename ="AR7" ,
The typename is obsolete and not needed if you have name field.
Quoted 25 lines
arch/mips/ar7/irq.c new file +25
-0+static void ar7_unmask_irq (unsigned int irq) +{ +unsigned long flags; +local_irq_save (flags); +/* enable the interrupt channel bit */ +REG (ESR_OFFSET (irq)) =1 << ((irq - ar7_irq_base) %32 ); +local_irq_restore (flags); +} + +static void ar7_mask_irq (unsigned int irq) +{ +unsigned long flags; +local_irq_save (flags); +/* disable the interrupt channel bit */ +REG (ECR_OFFSET (irq)) =1 << ((irq - ar7_irq_base) %32 ); +local_irq_restore (flags); +} + +static void ar7_unmask_secondary_irq (unsigned int irq) +{ +unsigned long flags; +local_irq_save (flags); +/* enable the interrupt channel bit */ +REG (SEC_ESR_OFFSET ) =1 << (irq - ar7_irq_base -40 ); +local_irq_restore (flags);
arch/mips/ar7/irq.c line 116
Quoted 10 lines
arch/mips/ar7/irq.c new file +10
-0+} + +static void ar7_mask_secondary_irq (unsigned int irq) +{ +unsigned long flags; +local_irq_save (flags); +/* disable the interrupt channel bit */ +REG (SEC_ECR_OFFSET ) =1 << (irq - ar7_irq_base -40 ); +local_irq_restore (flags); +}
The mask, unmask routines are always called irq disabled. So you can drop these local_irqsave/restore pairs.
Quoted 5 lines
arch/mips/ar7/irq.c new file +5
-0+for (i =0 ; i <40 ; i++) { +REG (CHNL_OFFSET (i)) = i; +/* Primary IRQ's */ + irq_desc[i + base].status =IRQ_DISABLED ; + irq_desc[i + base].action =NULL ;
arch/mips/ar7/irq.c line 152
Quoted 10 lines
arch/mips/ar7/irq.c new file +10
-0+ irq_desc[i + base].depth =1 ; + irq_desc[i + base].chip = &ar7_irq_type; +/* Secondary IRQ's */ +if (i <32 ) { + irq_desc[i + base +40 ].status =IRQ_DISABLED ; + irq_desc[i + base +40 ].action =NULL ; + irq_desc[i + base +40 ].depth =1 ; + irq_desc[i + base +40 ].chip = &ar7_secondary_irq_type; + } + }
Use set_irq_chip() or its variants instead of touching irq_desc[] directly. It seems this platform can set GENERIC_HARDIRQS_NO__DO_IRQ in Kconfig, using handle_level_irq irq handler.
arch/mips/ar7/irq.c line 203
Quoted 10 lines
arch/mips/ar7/irq.c new file +10
-0+asmlinkage void plat_irq_dispatch(void) +{ +unsigned int pending =read_c0_status () &read_c0_cause (); +if (pending &STATUSF_IP7 )/* cpu timer */ +do_IRQ (7 ); +else if (pending &STATUSF_IP2 )/* int0 hardware line */ +do_IRQ (2 ); +else +spurious_interrupt (); +}
It would be safer to mask 'pending' with ST0_IM.
Quoted 3 lines
arch/mips/ar7/prom.c new file +0
-0
...
Quoted 11 lines
arch/mips/ar7/prom.c new file +11
-0+/* from adm5120/prom.c */ +void prom_printf (char *fmt, ...) +{ +va_list args; +int l; +char *p, *buf_end; +char buf[1024 ]; + +va_start (args, fmt); + l =vsprintf (buf, fmt, args);/* hopefully i < sizeof(buf) */ +va_end (args);
arch/mips/ar7/prom.c line 308
Quoted 10 lines
arch/mips/ar7/prom.c new file +10
-0+ + buf_end = buf + l; + +for (p = buf; p < buf_end; p++) { +/* Crude cr/nl handling is better than none */ +if (*p =='\n' ) +prom_putchar ('\r' ); +prom_putchar (*p); + } +}
prom_printf() is not used in recent linux-mips.
Quoted 5 lines
arch/mips/ar7/time.c new file +0
-0
...
Quoted 4 lines
arch/mips/ar7/time.c new file +4
-0+#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h>
arch/mips/ar7/time.c line 34
Quoted 10 lines
arch/mips/ar7/time.c new file +10
-0+#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/mc146818rtc.h> +#include <linux/ptrace.h> +#include <linux/hardirq.h> +#include <linux/irq.h> +#include <linux/cpu.h> +#include <asm/time.h>
You do not have to include so many headers.
Quoted 5 lines
arch/mips/ar7/vlynq.c new file +0
-0
...
Quoted 5 lines
arch/mips/ar7/vlynq.c new file +5
-0+struct vlynq_regs { +volatile u32 revision; +volatile u32 control; +volatile u32 status; +volatile u32 int_prio;
arch/mips/ar7/vlynq.c line 74
Quoted 10 lines
arch/mips/ar7/vlynq.c new file +10
-0+volatile u32 int_status; +volatile u32 int_pending; +volatile u32 int_ptr; +volatile u32 tx_offset; +volatile struct vlynq_mapping rx_mapping[4 ]; +volatile u32 chip; +volatile u32 autonego; +volatile u32 unused[6 ]; +volatile u32 int_device[8 ]; +} __attribute__ ((packed));
You can drop these volatile, using readl/writel for accessing these members.
arch/mips/ar7/vlynq.c line 117
Quoted 4 lines
arch/mips/ar7/vlynq.c new file +4
-0+static void vlynq_irq_unmask (unsigned int irq) +{ +volatile u32 val; +struct vlynq_device *dev = irq_desc[irq].chip_data;
This "volatile" should be removed.
Use get_irq_chip_data(irq) instead of using irq_desc[] directly.
arch/mips/ar7/vlynq.c line 129
Quoted 3 lines
arch/mips/ar7/vlynq.c new file +3
-0+static void vlynq_irq_mask (unsigned int irq) +{ +volatile u32 val;
This "volatile" should be removed.
arch/mips/ar7/vlynq.c line 142
Quoted 3 lines
arch/mips/ar7/vlynq.c new file +3
-0+static int vlynq_irq_type (unsigned int irq,unsigned int flow_type) +{ +volatile u32 val;
This "volatile" should be removed.
arch/mips/ar7/vlynq.c line 202
Quoted 2 lines
arch/mips/ar7/vlynq.c new file +2
-0+static struct irq_chip vlynq_irq_chip = { + .typename ="VLYNQ" ,
The typename is obsolete and not needed if you have name field.
arch/mips/ar7/vlynq.c line 241
Quoted 10 lines
arch/mips/ar7/vlynq.c new file +10
-0+for (i =0 ; i <PER_DEVICE_IRQS ; i++) { +if ((i == dev->local_irq) || (i == dev->remote_irq)) +continue ; + irq_desc[dev->irq_start + i].status =IRQ_DISABLED ; + irq_desc[dev->irq_start + i].action =0 ; + irq_desc[dev->irq_start + i].depth =1 ; + irq_desc[dev->irq_start + i].chip = &vlynq_irq_chip; + irq_desc[dev->irq_start + i].chip_data = dev; + dev->remote->int_device[i >>2 ] =0 ; + }
Use set_irq_chip() or its variants.
arch/mips/ar7/vlynq.c line 435
Quoted 7 lines
arch/mips/ar7/vlynq.c new file +7
-0+ dev =kmalloc (sizeof (struct vlynq_device ),GFP_KERNEL ); +if (!dev) { +printk (KERN_ERR "vlynq: failed to allocate device structure\n" ); +return -ENOMEM ; + } + +memset (dev,0 ,sizeof (struct vlynq_device ));
Use kzalloc().
Quoted 1 line
+int
__initvlynq_init(void)
This can be static.
Quoted 18 lines
arch/mips/kernel/traps.c +10
-0@@ -1075,9 +1075,23 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler;if (n ==0 && cpu_has_divec) { +#ifdef CONFIG_AR7 +/* lui k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x200 ) = +0x3c1a0000 | (handler >>16 ); +/* ori k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x204 ) = +0x375a0000 | (handler &0xffff ); +/* jr k0 */ + *(volatile u32 *)(CAC_BASE +0x208 ) =0x03400008 ; +/* nop */
arch/mips/kernel/traps.c void *set_except_vector(int n, void *addr) · line 1097
Quoted 10 lines
arch/mips/kernel/traps.c +4
-0+ *(volatile u32 *)(CAC_BASE +0x20C ) =0x00000000 ; +flush_icache_range (CAC_BASE +0x200 ,CAC_BASE +0x210 ); +#else *(volatile u32 *)(ebase +0x200 ) =0x08000000 | (0x03ffffff & (handler >>2 ));flush_icache_range (ebase +0x200 , ebase +0x204 ); +#endif }return (void *)old_handler; }
Runtime checking, something like this would be better than ifdef:
if ((handler ^ (ebase + 4)) & 0xfc000000)
/* use jr */
...
} else {
/* use j */
...
}---
Atsushi Nemoto
Re: [PATCH][MIPS][4/7] AR7: leds driver
In reply to Matteo CroceQuoted 5 lines · Matteo Croce
Support for the leds in front of the board usually used to show power status, network traffic, connected eth devices etc.
Signed-off-by Matteo Croce <[email protected]>Signed-off-by Nicolas Thill <[email protected]>
The usual approach to drivers like this is to add the device definition (ar7_leds_device) to the platform specific code which is probably in arch/mips/ somewhere? See arch/arm/mach-pxa/{corgi|poodle|spitz}.c for example.
Also, does MIPS have any kind of generic GPIO framework? A quick look at the code suggests you might be able to use drivers/leds/leds-gpio.c although you might need to add a definition of gpio_set_value_cansleep() since MIPS appears to lack it.
Regards,
Richard
(LED Maintainer)
Il Saturday 08 September 2007 19:40:20 Atsushi Nemoto ha scritto:
Quoted 31 lines
Quoted 18 lines
arch/mips/kernel/traps.c +10
-0@@ -1075,9 +1075,23 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler;if (n ==0 && cpu_has_divec) { +#ifdef CONFIG_AR7 +/* lui k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x200 ) = +0x3c1a0000 | (handler >>16 ); +/* ori k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x204 ) = +0x375a0000 | (handler &0xffff ); +/* jr k0 */ + *(volatile u32 *)(CAC_BASE +0x208 ) =0x03400008 ; +/* nop */ arch/mips/kernel/traps.c void *set_except_vector(int n, void *addr) · line 1097
Quoted 10 lines
arch/mips/kernel/traps.c +4
-0+ *(volatile u32 *)(CAC_BASE +0x20C ) =0x00000000 ; +flush_icache_range (CAC_BASE +0x200 ,CAC_BASE +0x210 ); +#else *(volatile u32 *)(ebase +0x200 ) =0x08000000 | (0x03ffffff & (handler >>2 ));flush_icache_range (ebase +0x200 , ebase +0x204 ); +#endif }return (void *)old_handler; }Runtime checking, something like this would be better than ifdef:
Quoted 7 lines
if ((handler ^ (ebase + 4)) & 0xfc000000)
/* use jr */
...
} else {
/* use j */
...
}This will not make the code bigger? What's wrong with #ifdef?
Quoted 9 lines · Matteo Croce
Quoted 9 lines
arch/mips/kernel/traps.c void *set_except_vector(int n, void *addr) · line 1080
Quoted 9 lines
arch/mips/kernel/traps.c +3
-0@@ -1075,9 +1075,23 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler;if (n ==0 && cpu_has_divec) { +#ifdef CONFIG_AR7 +/* lui k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE+0x200) =
s/CAC_BASE/ebase/
Quoted 9 lines
Quoted 9 lines
arch/mips/kernel/traps.c void *set_except_vector(int n, void *addr) · line 1089
Quoted 9 lines
arch/mips/kernel/traps.c +9
-0+0x3c1a0000 | (handler >>16 ); +/* ori k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x204 ) = +0x375a0000 | (handler &0xffff ); +/* jr k0 */ + *(volatile u32 *)(CAC_BASE +0x208 ) =0x03400008 ; +/* nop */ + *(volatile u32 *)(CAC_BASE +0x20C ) =0x00000000 ; +flush_icache_range (CAC_BASE +0x200 ,CAC_BASE +0x210 );
All these volatile keywords are unnecessary btw.
You may want to read Documentation/volatile-considered-harmful.txt on why volatile is almost always a bad idea.
Quoted 3 lines
Quoted 3 lines
arch/mips/kernel/traps.c void *set_except_vector(int n, void *addr) · line 1092
Quoted 3 lines
arch/mips/kernel/traps.c +1
-0+#else *(volatile u32 *)(ebase +0x200 ) =0x08000000 | (0x03ffffff & (handler >>2 ));
Just like this one, so I will remove it now.
Quoted 8 lines
Quoted 8 lines
arch/mips/kernel/traps.c void *set_except_vector(int n, void *addr) · line 1097
Quoted 5 lines
arch/mips/kernel/traps.c +1
-0flush_icache_range (ebase +0x200 , ebase +0x204 ); +#endif }return (void *)old_handler; }Runtime checking, something like this would be better than ifdef:
Quoted 8 lines
Quoted 7 lines
if ((handler ^ (ebase + 4)) & 0xfc000000) /* use jr */ ... } else { /* use j */ ... }This will not make the code bigger?
It will by a miniscule amount. Which hardly matters because the function is (whops, should be ...) __init code anyway.
Quoted 1 line
What's wrong with #ifdef?
#ifdef makes for harder to read code (To paraphrase Linus - the kernel is write once and read 10 million times) , is less flexible and has a tendence to hide bugs in the deactivated part. So generally avoid.
And actually in this specific case it also should be a runtime decission simply because in the not so distant future the will be hardware which will simply need that.
Ralf
Thomas Bogendoerfer
maintainerQuoted 32 lines · Matteo Croce
Il Saturday 08 September 2007 19:40:20 Atsushi Nemoto ha scritto:
Quoted 31 lines
Quoted 18 lines
arch/mips/kernel/traps.c +10
-0@@ -1075,9 +1075,23 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler;if (n ==0 && cpu_has_divec) { +#ifdef CONFIG_AR7 +/* lui k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x200 ) = +0x3c1a0000 | (handler >>16 ); +/* ori k0, 0x0000 */ + *(volatile u32 *)(CAC_BASE +0x204 ) = +0x375a0000 | (handler &0xffff ); +/* jr k0 */ + *(volatile u32 *)(CAC_BASE +0x208 ) =0x03400008 ; +/* nop */ arch/mips/kernel/traps.c void *set_except_vector(int n, void *addr) · line 1097
Quoted 10 lines
arch/mips/kernel/traps.c +4
-0+ *(volatile u32 *)(CAC_BASE +0x20C ) =0x00000000 ; +flush_icache_range (CAC_BASE +0x200 ,CAC_BASE +0x210 ); +#else *(volatile u32 *)(ebase +0x200 ) =0x08000000 | (0x03ffffff & (handler >>2 ));flush_icache_range (ebase +0x200 , ebase +0x204 ); +#endif }return (void *)old_handler; }Runtime checking, something like this would be better than ifdef:
Quoted 8 lines
Quoted 7 lines
if ((handler ^ (ebase + 4)) & 0xfc000000) /* use jr */ ... } else { /* use j */ ... }This will not make the code bigger? What's wrong with #ifdef?
probably nothing, but having a generic decision whether we need a version with j or jr will help other platforms as well. Why make AR7 a special case ?
Thomas.
Signature · 2 lines
Crap can work. Given enough thrust pigs will fly, but it's not necessary a good idea. [ RFC1925, 2.3 ]
Quoted 3 lines · Thomas Bogendoerfer
probably nothing, but having a generic decision whether we need a version with j or jr will help other platforms as well. Why make AR7 a special case ?
The destination is potencially outside the range of the j instruction. Which is something that reasonably be expected on other systems as well. One scenario for example is having a few k of RAM at phys 0 then the rest starting at 256MB phys.
It's somewhat easier with an ebase register of course but older cores don't have that.
Ralf
Re: [PATCH][MIPS][7/7] AR7: ethernet
In reply to Matteo CroceQuoted 13 lines · Matteo Croce
Driver for the cpmac 100M ethernet driver.
It works fine disabling napi support, enabling it gives a kernel panic when the first IPv6 packet has to be forwarded.
Other than that works fine.Signed-off-by Matteo Croce <[email protected]>Signed-off-by Eugene Konev <[email protected]>drivers/net/Kconfig +0
-0
drivers/net/Kconfig config SC92031 · line 1827
Quoted 6 lines
drivers/net/Kconfig +3
-0@@ -1822,6 +1822,15 @@ config SC92031 To compile this driver as a module, choose M here: the module will be called sc92031. This is recommended. +config CPMAC + tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" + depends on NET_ETHERNET && EXPERIMENTAL && AR7
The dependency on NET_ETHERNET is not needed because this config block is enclosed in a
if NET_ETHERNET
...
endif # NET_ETHERNET
block.
Quoted 98 lines
drivers/net/Kconfig +6
-0+ select PHYLIB + select FIXED_PHY + select FIXED_MII_100_FDX + help + TI AR7 CPMAC Ethernet support + config NET_POCKET bool "Pocket and portable adapters" depends on PARPORTdrivers/net/Makefile +1
-0@@ -156,6 +156,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_ZNET) += znet.o obj-$(CONFIG_LAN_SAA9730) += saa9730.o +obj-$(CONFIG_CPMAC) += cpmac.o obj-$(CONFIG_DEPCA) += depca.o obj-$(CONFIG_EWRK3) += ewrk3.o obj-$(CONFIG_ATP) += atp.odrivers/net/cpmac.c new file +71
-0@@ -0,0 +1,1194 @@ +/* +* Copyright (C) 2006, 2007 Eugene Konev +* +* 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 St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/moduleparam.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/version.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> +#include <linux/mii.h> +#include <linux/phy.h> +#include <linux/platform_device.h> +#include <asm/ar7/ar7.h> +#include <gpio.h> + +MODULE_AUTHOR ("Eugene Konev" ); +MODULE_DESCRIPTION ("TI AR7 ethernet driver (CPMAC)" ); +MODULE_LICENSE ("GPL" ); + +static int rx_ring_size =64 ; +static int disable_napi; +module_param (rx_ring_size, int,64 ); +module_param (disable_napi, int,0 ); +MODULE_PARM_DESC (rx_ring_size,"Size of rx ring (in skbs)" ); +MODULE_PARM_DESC (disable_napi,"Disable NAPI polling" ); + +/* Register definitions */ +struct cpmac_control_regs { +u32 revision; +u32 control; +u32 teardown; +u32 unused; +} __attribute__ ((packed)); + +struct cpmac_int_regs { +u32 stat_raw; +u32 stat_masked; +u32 enable; +u32 clear; +} __attribute__ ((packed)); + +struct cpmac_stats { +u32 good; +u32 bcast; +u32 mcast; +u32 pause;
drivers/net/cpmac.c line 81
Quoted 10 lines
drivers/net/cpmac.c new file +10
-0+u32 crc_error; +u32 align_error; +u32 oversized; +u32 jabber; +u32 undersized; +u32 fragment; +u32 filtered; +u32 qos_filtered; +u32 octets; +} __attribute__ ((packed));
All struct members here are sized such that there is no padding needed, so the packed attribute doesn't buy you anything - unless of course the entire structure is missaligned but I don't see how that would be possible in this driver so the __attribute__ ((packed)) should go - it result in somwhat larger and slower code.
In any case, the __packed attribute is prefered over __attribute__ ((packed)) for readability sake.
Quoted 818 lines
drivers/net/cpmac.c new file +818
-0+ +struct cpmac_regs { +struct cpmac_control_regs tx_ctrl; +struct cpmac_control_regs rx_ctrl; +u32 unused1[56 ]; +u32 mbp; +/* MBP bits */ +#define MBP_RXPASSCRC 0x40000000 +#define MBP_RXQOS 0x20000000 +#define MBP_RXNOCHAIN 0x10000000 +#define MBP_RXCMF 0x01000000 +#define MBP_RXSHORT 0x00800000 +#define MBP_RXCEF 0x00400000 +#define MBP_RXPROMISC 0x00200000 +#define MBP_PROMISCCHAN (chan) (((chan) & 0x7) << 16) +#define MBP_RXBCAST 0x00002000 +#define MBP_BCASTCHAN (chan) (((chan) & 0x7) << 8) +#define MBP_RXMCAST 0x00000020 +#define MBP_MCASTCHAN (chan) ((chan) & 0x7) +u32 unicast_enable; +u32 unicast_clear; +u32 max_len; +u32 buffer_offset; +u32 filter_flow_threshold; +u32 unused2[2 ]; +u32 flow_thre[8 ]; +u32 free_buffer[8 ]; +u32 mac_control; +#define MAC_TXPTYPE 0x00000200 +#define MAC_TXPACE 0x00000040 +#define MAC_MII 0x00000020 +#define MAC_TXFLOW 0x00000010 +#define MAC_RXFLOW 0x00000008 +#define MAC_MTEST 0x00000004 +#define MAC_LOOPBACK 0x00000002 +#define MAC_FDX 0x00000001 +u32 mac_status; +#define MACST_QOS 0x4 +#define MACST_RXFLOW 0x2 +#define MACST_TXFLOW 0x1 +u32 emc_control; +u32 unused3; +struct cpmac_int_regs tx_int; +u32 mac_int_vector; +/* Int Status bits */ +#define INTST_STATUS 0x80000 +#define INTST_HOST 0x40000 +#define INTST_RX 0x20000 +#define INTST_TX 0x10000 +u32 mac_eoi_vector; +u32 unused4[2 ]; +struct cpmac_int_regs rx_int; +u32 mac_int_stat_raw; +u32 mac_int_stat_masked; +u32 mac_int_enable; +u32 mac_int_clear; +u32 mac_addr_low[8 ]; +u32 mac_addr_mid; +u32 mac_addr_high; +u32 mac_hash_low; +u32 mac_hash_high; +u32 boff_test; +u32 pac_test; +u32 rx_pause; +u32 tx_pause; +u32 unused5[2 ]; +struct cpmac_stats rx_stats; +struct cpmac_stats tx_stats; +u32 unused6[232 ]; +u32 tx_ptr[8 ]; +u32 rx_ptr[8 ]; +u32 tx_ack[8 ]; +u32 rx_ack[8 ]; + +} __attribute__ ((packed)); + +struct cpmac_mdio_regs { +u32 version; +u32 control; +#define MDIOC_IDLE 0x80000000 +#define MDIOC_ENABLE 0x40000000 +#define MDIOC_PREAMBLE 0x00100000 +#define MDIOC_FAULT 0x00080000 +#define MDIOC_FAULTDETECT 0x00040000 +#define MDIOC_INTTEST 0x00020000 +#define MDIOC_CLKDIV (div) ((div) & 0xff) +u32 alive; +u32 link; +struct cpmac_int_regs link_int; +struct cpmac_int_regs user_int; +u32 unused[20 ]; +volatile u32 access; +#define MDIO_BUSY 0x80000000 +#define MDIO_WRITE 0x40000000 +#define MDIO_REG (reg) (((reg) & 0x1f) << 21) +#define MDIO_PHY (phy) (((phy) & 0x1f) << 16) +#define MDIO_DATA (data) ((data) & 0xffff) +u32 physel; +} __attribute__ ((packed)); + +/* Descriptor */ +struct cpmac_desc { +u32 hw_next; +u32 hw_data; +u16 buflen; +u16 bufflags; +u16 datalen; +u16 dataflags; +/* Flags bits */ +#define CPMAC_SOP 0x8000 +#define CPMAC_EOP 0x4000 +#define CPMAC_OWN 0x2000 +#define CPMAC_EOQ 0x1000 +struct sk_buff *skb; +struct cpmac_desc *next; +} __attribute__ ((packed)); + +struct cpmac_priv { +struct net_device_stats stats; +spinlock_t lock;/* irq{save,restore} */ +struct sk_buff *skb_pool; +int free_skbs; +struct cpmac_desc *rx_head; +int tx_head, tx_tail; +struct cpmac_desc *desc_ring; +struct cpmac_regs *regs; +struct mii_bus *mii_bus; +struct phy_device *phy; +char phy_name[BUS_ID_SIZE ]; +struct plat_cpmac_data *config; +int oldlink, oldspeed, oldduplex; +u32 msg_enable; +struct net_device *dev; +struct work_struct alloc_work; +}; + +static irqreturn_t cpmac_irq (int ,void *); +static void cpmac_reset (struct net_device *dev); +static void cpmac_hw_init (struct net_device *dev); +static int cpmac_stop (struct net_device *dev); +static int cpmac_open (struct net_device *dev); + +#undef CPMAC_DEBUG +#define CPMAC_LOW_THRESH 32 +#define CPMAC_ALLOC_SIZE 64 +#define CPMAC_SKB_SIZE 1518 +#define CPMAC_TX_RING_SIZE 8 + +#ifdef CPMAC_DEBUG +static void cpmac_dump_regs (u32 *base,int count) +{ +int i; +for (i =0 ; i < (count +3 ) /4 ; i++) { +if (i %4 ==0 )printk (KERN_DEBUG "\nCPMAC[0x%04x]:" , i *4 ); +printk (KERN_DEBUG " 0x%08x" , *(base + i)); + } +printk (KERN_DEBUG "\n" ); +} + +static const char *cpmac_dump_buf (const uint8_t *buf,unsigned size) +{ +static char buffer[3 *25 +1 ]; +char *p = &buffer[0 ]; +if (size >20 ) + size =20 ; +while (size-- >0 ) + p +=sprintf (p," %02x" , *buf++); +return buffer; +} +#endif + +static int cpmac_mdio_read (struct mii_bus *bus,int phy_id,int regnum) +{ +struct cpmac_mdio_regs *regs = bus->priv; +u32 val; + +while ((val = regs->access) &MDIO_BUSY ); + regs->access =MDIO_BUSY |MDIO_REG (regnum &0x1f ) | +MDIO_PHY (phy_id &0x1f ); +while ((val = regs->access) &MDIO_BUSY ); + +return val &0xffff ; +} + +static int cpmac_mdio_write (struct mii_bus *bus,int phy_id, +int regnum,u16 val) +{ +struct cpmac_mdio_regs *regs = bus->priv; + +while (regs->access &MDIO_BUSY ); + regs->access =MDIO_BUSY |MDIO_WRITE | +MDIO_REG (regnum &0x1f ) |MDIO_PHY (phy_id &0x1f ) | val; + +return 0 ; +} + +static int cpmac_mdio_reset (struct mii_bus *bus) +{ +ar7_device_reset (AR7_RESET_BIT_MDIO ); + ((struct cpmac_mdio_regs *)bus->priv)->control =MDIOC_ENABLE | +MDIOC_CLKDIV (ar7_cpmac_freq () /2200000 -1 ); + +return 0 ; +} + +static int mii_irqs[PHY_MAX_ADDR ] = {PHY_POLL , }; + +static struct mii_bus cpmac_mii = { + .name ="cpmac-mii" , + .read = cpmac_mdio_read, + .write = cpmac_mdio_write, + .reset = cpmac_mdio_reset, + .irq = mii_irqs, +}; + +static int cpmac_config (struct net_device *dev,struct ifmap *map) +{ +if (dev->flags &IFF_UP ) +return -EBUSY ; + +/* Don't allow changing the I/O address */ +if (map->base_addr != dev->base_addr) +return -EOPNOTSUPP ; + +/* ignore other fields */ +return 0 ; +} + +static int cpmac_set_mac_address (struct net_device *dev,void *addr) +{ +struct sockaddr *sa = addr; + +if (dev->flags &IFF_UP ) +return -EBUSY ; + +memcpy (dev->dev_addr, sa->sa_data, dev->addr_len); + +return 0 ; +} + +static void cpmac_set_multicast_list (struct net_device *dev) +{ +struct dev_mc_list *iter; +int i; +int hash, tmp; +int hashlo =0 , hashhi =0 ; +struct cpmac_priv *priv =netdev_priv (dev); + +if (dev->flags &IFF_PROMISC ) { + priv->regs->mbp &= ~MBP_PROMISCCHAN (0 );/* promisc channel 0 */ + priv->regs->mbp |=MBP_RXPROMISC ; + }else { + priv->regs->mbp &= ~MBP_RXPROMISC ; +if (dev->flags &IFF_ALLMULTI ) { +/* enable all multicast mode */ + priv->regs->mac_hash_low =0xffffffff ; + priv->regs->mac_hash_high =0xffffffff ; + }else { +for (i =0 , iter = dev->mc_list; i < dev->mc_count; + i++, iter = iter->next) { + hash =0 ; + tmp = iter->dmi_addr[0 ]; + hash ^= (tmp >>2 ) ^ (tmp <<4 ); + tmp = iter->dmi_addr[1 ]; + hash ^= (tmp >>4 ) ^ (tmp <<2 ); + tmp = iter->dmi_addr[2 ]; + hash ^= (tmp >>6 ) ^ tmp; + tmp = iter->dmi_addr[4 ]; + hash ^= (tmp >>2 ) ^ (tmp <<4 ); + tmp = iter->dmi_addr[5 ]; + hash ^= (tmp >>4 ) ^ (tmp <<2 ); + tmp = iter->dmi_addr[6 ]; + hash ^= (tmp >>6 ) ^ tmp; + hash &=0x3f ; +if (hash <32 ) { + hashlo |=1 <<hash; + }else { + hashhi |=1 <<(hash -32 ); + } + } + + priv->regs->mac_hash_low = hashlo; + priv->regs->mac_hash_high = hashhi; + } + } +} + +static struct sk_buff *cpmac_get_skb (struct net_device *dev) +{ +struct sk_buff *skb; +struct cpmac_priv *priv =netdev_priv (dev); + + skb = priv->skb_pool; +if (likely (skb)) + priv->skb_pool = skb->next; +else { + skb =dev_alloc_skb (CPMAC_SKB_SIZE +2 ); +if (skb) { + skb->next =NULL ; +skb_reserve (skb,2 ); + skb->dev = priv->dev; + } + } + +if (likely (priv->free_skbs)) + priv->free_skbs--; + +if (priv->free_skbs <CPMAC_LOW_THRESH ) +schedule_work (&priv->alloc_work); + +return skb; +} + +static struct sk_buff *cpmac_rx_one (struct net_device *dev, +struct cpmac_priv *priv, +struct cpmac_desc *desc) +{ +unsigned long flags; +char *data; +struct sk_buff *skb, *result =NULL ; + + priv->regs->rx_ack[0 ] =virt_to_phys (desc); +if (unlikely (!desc->datalen)) { +if (printk_ratelimit ()) +printk (KERN_WARNING "%s: rx: spurious interrupt\n" , + dev->name); + priv->stats.rx_errors++; +return NULL ; + } + +spin_lock_irqsave (&priv->lock, flags); + skb =cpmac_get_skb (dev); +if (likely (skb)) { + data = (char *)phys_to_virt (desc->hw_data); +dma_cache_inv ((u32 )data, desc->datalen); +skb_put (desc->skb, desc->datalen); + desc->skb->protocol =eth_type_trans (desc->skb, dev); + desc->skb->ip_summed =CHECKSUM_NONE ; + priv->stats.rx_packets++; + priv->stats.rx_bytes += desc->datalen; + result = desc->skb; + desc->skb = skb; + }else { +#ifdef CPMAC_DEBUG +if (printk_ratelimit ()) +printk (KERN_NOTICE "%s: low on skbs, dropping packet\n" , + dev->name); +#endif + priv->stats.rx_dropped++; + } +spin_unlock_irqrestore (&priv->lock, flags); + + desc->hw_data =virt_to_phys (desc->skb->data); + desc->buflen =CPMAC_SKB_SIZE ; + desc->dataflags =CPMAC_OWN ; +dma_cache_wback ((u32 )desc,16 ); + +return result; +} + +static void cpmac_rx (struct net_device *dev) +{ +struct sk_buff *skb; +struct cpmac_desc *desc; +struct cpmac_priv *priv =netdev_priv (dev); + +spin_lock (&priv->lock); +if (unlikely (!priv->rx_head)) { +spin_unlock (&priv->lock); +return ; + } + + desc = priv->rx_head; +dma_cache_inv ((u32 )desc,16 ); +#ifdef CPMAC_DEBUG +printk (KERN_DEBUG "%s: len=%d, %s\n" , __func__, pkt->datalen, +cpmac_dump_buf (data, pkt->datalen)); +#endif + +while ((desc->dataflags &CPMAC_OWN ) ==0 ) { + skb =cpmac_rx_one (dev, priv, desc); +if (likely (skb)) +netif_rx (skb); + desc = desc->next; +dma_cache_inv ((u32 )desc,16 ); + } + + priv->rx_head = desc; + priv->regs->rx_ptr[0 ] =virt_to_phys (desc); +spin_unlock (&priv->lock); +} + +static int cpmac_poll (struct net_device *dev,int *budget) +{ +struct sk_buff *skb; +struct cpmac_desc *desc; +int received =0 , quota =min (dev->quota, *budget); +struct cpmac_priv *priv =netdev_priv (dev); + +if (unlikely (!priv->rx_head)) { +if (printk_ratelimit ()) +printk (KERN_NOTICE "%s: rx: polling, but no queue\n" , + dev->name); +netif_rx_complete (dev); +return 0 ; + } + + desc = priv->rx_head; +dma_cache_inv ((u32 )desc,16 ); + +while ((received < quota) && ((desc->dataflags &CPMAC_OWN ) ==0 )) { + skb =cpmac_rx_one (dev, priv, desc); +if (likely (skb)) { +netif_receive_skb (skb); + received++; + } + desc = desc->next; + priv->rx_head = desc; +dma_cache_inv ((u32 )desc,16 ); + } + + *budget -= received; + dev->quota -= received; +#ifdef CPMAC_DEBUG +printk (KERN_DEBUG "%s: processed %d packets\n" , dev->name, received); +#endif +if (desc->dataflags &CPMAC_OWN ) { + priv->regs->rx_ptr[0 ] =virt_to_phys (desc); +netif_rx_complete (dev); + priv->regs->rx_int.enable =0x1 ; + priv->regs->rx_int.clear =0xfe ; +return 0 ; + } + +return 1 ; +} + +static void +cpmac_alloc_skbs (struct work_struct *work) +{ + struct cpmac_priv *priv = container_of(work, struct cpmac_priv, + alloc_work); +unsigned long flags; +int i, num_skbs =0 ; +struct sk_buff *skb, *skbs =NULL ; + +for (i =0 ; i <CPMAC_ALLOC_SIZE ; i++) { + skb =alloc_skb (CPMAC_SKB_SIZE +2 ,GFP_KERNEL ); +if (!skb) +break ; + skb->next = skbs; +skb_reserve (skb,2 ); + skb->dev = priv->dev; + num_skbs++; + skbs = skb; + } + +if (skbs) { +spin_lock_irqsave (&priv->lock, flags); +for (skb = priv->skb_pool; skb && skb->next; skb = skb->next); +if (!skb) + priv->skb_pool = skbs; +else + skb->next = skbs; + priv->free_skbs += num_skbs; +spin_unlock_irqrestore (&priv->lock, flags); +#ifdef CPMAC_DEBUG +printk (KERN_DEBUG "%s: allocated %d skbs\n" , + priv->dev->name, num_skbs); +#endif + } +} + +static int cpmac_start_xmit (struct sk_buff *skb,struct net_device *dev) +{ +unsigned long flags; +int len, chan; +struct cpmac_desc *desc; +struct cpmac_priv *priv =netdev_priv (dev); + + len = skb->len; +#ifdef CPMAC_DEBUG +printk (KERN_DEBUG "%s: len=%d\n" , __func__, len); +/* cpmac_dump_buf(const uint8_t * buf, unsigned size) */ +#endif +if (unlikely (len <ETH_ZLEN )) { +if (unlikely (skb_padto (skb,ETH_ZLEN ))) { +if (printk_ratelimit ()) +printk (KERN_NOTICE +"%s: padding failed, dropping\n" , + dev->name); +spin_lock_irqsave (&priv->lock, flags); + priv->stats.tx_dropped++; +spin_unlock_irqrestore (&priv->lock, flags); +return -ENOMEM ; + } + len =ETH_ZLEN ; + } +spin_lock_irqsave (&priv->lock, flags); + chan = priv->tx_tail++; + priv->tx_tail %=8 ; +if (priv->tx_tail == priv->tx_head) +netif_stop_queue (dev); + + desc = &priv->desc_ring[chan]; +dma_cache_inv ((u32 )desc,16 ); +if (desc->dataflags &CPMAC_OWN ) { +printk (KERN_NOTICE "%s: tx dma ring full, dropping\n" , + dev->name); + priv->stats.tx_dropped++; +spin_unlock_irqrestore (&priv->lock, flags); +return -ENOMEM ; + } + + dev->trans_start = jiffies; + desc->dataflags =CPMAC_SOP |CPMAC_EOP |CPMAC_OWN ; + desc->skb = skb; + desc->hw_data =virt_to_phys (skb->data); +dma_cache_wback ((u32 )skb->data, len); + desc->buflen = len; + desc->datalen = len; + desc->hw_next =0 ; +dma_cache_wback ((u32 )desc,16 ); + priv->regs->tx_ptr[chan] =virt_to_phys (desc); +spin_unlock_irqrestore (&priv->lock, flags); + +return 0 ; +} + +static void cpmac_end_xmit (struct net_device *dev,int channel) +{ +struct cpmac_desc *desc; +struct cpmac_priv *priv =netdev_priv (dev); + +spin_lock (&priv->lock); + desc = &priv->desc_ring[channel]; + priv->regs->tx_ack[channel] =virt_to_phys (desc); +if (likely (desc->skb)) { + priv->stats.tx_packets++; + priv->stats.tx_bytes += desc->skb->len; +dev_kfree_skb_irq (desc->skb); +if (netif_queue_stopped (dev)) +netif_wake_queue (dev); + }else +if (printk_ratelimit ()) +printk (KERN_NOTICE "%s: end_xmit: spurious interrupt\n" , + dev->name); +spin_unlock (&priv->lock); +} + +static void cpmac_reset (struct net_device *dev) +{ +int i; +struct cpmac_priv *priv =netdev_priv (dev); + +ar7_device_reset (priv->config->reset_bit); + priv->regs->rx_ctrl.control &= ~1 ; + priv->regs->tx_ctrl.control &= ~1 ; +for (i =0 ; i <8 ; i++) { + priv->regs->tx_ptr[i] =0 ; + priv->regs->rx_ptr[i] =0 ; + } + priv->regs->mac_control &= ~MAC_MII ;/* disable mii */ +} + +static inline void cpmac_free_rx_ring (struct net_device *dev) +{ +struct cpmac_desc *desc; +int i; +struct cpmac_priv *priv =netdev_priv (dev); + +if (unlikely (!priv->rx_head)) +return ; + + desc = priv->rx_head; +dma_cache_inv ((u32 )desc,16 ); + +for (i =0 ; i < rx_ring_size; i++) { + desc->buflen =CPMAC_SKB_SIZE ; +if ((desc->dataflags &CPMAC_OWN ) ==0 ) { + desc->dataflags =CPMAC_OWN ; + priv->stats.rx_dropped++; + } +dma_cache_wback ((u32 )desc,16 ); + desc = desc->next; +dma_cache_inv ((u32 )desc,16 ); + } +} + +static irqreturn_t cpmac_irq (int irq,void *dev_id) +{ +struct net_device *dev = dev_id; +struct cpmac_priv *priv =netdev_priv (dev); +u32 status; + +if (!dev) +return IRQ_NONE ; + + status = priv->regs->mac_int_vector; + +if (status &INTST_TX ) +cpmac_end_xmit (dev, (status &7 )); + +if (status &INTST_RX ) { +if (disable_napi) +cpmac_rx (dev); +else { + priv->regs->rx_int.enable =0 ; + priv->regs->rx_int.clear =0xff ; +netif_rx_schedule (dev); + } + } + + priv->regs->mac_eoi_vector =0 ; + +if (unlikely (status & (INTST_HOST |INTST_STATUS ))) { +if (printk_ratelimit ()) +printk (KERN_ERR "%s: hw error, resetting...\n" , + dev->name); +spin_lock (&priv->lock); +phy_stop (priv->phy); +cpmac_reset (dev); +cpmac_free_rx_ring (dev); +cpmac_hw_init (dev); +spin_unlock (&priv->lock); + } + +return IRQ_HANDLED ; +} + +static void cpmac_tx_timeout (struct net_device *dev) +{ +struct cpmac_priv *priv =netdev_priv (dev); +struct cpmac_desc *desc; + + priv->stats.tx_errors++; + desc = &priv->desc_ring[priv->tx_head++]; + priv->tx_head %=8 ; +printk (KERN_NOTICE "%s: transmit timeout\n" , dev->name); +if (desc->skb) +dev_kfree_skb (desc->skb); +netif_wake_queue (dev); +} + +static int cpmac_ioctl (struct net_device *dev,struct ifreq *ifr,int cmd) +{ +struct cpmac_priv *priv =netdev_priv (dev); +if (!(netif_running (dev))) +return -EINVAL ; +if (!priv->phy) +return -EINVAL ; +if ((cmd ==SIOCGMIIPHY ) || (cmd ==SIOCGMIIREG ) || + (cmd ==SIOCSMIIREG )) +return phy_mii_ioctl (priv->phy,if_mii (ifr), cmd); + +return -EINVAL ; +} + +static int cpmac_get_settings (struct net_device *dev,struct ethtool_cmd *cmd) +{ +struct cpmac_priv *priv =netdev_priv (dev); + +if (priv->phy) +return phy_ethtool_gset (priv->phy, cmd); + +return -EINVAL ; +} + +static int cpmac_set_settings (struct net_device *dev,struct ethtool_cmd *cmd) +{ +struct cpmac_priv *priv =netdev_priv (dev); + +if (!capable (CAP_NET_ADMIN )) +return -EPERM ; + +if (priv->phy) +return phy_ethtool_sset (priv->phy, cmd); + +return -EINVAL ; +} + +static void cpmac_get_drvinfo (struct net_device *dev, +struct ethtool_drvinfo *info) +{ +strcpy (info->driver,"cpmac" ); +strcpy (info->version,"0.0.3" ); + info->fw_version[0 ] ='\0' ; +sprintf (info->bus_info,"%s" ,"cpmac" ); + info->regdump_len =0 ; +} + +static const struct ethtool_ops cpmac_ethtool_ops = { + .get_settings = cpmac_get_settings, + .set_settings = cpmac_set_settings, + .get_drvinfo = cpmac_get_drvinfo, + .get_link = ethtool_op_get_link, +}; + +static struct net_device_stats *cpmac_stats (struct net_device *dev) +{ +struct cpmac_priv *priv =netdev_priv (dev); + +if (netif_device_present (dev)) +return &priv->stats; + +return NULL ; +} + +static int cpmac_change_mtu (struct net_device *dev,int mtu) +{ +unsigned long flags; +struct cpmac_priv *priv =netdev_priv (dev); +spinlock_t *lock = &priv->lock; + +if ((mtu <68 ) || (mtu >1500 )) +return -EINVAL ; + +spin_lock_irqsave (lock, flags); + dev->mtu = mtu; +spin_unlock_irqrestore (lock, flags); + +return 0 ; +} + +static void cpmac_adjust_link (struct net_device *dev) +{ +struct cpmac_priv *priv =netdev_priv (dev); +unsigned long flags; +int new_state =0 ; + +spin_lock_irqsave (&priv->lock, flags); +if (priv->phy->link) { +if (priv->phy->duplex != priv->oldduplex) { + new_state =1 ; + priv->oldduplex = priv->phy->duplex; + } + +if (priv->phy->speed != priv->oldspeed) { + new_state =1 ; + priv->oldspeed = priv->phy->speed; + } + +if (!priv->oldlink) { + new_state =1 ; + priv->oldlink =1 ; +netif_schedule (dev); + } + }else if (priv->oldlink) { + new_state =1 ; + priv->oldlink =0 ; + priv->oldspeed =0 ; + priv->oldduplex =-1 ; + } + +if (new_state) +phy_print_status (priv->phy); + +spin_unlock_irqrestore (&priv->lock, flags); +} + +static void cpmac_hw_init (struct net_device *dev) +{ +int i; +struct cpmac_priv *priv =netdev_priv (dev); + +for (i =0 ; i <8 ; i++) + priv->regs->tx_ptr[i] =0 ; + priv->regs->rx_ptr[0 ] =virt_to_phys (priv->rx_head); + + priv->regs->mbp =MBP_RXSHORT |MBP_RXBCAST |MBP_RXMCAST ; + priv->regs->unicast_enable =0x1 ; + priv->regs->unicast_clear =0xfe ; + priv->regs->buffer_offset =0 ; +for (i =0 ; i <8 ; i++) + priv->regs->mac_addr_low[i] = dev->dev_addr[5 ]; + priv->regs->mac_addr_mid = dev->dev_addr[4 ]; + priv->regs->mac_addr_high = dev->dev_addr[0 ] | (dev->dev_addr[1 ] <<8 ) + | (dev->dev_addr[2 ] <<16 ) | (dev->dev_addr[3 ] <<24 ); + priv->regs->max_len =CPMAC_SKB_SIZE ; + priv->regs->rx_int.enable =0x1 ; + priv->regs->rx_int.clear =0xfe ; + priv->regs->tx_int.enable =0xff ; + priv->regs->tx_int.clear =0 ; + priv->regs->mac_int_enable =3 ; + priv->regs->mac_int_clear =0xfc ; + + priv->regs->rx_ctrl.control |=1 ; + priv->regs->tx_ctrl.control |=1 ; + priv->regs->mac_control |=MAC_MII |MAC_FDX ; + + priv->phy->state =PHY_CHANGELINK ; +phy_start (priv->phy); +} + +static int cpmac_open (struct net_device *dev) +{ +int i, size, res; +struct cpmac_priv *priv =netdev_priv (dev); +struct cpmac_desc *desc; +struct sk_buff *skb; + + priv->phy =phy_connect (dev, priv->phy_name, &cpmac_adjust_link, +0 ,PHY_INTERFACE_MODE_MII ); +if (IS_ERR (priv->phy)) { +printk (KERN_ERR "%s: Could not attach to PHY\n" , dev->name); +return PTR_ERR (priv->phy); + } + +if (!request_mem_region (dev->mem_start, dev->mem_end - + dev->mem_start, dev->name)) { +printk (KERN_ERR "%s: failed to request registers\n" , + dev->name); + res = -ENXIO ; + goto fail_reserve; + } + + priv->regs =ioremap_nocache (dev->mem_start, dev->mem_end - + dev->mem_start);
drivers/net/cpmac.c line 909
Quoted 10 lines
drivers/net/cpmac.c new file +10
-0+if (!priv->regs) { +printk (KERN_ERR "%s: failed to remap registers\n" , dev->name); + res = -ENXIO ; + goto fail_remap; + } + + priv->rx_head =NULL ; + size =sizeof (struct cpmac_desc ) * (rx_ring_size + +CPMAC_TX_RING_SIZE ); + priv->desc_ring = (struct cpmac_desc *)kmalloc (size,GFP_KERNEL );
kmalloc returns void * so no cast to another pointer type necessary.
drivers/net/cpmac.c line 915
Quoted 6 lines
drivers/net/cpmac.c new file +6
-0+if (!priv->desc_ring) { + res = -ENOMEM ; + goto fail_alloc; + } + +memset ((char *)priv->desc_ring,0 , size);
Use kzalloc instead of kmalloc. kzalloc is like kmalloc but returns zero'd memory.
Quoted 131 lines
drivers/net/cpmac.c new file +131
-0+ priv->skb_pool =NULL ; + priv->free_skbs =0 ; + priv->rx_head = &priv->desc_ring[CPMAC_TX_RING_SIZE ]; + +INIT_WORK (&priv->alloc_work, cpmac_alloc_skbs); +schedule_work (&priv->alloc_work); +flush_scheduled_work (); + +for (i =0 ; i < rx_ring_size; i++) { + desc = &priv->rx_head[i]; + skb =cpmac_get_skb (dev); +if (!skb) { + res = -ENOMEM ; + goto fail_desc; + } + desc->skb = skb; + desc->hw_data =virt_to_phys (skb->data); + desc->buflen =CPMAC_SKB_SIZE ; + desc->dataflags =CPMAC_OWN ; + desc->next = &priv->rx_head[(i +1 ) % rx_ring_size]; + desc->hw_next =virt_to_phys (desc->next); +dma_cache_wback ((u32 )desc,16 ); + } + +if ((res =request_irq (dev->irq, cpmac_irq,SA_INTERRUPT , + dev->name, dev))) { +printk (KERN_ERR "%s: failed to obtain irq\n" , dev->name); + goto fail_irq; + } + +cpmac_reset (dev); +cpmac_hw_init (dev); + +netif_start_queue (dev); +return 0 ; + +fail_irq: +fail_desc: +for (i =0 ; i < rx_ring_size; i++) +if (priv->rx_head[i].skb) +kfree_skb (priv->rx_head[i].skb); +fail_alloc: +kfree (priv->desc_ring); + +for (skb = priv->skb_pool; skb; skb = priv->skb_pool) { + priv->skb_pool = skb->next; +kfree_skb (skb); + } + +iounmap (priv->regs); + +fail_remap: +release_mem_region (dev->mem_start, dev->mem_end - + dev->mem_start); + +fail_reserve: +phy_disconnect (priv->phy); + +return res; +} + +static int cpmac_stop (struct net_device *dev) +{ +int i; +struct sk_buff *skb; +struct cpmac_priv *priv =netdev_priv (dev); + +netif_stop_queue (dev); + +phy_stop (priv->phy); +phy_disconnect (priv->phy); + priv->phy =NULL ; + +cpmac_reset (dev); + +for (i =0 ; i <8 ; i++) { + priv->regs->rx_ptr[i] =0 ; + priv->regs->tx_ptr[i] =0 ; + priv->regs->mbp =0 ; + } + +free_irq (dev->irq, dev); +release_mem_region (dev->mem_start, dev->mem_end - + dev->mem_start); + +cancel_delayed_work (&priv->alloc_work); +flush_scheduled_work (); + + priv->rx_head = &priv->desc_ring[CPMAC_TX_RING_SIZE ]; +for (i =0 ; i < rx_ring_size; i++) +if (priv->rx_head[i].skb) +kfree_skb (priv->rx_head[i].skb); + +kfree (priv->desc_ring); + +for (skb = priv->skb_pool; skb; skb = priv->skb_pool) { + priv->skb_pool = skb->next; +kfree_skb (skb); + } + +return 0 ; +} + +static int external_switch; + +static int __devinit cpmac_probe (struct platform_device *pdev) +{ +int i, rc, phy_id; +struct resource *res; +struct cpmac_priv *priv; +struct net_device *dev; +struct plat_cpmac_data *pdata; + + pdata = pdev->dev.platform_data; + +for (phy_id =0 ; phy_id <PHY_MAX_ADDR ; phy_id++) { +if (!(pdata->phy_mask & (1 << phy_id))) +continue ; +if (!cpmac_mii.phy_map[phy_id]) +continue ; +break ; + } + +if (phy_id ==PHY_MAX_ADDR ) { +if (external_switch) + phy_id =0 ; +else { +printk (KERN_ERR "cpmac: no PHY present\n" ); +return -ENODEV ; + } + }
drivers/net/cpmac.c line 1057
Quoted 10 lines
drivers/net/cpmac.c new file +10
-0+ + dev =alloc_etherdev (sizeof (struct cpmac_priv )); + +if (!dev) { +printk (KERN_ERR +"cpmac: Unable to allocate net_device structure!\n" ); +return -ENOMEM ; + } + +SET_MODULE_OWNER (dev);
Set SET_MODULE_OWNER is a useless nop which only exists in 2.6 for driver source compatibility with 2.4. So you can remove this call.
I used the opportunity to send out a patch to remove SET_MODULE_OWNER from the kernel entirely.
Quoted 4 lines
drivers/net/cpmac.c new file +4
-0+platform_set_drvdata (pdev, dev); + priv =netdev_priv (dev); + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"regs" );
drivers/net/cpmac.c line 1071
Quoted 10 lines
drivers/net/cpmac.c new file +10
-0+if (!res) { + rc = -ENODEV ; + goto fail; + } + + dev->mem_start = res->start; + dev->mem_end = res->end; + dev->irq =platform_get_irq_byname (pdev,"irq" ); + + dev->mtu =1500 ;
Initializing this field is redundant; alloc_etherdev has already done it, so remove this line.
Quoted 7 lines
drivers/net/cpmac.c new file +7
-0+ dev->open = cpmac_open; + dev->stop = cpmac_stop; + dev->set_config = cpmac_config; + dev->hard_start_xmit = cpmac_start_xmit; + dev->do_ioctl = cpmac_ioctl; + dev->get_stats = cpmac_stats; + dev->change_mtu = cpmac_change_mtu;
drivers/net/cpmac.c line 1088
Quoted 10 lines
drivers/net/cpmac.c new file +10
-0+ dev->set_mac_address = cpmac_set_mac_address; + dev->set_multicast_list = cpmac_set_multicast_list; + dev->tx_timeout = cpmac_tx_timeout; + dev->ethtool_ops = &cpmac_ethtool_ops; +if (!disable_napi) { + dev->poll = cpmac_poll; + dev->weight =min (rx_ring_size,64 ); + } + +memset (priv,0 ,sizeof (struct cpmac_priv ));
Useless, alloc_etherdev does that already.
Quoted 32 lines
drivers/net/cpmac.c new file +32
-0+spin_lock_init (&priv->lock); + priv->msg_enable =netif_msg_init (NETIF_MSG_WOL ,0x3fff ); + priv->config = pdata; + priv->dev = dev; +memcpy (dev->dev_addr, priv->config->dev_addr,sizeof (dev->dev_addr)); +if (phy_id ==31 ) +snprintf (priv->phy_name,BUS_ID_SIZE ,PHY_ID_FMT , + cpmac_mii.id, phy_id); +else +snprintf (priv->phy_name,BUS_ID_SIZE ,"fixed@%d:%d" ,100 ,1 ); + +if ((rc =register_netdev (dev))) { +printk (KERN_ERR "cpmac: error %i registering device %s\n" , + rc, dev->name); + goto fail; + } + +printk (KERN_INFO "cpmac: device %s (regs: %p, irq: %d, phy: %s, mac: " , + dev->name, (u32 *)dev->mem_start, dev->irq, + priv->phy_name); +for (i =0 ; i <6 ; i++) +printk ("%02x%s" , dev->dev_addr[i], i <5 ?":" :")\n" ); + +return 0 ; + +fail: +free_netdev (dev); +return rc; +} + +static int __devexit cpmac_remove(struct platform_device *pdev) +{
drivers/net/cpmac.c line 1130
Quoted 10 lines
drivers/net/cpmac.c new file +10
-0+struct net_device *dev =platform_get_drvdata (pdev); +unregister_netdev (dev); +free_netdev (dev); +return 0 ; +} + +static struct platform_driver cpmac_driver = { + .driver.name ="cpmac" , + .probe = cpmac_probe, + .remove = cpmac_remove,
This should be:
.remove = __devexit_p(cpmac_remove),
to avoid the final link from blowing up when the driver is built into the kernel.
drivers/net/cpmac.c line 1133
Quoted 3 lines
drivers/net/cpmac.c new file +3
-0+}; + +int __devinit cpmac_init (void )
Make this function static; no need to export.
drivers/net/cpmac.c line 1145
Quoted 12 lines
drivers/net/cpmac.c new file +12
-0+{ +u32 mask; +int i, res; + cpmac_mii.priv = +ioremap_nocache (AR7_REGS_MDIO ,sizeof (struct cpmac_mdio_regs )); + +if (!cpmac_mii.priv) { +printk (KERN_ERR "Can't ioremap mdio registers\n" ); +return -ENXIO ; + } + +#warning FIXME: unhardcode gpio&reset bits
Seeing such warnings always gives me a warm fuzzy feeling ;-)
Quoted 39 lines
drivers/net/cpmac.c new file +39
-0+ar7_gpio_disable (26 ); +ar7_gpio_disable (27 ); +ar7_device_reset (AR7_RESET_BIT_CPMAC_LO ); +ar7_device_reset (AR7_RESET_BIT_CPMAC_HI ); +ar7_device_reset (AR7_RESET_BIT_EPHY ); + + cpmac_mii.reset (&cpmac_mii); + +for (i =0 ; i <300000 ; i++) { + mask = ((struct cpmac_mdio_regs *)cpmac_mii.priv)->alive; +if (mask) +break ; + } + +/* mask &= 0x7fffffff; +if (mask & (mask - 1)) {*/ + external_switch =1 ; + mask =0 ; +/* }*/ + + cpmac_mii.phy_mask = ~(mask |0x80000000 ); + + res =mdiobus_register (&cpmac_mii); +if (res) + goto fail_mii; + + res =platform_driver_register (&cpmac_driver); +if (res) + goto fail_cpmac; + +return 0 ; + +fail_cpmac: +mdiobus_unregister (&cpmac_mii); + +fail_mii: +iounmap (cpmac_mii.priv); + +return res;
drivers/net/cpmac.c line 1194
Quoted 10 lines
drivers/net/cpmac.c new file +10
-0+} + +void __devexit cpmac_exit(void) +{ +platform_driver_unregister (&cpmac_driver); +mdiobus_unregister (&cpmac_mii); +} + +module_init (cpmac_init); +module_exit (cpmac_exit);
Time to run ...
Ralf
Re: [PATCH][MIPS][7/7] AR7: ethernet
Quoted 1 line · Ralf Baechle
On Sat, Sep 08, 2007 at 02:23:00AM +0200, Matteo Croce wrote:
[snip]
Quoted 28 lines
Quoted 28 lines
drivers/net/cpmac.c new file +28
-0+/* Register definitions */ +struct cpmac_control_regs { +u32 revision; +u32 control; +u32 teardown; +u32 unused; +} __attribute__ ((packed)); + +struct cpmac_int_regs { +u32 stat_raw; +u32 stat_masked; +u32 enable; +u32 clear; +} __attribute__ ((packed)); + +struct cpmac_stats { +u32 good; +u32 bcast; +u32 mcast; +u32 pause; +u32 crc_error; +u32 align_error; +u32 oversized; +u32 jabber; +u32 undersized; +u32 fragment; +u32 filtered; +u32 qos_filtered;
Quoted 8 lines
drivers/net/cpmac.c line 81
Quoted 2 lines
drivers/net/cpmac.c new file +2
-0+u32 octets; +} __attribute__ ((packed));All struct members here are sized such that there is no padding needed, so the packed attribute doesn't buy you anything - unless of course the entire structure is missaligned but I don't see how that would be possible in this driver so the
__attribute__((packed)) should go - it result in somwhat larger and slower code.
FWIW, a modern gcc will warn about such superfluous packed attributes, that's another reason to remove those.
Thiemo
Re: [PATCH][MIPS][7/7] AR7: ethernet
Quoted 8 lines · Thiemo Seufer
Quoted 5 lines
All struct members here are sized such that there is no padding needed, so the packed attribute doesn't buy you anything - unless of course the entire structure is missaligned but I don't see how that would be possible in this driver so the
__attribute__((packed)) should go - it result in somwhat larger and slower code.FWIW, a modern gcc will warn about such superfluous packed attributes, that's another reason to remove those.
I doubt it will in this case; the packed structure is dereferenced by a pointer so no way for gcc to know the alignment.
Ralf