From 1a73c7e2c98f05b830dd6634b044ea42fd81cdf5 Mon Sep 17 00:00:00 2001 From: wbx Date: Sun, 25 Dec 2005 20:04:16 +0000 Subject: first ar531x support for 2.4, thx Mile Albon, some addons from me for mips big endian toolchain git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@2781 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../patches/ar531x/000-atheros-support.patch | 2642 +++++++++++ .../patches/ar531x/001-ar531x-ethernet.patch | 4890 ++++++++++++++++++++ 2 files changed, 7532 insertions(+) create mode 100644 target/linux/linux-2.4/patches/ar531x/000-atheros-support.patch create mode 100644 target/linux/linux-2.4/patches/ar531x/001-ar531x-ethernet.patch (limited to 'target/linux/linux-2.4/patches') diff --git a/target/linux/linux-2.4/patches/ar531x/000-atheros-support.patch b/target/linux/linux-2.4/patches/ar531x/000-atheros-support.patch new file mode 100644 index 0000000000..1ec012f630 --- /dev/null +++ b/target/linux/linux-2.4/patches/ar531x/000-atheros-support.patch @@ -0,0 +1,2642 @@ +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xdbg_io.c linux-2.4.32.new/arch/mips/ar531x/ar531xdbg_io.c +--- linux-2.4.32/arch/mips/ar531x/ar531xdbg_io.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xdbg_io.c 2005-12-24 20:29:42.102311328 +0000 +@@ -0,0 +1,217 @@ ++/* ++ * 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 MontaVista Software Inc ++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * Basic support for polled character input/output ++ * using the AR531X's serial port. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++ ++#if CONFIG_EARLY_PRINTK_HACK || CONFIG_KGDB ++/* base addr of uart and clock timing */ ++#define BASE 0xbc000003 ++ ++/* distance in bytes between two serial registers */ ++#define REG_OFFSET 4 ++ ++/* ++ * 0 - we need to do serial init ++ * 1 - skip serial init ++ */ ++static int serialPortInitialized = 0; ++ ++/* ++ * * the default baud rate *if* we do serial init ++ * */ ++#define BAUD_DEFAULT UART16550_BAUD_9600 ++ ++/* === END OF CONFIG === */ ++ ++#define UART16550_BAUD_2400 2400 ++#define UART16550_BAUD_4800 4800 ++#define UART16550_BAUD_9600 9600 ++#define UART16550_BAUD_19200 19200 ++#define UART16550_BAUD_38400 38400 ++#define UART16550_BAUD_57600 57600 ++#define UART16550_BAUD_115200 115200 ++ ++#define UART16550_PARITY_NONE 0 ++#define UART16550_PARITY_ODD 0x08 ++#define UART16550_PARITY_EVEN 0x18 ++#define UART16550_PARITY_MARK 0x28 ++#define UART16550_PARITY_SPACE 0x38 ++ ++#define UART16550_DATA_5BIT 0x0 ++#define UART16550_DATA_6BIT 0x1 ++#define UART16550_DATA_7BIT 0x2 ++#define UART16550_DATA_8BIT 0x3 ++ ++#define UART16550_STOP_1BIT 0x0 ++#define UART16550_STOP_2BIT 0x4 ++ ++/* register offset */ ++#define OFS_RCV_BUFFER (0*REG_OFFSET) ++#define OFS_TRANS_HOLD (0*REG_OFFSET) ++#define OFS_SEND_BUFFER (0*REG_OFFSET) ++#define OFS_INTR_ENABLE (1*REG_OFFSET) ++#define OFS_INTR_ID (2*REG_OFFSET) ++#define OFS_DATA_FORMAT (3*REG_OFFSET) ++#define OFS_LINE_CONTROL (3*REG_OFFSET) ++#define OFS_MODEM_CONTROL (4*REG_OFFSET) ++#define OFS_RS232_OUTPUT (4*REG_OFFSET) ++#define OFS_LINE_STATUS (5*REG_OFFSET) ++#define OFS_MODEM_STATUS (6*REG_OFFSET) ++#define OFS_RS232_INPUT (6*REG_OFFSET) ++#define OFS_SCRATCH_PAD (7*REG_OFFSET) ++ ++#define OFS_DIVISOR_LSB (0*REG_OFFSET) ++#define OFS_DIVISOR_MSB (1*REG_OFFSET) ++ ++ ++/* memory-mapped read/write of the port */ ++#define UART16550_READ(y) (*((volatile u8*)(BASE + y))) ++#define UART16550_WRITE(y, z) ((*((volatile u8*)(BASE + y))) = z) ++ ++void ++debugPortInit(u32 baud, u8 data, u8 parity, u8 stop) ++{ ++ /* Pull UART out of reset */ ++ sysRegWrite(AR531X_RESET, ++ sysRegRead(AR531X_RESET) & ~(AR531X_RESET_UART0)); ++ ++ /* disable interrupts */ ++ UART16550_WRITE(OFS_LINE_CONTROL, 0x0); ++ UART16550_WRITE(OFS_INTR_ENABLE, 0); ++ ++ /* set up buad rate */ ++ { ++ u32 divisor; ++ u32 uart_clock_rate = ar531x_cpu_frequency() / 4; ++ u32 base_baud = uart_clock_rate / 16; ++ ++ /* set DIAB bit */ ++ UART16550_WRITE(OFS_LINE_CONTROL, 0x80); ++ ++ /* set divisor */ ++ divisor = base_baud / baud; ++ UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); ++ UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8); ++ ++ /* clear DIAB bit */ ++ UART16550_WRITE(OFS_LINE_CONTROL, 0x0); ++ } ++ ++ /* set data format */ ++ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); ++} ++ ++u8 ++getDebugChar(void) ++{ ++ if (!serialPortInitialized) { ++ serialPortInitialized = 1; ++ debugPortInit(BAUD_DEFAULT, ++ UART16550_DATA_8BIT, ++ UART16550_PARITY_NONE, UART16550_STOP_1BIT); ++ } ++ ++ while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); ++ return UART16550_READ(OFS_RCV_BUFFER); ++} ++ ++#if CONFIG_KGDB ++/* ++ * Peek at the most recently received character. ++ * Don't wait for a new character to be received. ++ */ ++u8 ++peekDebugChar(void) ++{ ++ return UART16550_READ(OFS_RCV_BUFFER); ++} ++ ++static int kgdbInitialized = 0; ++ ++void ++kgdbInit(void) ++{ ++ sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION); ++ ++ if (!kgdbInitialized) { ++ printk("Setting debug traps - please connect the remote debugger.\n"); ++ set_debug_traps(); ++ kgdbInitialized = 1; ++ } ++ breakpoint(); ++} ++ ++int ++kgdbEnabled(void) ++{ ++ return kgdbInitialized; ++} ++ ++#define DEBUG_CHAR '\001'; ++ ++int ++kgdbInterrupt(void) ++{ ++ if (!kgdbInitialized) { ++ return 0; ++ } ++ ++ /* ++ * Try to avoid swallowing too much input: Only consume ++ * a character if nothing new has arrived. Yes, there's ++ * still a small hole here, and we may lose an input ++ * character now and then. ++ */ ++ if (UART16550_READ(OFS_LINE_STATUS) & 1) { ++ return 0; ++ } else { ++ return UART16550_READ(OFS_RCV_BUFFER) == DEBUG_CHAR; ++ } ++} ++#endif ++ ++ ++void ++putDebugChar(char byte) ++{ ++ if (!serialPortInitialized) { ++ serialPortInitialized = 1; ++ debugPortInit(BAUD_DEFAULT, ++ UART16550_DATA_8BIT, ++ UART16550_PARITY_NONE, UART16550_STOP_1BIT); ++ } ++ ++ while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0); ++ UART16550_WRITE(OFS_SEND_BUFFER, byte); ++ } ++#endif /* CONFIG_EARLY_PRINTK_HACK || CONFIG_KGDB */ +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xgpio.c linux-2.4.32.new/arch/mips/ar531x/ar531xgpio.c +--- linux-2.4.32/arch/mips/ar531x/ar531xgpio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xgpio.c 2005-12-24 20:29:42.102311328 +0000 +@@ -0,0 +1,141 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * Support for GPIO -- General Purpose Input/Output Pins ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++ ++/* GPIO Interrupt Support */ ++ ++/* Turn on the specified AR531X_GPIO_IRQ interrupt */ ++static unsigned int ++ar531x_gpio_intr_startup(unsigned int irq) ++{ ++ ar531x_gpio_intr_enable(irq); ++ return 0; ++} ++ ++/* Turn off the specified AR531X_GPIO_IRQ interrupt */ ++static void ++ar531x_gpio_intr_shutdown(unsigned int irq) ++{ ++ ar531x_gpio_intr_disable(irq); ++} ++ ++u32 gpioIntMask = 0; ++ ++/* Enable the specified AR531X_GPIO_IRQ interrupt */ ++void ++ar531x_gpio_intr_enable(unsigned int irq) ++{ ++ u32 reg; ++ int gpio; ++ ++ gpio = irq - AR531X_GPIO_IRQ_BASE; ++ gpioIntMask |= gpio; ++ ++ reg = sysRegRead(AR531X_GPIO_CR); ++ reg &= ~(GPIO_CR_M(gpio) | GPIO_CR_UART(gpio) | GPIO_CR_INT(gpio)); ++ reg |= GPIO_CR_I(gpio); ++ reg |= GPIO_CR_INT(gpio); ++ ++ sysRegWrite(AR531X_GPIO_CR, reg); ++ (void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */ ++} ++ ++/* Disable the specified AR531X_GPIO_IRQ interrupt */ ++void ++ar531x_gpio_intr_disable(unsigned int irq) ++{ ++ u32 reg; ++ int gpio; ++ ++ gpio = irq - AR531X_GPIO_IRQ_BASE; ++ ++ reg = sysRegRead(AR531X_GPIO_CR); ++ reg &= ~(GPIO_CR_M(gpio) | GPIO_CR_UART(gpio) | GPIO_CR_INT(gpio)); ++ reg |= GPIO_CR_I(gpio); ++ /* No GPIO_CR_INT bit */ ++ ++ sysRegWrite(AR531X_GPIO_CR, reg); ++ (void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */ ++ ++ gpioIntMask &= ~gpio; ++} ++ ++static void ++ar531x_gpio_intr_ack(unsigned int irq) ++{ ++ ar531x_gpio_intr_disable(irq); ++} ++ ++static void ++ar531x_gpio_intr_end(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) ++ ar531x_gpio_intr_enable(irq); ++} ++ ++static void ++ar531x_gpio_intr_set_affinity(unsigned int irq, unsigned long mask) ++{ ++ /* Only 1 CPU; ignore affinity request */ ++} ++ ++int ar531x_gpio_irq_base; ++ ++struct hw_interrupt_type ar531x_gpio_intr_controller = { ++ "AR531X GPIO", ++ ar531x_gpio_intr_startup, ++ ar531x_gpio_intr_shutdown, ++ ar531x_gpio_intr_enable, ++ ar531x_gpio_intr_disable, ++ ar531x_gpio_intr_ack, ++ ar531x_gpio_intr_end, ++ ar531x_gpio_intr_set_affinity, ++}; ++ ++void ++ar531x_gpio_intr_init(int irq_base) ++{ ++ int i; ++ ++ for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) { ++ irq_desc[i].status = IRQ_DISABLED; ++ irq_desc[i].action = NULL; ++ irq_desc[i].depth = 1; ++ irq_desc[i].handler = &ar531x_gpio_intr_controller; ++ } ++ ++ ar531x_gpio_irq_base = irq_base; ++} ++ ++/* ARGSUSED */ ++void ++spurious_gpio_handler(int cpl, void *dev_id, struct pt_regs *regs) ++{ ++ u32 gpioDataIn; ++ ++ gpioDataIn = sysRegRead(AR531X_GPIO_DI) & gpioIntMask; ++ ++ printk("spurious_gpio_handler: 0x%x di=0x%8.8x gpioIntMask=0x%8.8x\n", ++ cpl, gpioDataIn, gpioIntMask); ++} ++ ++struct irqaction spurious_gpio = ++ {spurious_gpio_handler, SA_INTERRUPT, 0, "spurious_gpio", ++ NULL, NULL}; ++ +diff -urN linux-2.4.32/arch/mips/ar531x/ar531x.h linux-2.4.32.new/arch/mips/ar531x/ar531x.h +--- linux-2.4.32/arch/mips/ar531x/ar531x.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531x.h 2005-12-24 20:29:42.102311328 +0000 +@@ -0,0 +1,280 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++#ifndef AR531X_H ++#define AR531X_H 1 ++ ++#include ++ ++/* Address Map */ ++#define AR531X_WLAN0 0x18000000 ++#define AR531X_WLAN1 0x18500000 ++#define AR531X_ENET0 0x18100000 ++#define AR531X_ENET1 0x18200000 ++#define AR531X_SDRAMCTL 0x18300000 ++#define AR531X_FLASHCTL 0x18400000 ++#define AR531X_APBBASE 0x1c000000 ++#define AR531X_FLASH 0x1e000000 ++ ++/* ++ * AR531X_NUM_ENET_MAC defines the number of ethernet MACs that ++ * should be considered available. The AR5312 supports 2 enet MACS, ++ * even though many reference boards only actually use 1 of them ++ * (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch. ++ * The AR2312 supports 1 enet MAC. ++ */ ++#define AR531X_NUM_ENET_MAC 2 ++ ++/* ++ * Need these defines to determine true number of ethernet MACs ++ */ ++#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ ++#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ ++#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */ ++#define AR531X_RADIO_MASK_OFF 0xc8 ++#define AR531X_RADIO0_MASK 0x0003 ++#define AR531X_RADIO1_MASK 0x000c ++#define AR531X_RADIO1_S 2 ++ ++/* ++ * AR531X_NUM_WMAC defines the number of Wireless MACs that\ ++ * should be considered available. ++ */ ++#define AR531X_NUM_WMAC 2 ++ ++/* Reset/Timer Block Address Map */ ++#define AR531X_RESETTMR (AR531X_APBBASE + 0x3000) ++#define AR531X_TIMER (AR531X_RESETTMR + 0x0000) /* countdown timer */ ++#define AR531X_WD_CTRL (AR531X_RESETTMR + 0x0008) /* watchdog cntrl */ ++#define AR531X_WD_TIMER (AR531X_RESETTMR + 0x000c) /* watchdog timer */ ++#define AR531X_ISR (AR531X_RESETTMR + 0x0010) /* Intr Status Reg */ ++#define AR531X_IMR (AR531X_RESETTMR + 0x0014) /* Intr Mask Reg */ ++#define AR531X_RESET (AR531X_RESETTMR + 0x0020) ++#define AR5312_CLOCKCTL1 (AR531X_RESETTMR + 0x0064) ++#define AR5312_SCRATCH (AR531X_RESETTMR + 0x006c) ++#define AR531X_PROCADDR (AR531X_RESETTMR + 0x0070) ++#define AR531X_PROC1 (AR531X_RESETTMR + 0x0074) ++#define AR531X_DMAADDR (AR531X_RESETTMR + 0x0078) ++#define AR531X_DMA1 (AR531X_RESETTMR + 0x007c) ++#define AR531X_ENABLE (AR531X_RESETTMR + 0x0080) /* interface enb */ ++#define AR531X_REV (AR531X_RESETTMR + 0x0090) /* revision */ ++ ++/* AR531X_WD_CTRL register bit field definitions */ ++#define AR531X_WD_CTRL_IGNORE_EXPIRATION 0x0000 ++#define AR531X_WD_CTRL_NMI 0x0001 ++#define AR531X_WD_CTRL_RESET 0x0002 ++ ++/* AR531X_ISR register bit field definitions */ ++#define AR531X_ISR_NONE 0x0000 ++#define AR531X_ISR_TIMER 0x0001 ++#define AR531X_ISR_AHBPROC 0x0002 ++#define AR531X_ISR_AHBDMA 0x0004 ++#define AR531X_ISR_GPIO 0x0008 ++#define AR531X_ISR_UART0 0x0010 ++#define AR531X_ISR_UART0DMA 0x0020 ++#define AR531X_ISR_WD 0x0040 ++#define AR531X_ISR_LOCAL 0x0080 ++ ++/* AR531X_RESET register bit field definitions */ ++#define AR531X_RESET_SYSTEM 0x00000001 /* cold reset full system */ ++#define AR531X_RESET_PROC 0x00000002 /* cold reset MIPS core */ ++#define AR531X_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */ ++#define AR531X_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ ++#define AR531X_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ ++#define AR531X_RESET_ENET0 0x00000020 /* cold reset ENET0 mac */ ++#define AR531X_RESET_ENET1 0x00000040 /* cold reset ENET1 mac */ ++#define AR531X_RESET_UART0 0x00000100 /* cold reset UART0 (high speed) */ ++#define AR531X_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */ ++#define AR531X_RESET_APB 0x00000400 /* cold reset APB (ar5312) */ ++#define AR531X_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */ ++#define AR531X_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */ ++#define AR531X_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BaseBand */ ++#define AR531X_RESET_NMI 0x00010000 /* send an NMI to the processor */ ++#define AR531X_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 mac */ ++#define AR531X_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 baseband */ ++#define AR531X_RESET_LOCAL_BUS 0x00080000 /* reset local bus */ ++#define AR531X_RESET_WDOG 0x00100000 /* last reset was a watchdog */ ++ ++#define AR531X_RESET_WMAC0_BITS \ ++ AR531X_RESET_WLAN0 |\ ++ AR531X_RESET_WARM_WLAN0_MAC |\ ++ AR531X_RESET_WARM_WLAN0_BB ++ ++#define AR531X_RESERT_WMAC1_BITS \ ++ AR531X_RESET_WLAN1 |\ ++ AR531X_RESET_WARM_WLAN1_MAC |\ ++ AR531X_RESET_WARM_WLAN1_BB ++ ++/* AR5312_CLOCKCTL1 register bit field definitions */ ++#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 ++#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 ++#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 ++#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 ++#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 ++ ++/* Valid for AR5312 and AR2312 */ ++#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 ++#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 ++#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 ++#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 ++#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 ++ ++/* Valid for AR2313 */ ++#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000 ++#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12 ++#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000 ++#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16 ++#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000 ++ ++ ++/* AR531X_ENABLE register bit field definitions */ ++#define AR531X_ENABLE_WLAN0 0x0001 ++#define AR531X_ENABLE_ENET0 0x0002 ++#define AR531X_ENABLE_ENET1 0x0004 ++#define AR531X_ENABLE_UART_AND_WLAN1_PIO 0x0008 /* UART, and WLAN1 PIOs */ ++#define AR531X_ENABLE_WLAN1_DMA 0x0010 /* WLAN1 DMAs */ ++#define AR531X_ENABLE_WLAN1 \ ++ (AR531X_ENABLE_UART_AND_WLAN1_PIO | AR531X_ENABLE_WLAN1_DMA) ++ ++/* AR531X_REV register bit field definitions */ ++#define AR531X_REV_WMAC_MAJ 0xf000 ++#define AR531X_REV_WMAC_MAJ_S 12 ++#define AR531X_REV_WMAC_MIN 0x0f00 ++#define AR531X_REV_WMAC_MIN_S 8 ++#define AR531X_REV_MAJ 0x00f0 ++#define AR531X_REV_MAJ_S 4 ++#define AR531X_REV_MIN 0x000f ++#define AR531X_REV_MIN_S 0 ++#define AR531X_REV_CHIP (REV_MAJ|REV_MIN) ++ ++/* Major revision numbers, bits 7..4 of Revision ID register */ ++#define AR531X_REV_MAJ_AR5312 0x4 ++#define AR531X_REV_MAJ_AR2313 0x5 ++ ++/* Minor revision numbers, bits 3..0 of Revision ID register */ ++#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */ ++#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */ ++ ++/* AR531X_FLASHCTL register bit field definitions */ ++#define FLASHCTL_IDCY 0x0000000f /* Idle cycle turn around time */ ++#define FLASHCTL_IDCY_S 0 ++#define FLASHCTL_WST1 0x000003e0 /* Wait state 1 */ ++#define FLASHCTL_WST1_S 5 ++#define FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */ ++#define FLASHCTL_WST2 0x0000f800 /* Wait state 2 */ ++#define FLASHCTL_WST2_S 11 ++#define FLASHCTL_AC 0x00070000 /* Flash address check (added) */ ++#define FLASHCTL_AC_S 16 ++#define FLASHCTL_AC_128K 0x00000000 ++#define FLASHCTL_AC_256K 0x00010000 ++#define FLASHCTL_AC_512K 0x00020000 ++#define FLASHCTL_AC_1M 0x00030000 ++#define FLASHCTL_AC_2M 0x00040000 ++#define FLASHCTL_AC_4M 0x00050000 ++#define FLASHCTL_AC_8M 0x00060000 ++#define FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */ ++#define FLASHCTL_E 0x00080000 /* Flash bank enable (added) */ ++#define FLASHCTL_BUSERR 0x01000000 /* Bus transfer error status flag */ ++#define FLASHCTL_WPERR 0x02000000 /* Write protect error status flag */ ++#define FLASHCTL_WP 0x04000000 /* Write protect */ ++#define FLASHCTL_BM 0x08000000 /* Burst mode */ ++#define FLASHCTL_MW 0x30000000 /* Memory width */ ++#define FLASHCTL_MWx8 0x00000000 /* Memory width x8 */ ++#define FLASHCTL_MWx16 0x10000000 /* Memory width x16 */ ++#define FLASHCTL_MWx32 0x20000000 /* Memory width x32 (not supported) */ ++#define FLASHCTL_ATNR 0x00000000 /* Access type == no retry */ ++#define FLASHCTL_ATR 0x80000000 /* Access type == retry every */ ++#define FLASHCTL_ATR4 0xc0000000 /* Access type == retry every 4 */ ++ ++/* ARM Flash Controller -- 3 flash banks with either x8 or x16 devices. */ ++#define AR531X_FLASHCTL0 (AR531X_FLASHCTL + 0x00) ++#define AR531X_FLASHCTL1 (AR531X_FLASHCTL + 0x04) ++#define AR531X_FLASHCTL2 (AR531X_FLASHCTL + 0x08) ++ ++/* ARM SDRAM Controller -- just enough to determine memory size */ ++#define AR531X_MEM_CFG1 (AR531X_SDRAMCTL + 0x04) ++#define MEM_CFG1_AC0 0x00000700 /* bank 0: SDRAM addr check (added) */ ++#define MEM_CFG1_AC0_S 8 ++#define MEM_CFG1_AC1 0x00007000 /* bank 1: SDRAM addr check (added) */ ++#define MEM_CFG1_AC1_S 12 ++ ++/* GPIO Address Map */ ++#define AR531X_GPIO (AR531X_APBBASE + 0x2000) ++#define AR531X_GPIO_DO (AR531X_GPIO + 0x00) /* output register */ ++#define AR531X_GPIO_DI (AR531X_GPIO + 0x04) /* intput register */ ++#define AR531X_GPIO_CR (AR531X_GPIO + 0x08) /* control register */ ++ ++/* GPIO Control Register bit field definitions */ ++#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ ++#define GPIO_CR_O(x) (0 << (x)) /* mask for output */ ++#define GPIO_CR_I(x) (1 << (x)) /* mask for input */ ++#define GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */ ++#define GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */ ++ ++ ++typedef unsigned int AR531X_REG; ++ ++#define sysRegRead(phys) \ ++ (*(volatile AR531X_REG *)PHYS_TO_K1(phys)) ++ ++#define sysRegWrite(phys, val) \ ++ ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val)) ++ ++ ++/* ++ * This is board-specific data that is stored in a "fixed" location in flash. ++ * It is shared across operating systems, so it should not be changed lightly. ++ * The main reason we need it is in order to extract the ethernet MAC ++ * address(es). ++ */ ++struct ar531x_boarddata { ++ u32 magic; /* board data is valid */ ++#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */ ++ u16 cksum; /* checksum (starting with BD_REV 2) */ ++ u16 rev; /* revision of this struct */ ++#define BD_REV 4 ++ char boardName[64]; /* Name of board */ ++ u16 major; /* Board major number */ ++ u16 minor; /* Board minor number */ ++ u32 config; /* Board configuration */ ++#define BD_ENET0 0x00000001 /* ENET0 is stuffed */ ++#define BD_ENET1 0x00000002 /* ENET1 is stuffed */ ++#define BD_UART1 0x00000004 /* UART1 is stuffed */ ++#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */ ++#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */ ++#define BD_SYSLED 0x00000020 /* System LED stuffed */ ++#define BD_EXTUARTCLK 0x00000040 /* External UART clock */ ++#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */ ++#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */ ++#define BD_WLAN0 0x00000200 /* Enable WLAN0 */ ++#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */ ++#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */ ++#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */ ++#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */ ++#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */ ++#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */ ++#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */ ++#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */ ++ u16 resetConfigGpio; /* Reset factory GPIO pin */ ++ u16 sysLedGpio; /* System LED GPIO pin */ ++ ++ u32 cpuFreq; /* CPU core frequency in Hz */ ++ u32 sysFreq; /* System frequency in Hz */ ++ u32 cntFreq; /* Calculated C0_COUNT frequency */ ++ ++ u8 wlan0Mac[6]; ++ u8 enet0Mac[6]; ++ u8 enet1Mac[6]; ++ ++ u16 pciId; /* Pseudo PCIID for common code */ ++ u16 memCap; /* cap bank1 in MB */ ++ ++ /* version 3 */ ++ u8 wlan1Mac[6]; /* (ar5212) */ ++}; ++#endif /* AR531X_H */ +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xintr.S linux-2.4.32.new/arch/mips/ar531x/ar531xintr.S +--- linux-2.4.32/arch/mips/ar531x/ar531xintr.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xintr.S 2005-12-24 20:29:42.103311176 +0000 +@@ -0,0 +1,30 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * Glue code to save registers and get us to the interrupt dispatcher ++ */ ++ .text ++ .set noat ++ .align 5 ++NESTED(ar531x_interrupt_receive, PT_SIZE, sp) ++ SAVE_ALL ++ CLI ++ .set at ++ ++ move a0, sp ++ jal ar531x_irq_dispatch ++ ++ j ret_from_irq ++ ++ END(ar531x_interrupt_receive) +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xirq.c linux-2.4.32.new/arch/mips/ar531x/ar531xirq.c +--- linux-2.4.32/arch/mips/ar531x/ar531xirq.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xirq.c 2005-12-24 20:29:42.132306768 +0000 +@@ -0,0 +1,292 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * Interrupt support for AR531X WiSOC. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++#include ++ ++extern int setup_irq(unsigned int irq, struct irqaction *irqaction); ++ ++static void ar531x_misc_intr_enable(unsigned int irq); ++static void ar531x_misc_intr_disable(unsigned int irq); ++ ++/* Turn on the specified AR531X_MISC_IRQ interrupt */ ++static unsigned int ++ar531x_misc_intr_startup(unsigned int irq) ++{ ++ ar531x_misc_intr_enable(irq); ++ return 0; ++} ++ ++/* Turn off the specified AR531X_MISC_IRQ interrupt */ ++static void ++ar531x_misc_intr_shutdown(unsigned int irq) ++{ ++ ar531x_misc_intr_disable(irq); ++} ++ ++/* Enable the specified AR531X_MISC_IRQ interrupt */ ++static void ++ar531x_misc_intr_enable(unsigned int irq) ++{ ++ unsigned int imr; ++ ++ imr = sysRegRead(AR531X_IMR); ++ imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1)); ++ sysRegWrite(AR531X_IMR, imr); ++ sysRegRead(AR531X_IMR); /* flush write buffer */ ++} ++ ++/* Disable the specified AR531X_MISC_IRQ interrupt */ ++static void ++ar531x_misc_intr_disable(unsigned int irq) ++{ ++ unsigned int imr; ++ ++ imr = sysRegRead(AR531X_IMR); ++ imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1)); ++ sysRegWrite(AR531X_IMR, imr); ++ sysRegRead(AR531X_IMR); /* flush write buffer */ ++} ++ ++static void ++ar531x_misc_intr_ack(unsigned int irq) ++{ ++ ar531x_misc_intr_disable(irq); ++} ++ ++static void ++ar531x_misc_intr_end(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) ++ ar531x_misc_intr_enable(irq); ++} ++ ++static void ++ar531x_misc_intr_set_affinity(unsigned int irq, unsigned long mask) ++{ ++ /* Only 1 CPU; ignore affinity request */ ++} ++ ++struct hw_interrupt_type ar531x_misc_intr_controller = { ++ "AR531X MISC", ++ ar531x_misc_intr_startup, ++ ar531x_misc_intr_shutdown, ++ ar531x_misc_intr_enable, ++ ar531x_misc_intr_disable, ++ ar531x_misc_intr_ack, ++ ar531x_misc_intr_end, ++ ar531x_misc_intr_set_affinity, ++}; ++ ++int ar531x_misc_irq_base; ++ ++/* ++ * Determine interrupt source among interrupts that use IP6 ++ */ ++void ++ar531x_misc_intr_init(int irq_base) ++{ ++ int i; ++ ++ for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) { ++ irq_desc[i].status = IRQ_DISABLED; ++ irq_desc[i].action = NULL; ++ irq_desc[i].depth = 1; ++ irq_desc[i].handler = &ar531x_misc_intr_controller; ++ } ++ ++ ar531x_misc_irq_base = irq_base; ++} ++ ++/* ARGSUSED */ ++void ++spurious_irq_handler(int cpl, void *dev_id, struct pt_regs *regs) ++{ ++ /* ++ printk("spurious_irq_handler: %d cause=0x%8.8x status=0x%8.8x\n", ++ cpl, cause_intrs, status_intrs); ++ */ ++} ++ ++/* ARGSUSED */ ++void ++spurious_misc_handler(int cpl, void *dev_id, struct pt_regs *regs) ++{ ++ /* ++ printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n", ++ cpl, ar531x_isr, ar531x_imr); ++ */ ++} ++ ++void ++ar531x_timer_handler(int cpl, void *dev_id, struct pt_regs *regs) ++{ ++ (void)sysRegRead(AR531X_TIMER); /* clear interrupt */ ++} ++ ++void ++ar531x_ahb_proc_handler(int cpl, void *dev_id, struct pt_regs *regs) ++{ ++ u32 procAddr; ++ u32 proc1; ++ u32 dmaAddr; ++ u32 dma1; ++ ++ proc1 = sysRegRead(AR531X_PROC1); ++ procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */ ++ dma1 = sysRegRead(AR531X_DMA1); ++ dmaAddr = sysRegRead(AR531X_DMAADDR); /* clears error state */ ++ ++ printk("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n", ++ procAddr, proc1, dmaAddr, dma1); ++ ++ machine_restart("AHB error"); /* Catastrophic failure */ ++} ++ ++static struct irqaction cascade = ++ {no_action, SA_INTERRUPT, 0, "cascade", ++ NULL, NULL}; ++ ++static struct irqaction spurious_irq = ++ {spurious_irq_handler, SA_INTERRUPT, 0, "spurious_irq", ++ NULL, NULL}; ++ ++static struct irqaction spurious_misc = ++ {spurious_misc_handler, SA_INTERRUPT, 0, "spurious_misc", ++ NULL, NULL}; ++ ++static struct irqaction ar531x_timer_interrupt = ++ {ar531x_timer_handler, SA_INTERRUPT, 0, "ar531x_timer_interrupt", ++ NULL, NULL}; ++ ++static struct irqaction ar531x_ahb_proc_interrupt = ++ {ar531x_ahb_proc_handler, SA_INTERRUPT, 0, "ar531x_ahb_proc_interrupt", ++ NULL, NULL}; ++ ++extern asmlinkage void ar531x_interrupt_receive(void); ++ ++/* ++ * Called when an interrupt is received, this function ++ * determines exactly which interrupt it was, and it ++ * invokes the appropriate handler. ++ * ++ * Implicitly, we also define interrupt priority by ++ * choosing which to dispatch first. ++ */ ++void ++ar531x_irq_dispatch(struct pt_regs *regs) ++{ ++ int cause_intrs = regs->cp0_cause; ++ int status_intrs = regs->cp0_status; ++ int pending = cause_intrs & status_intrs; ++ ++ if (pending & CAUSEF_IP2) { ++ do_IRQ(AR531X_IRQ_WLAN0_INTRS, regs); ++ } ++ else if (pending & CAUSEF_IP3) { ++ do_IRQ(AR531X_IRQ_ENET0_INTRS, regs); ++ } ++ else if (pending & CAUSEF_IP4) { ++ do_IRQ(AR531X_IRQ_ENET1_INTRS, regs); ++ } ++ else if (pending & CAUSEF_IP5) { ++ do_IRQ(AR531X_IRQ_WLAN1_INTRS, regs); ++ } ++ else if (pending & CAUSEF_IP6) { ++ AR531X_REG ar531x_isr = sysRegRead(AR531X_ISR); ++ AR531X_REG ar531x_imr = sysRegRead(AR531X_IMR); ++ unsigned int ar531x_misc_intrs = ar531x_isr & ar531x_imr; ++ ++ if (ar531x_misc_intrs & AR531X_ISR_TIMER) ++ do_IRQ(AR531X_MISC_IRQ_TIMER, regs); ++ else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC) ++ do_IRQ(AR531X_MISC_IRQ_AHB_PROC, regs); ++ else if (ar531x_misc_intrs & AR531X_ISR_AHBDMA) ++ do_IRQ(AR531X_MISC_IRQ_AHB_DMA, regs); ++ else if (ar531x_misc_intrs & AR531X_ISR_GPIO) ++ { ++ int i; ++ u32 gpioIntPending; ++ ++ gpioIntPending = sysRegRead(AR531X_GPIO_DI) & gpioIntMask; ++ for (i=0; icp0_epc); ++ } ++#endif /* CONFIG_KGDB */ ++ } ++ else if (ar531x_misc_intrs & AR531X_ISR_WD) ++ do_IRQ(AR531X_MISC_IRQ_WATCHDOG, regs); ++ else if (ar531x_misc_intrs & AR531X_ISR_LOCAL) ++ do_IRQ(AR531X_MISC_IRQ_LOCAL, regs); ++ else ++ do_IRQ(AR531X_MISC_IRQ_NONE, regs); ++ } else if (pending & CAUSEF_IP7) ++ do_IRQ(AR531X_IRQ_CPU_CLOCK, regs); ++ else ++ do_IRQ(AR531X_IRQ_NONE, regs); ++} ++ ++void __init init_IRQ(void) ++{ ++ init_generic_irq(); ++ set_except_vector(0, ar531x_interrupt_receive); ++ ++ /* Initialize interrupt controllers */ ++ mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); ++ ar531x_misc_intr_init(AR531X_MISC_IRQ_BASE); ++ ar531x_gpio_intr_init(AR531X_GPIO_IRQ_BASE); ++ setup_irq(AR531X_IRQ_MISC_INTRS, &cascade); ++ /* ++ * AR531X_IRQ_CPU_CLOCK is setup by ar531x_timer_setup. ++ */ ++ ++ /* Default "spurious interrupt" handlers */ ++ setup_irq(AR531X_IRQ_NONE, &spurious_irq); ++ setup_irq(AR531X_MISC_IRQ_NONE, &spurious_misc); ++ setup_irq(AR531X_GPIO_IRQ_NONE, &spurious_gpio); ++ ++ setup_irq(AR531X_MISC_IRQ_TIMER, &ar531x_timer_interrupt); ++ setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar531x_ahb_proc_interrupt); ++ setup_irq(AR531X_MISC_IRQ_GPIO, &cascade); ++ ++#ifdef CONFIG_KGDB ++#if CONFIG_EARLY_STOP ++ kgdbInit(); ++#endif ++#endif ++} +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xksyms.c linux-2.4.32.new/arch/mips/ar531x/ar531xksyms.c +--- linux-2.4.32/arch/mips/ar531x/ar531xksyms.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xksyms.c 2005-12-24 20:29:42.132306768 +0000 +@@ -0,0 +1,16 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++#include ++#include "asm/atheros/ar531xbsp.h" ++ ++#if CONFIG_KGDB ++EXPORT_SYMBOL(kgdbInit); ++EXPORT_SYMBOL(kgdbEnabled); ++#endif ++EXPORT_SYMBOL(ar531x_sys_frequency); +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xlnx.h linux-2.4.32.new/arch/mips/ar531x/ar531xlnx.h +--- linux-2.4.32/arch/mips/ar531x/ar531xlnx.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xlnx.h 2005-12-24 20:29:42.133306616 +0000 +@@ -0,0 +1,122 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * This file contains definitions needed in order to compile ++ * AR531X products for linux. Definitions that are largely ++ * AR531X-specific and independent of operating system belong ++ * in ar531x.h rather than this file. ++ */ ++#include "ar531x.h" ++ ++#define MIPS_CPU_IRQ_BASE 0x00 ++#define AR531X_HIGH_PRIO 0x10 ++#define AR531X_MISC_IRQ_BASE 0x20 ++#define AR531X_GPIO_IRQ_BASE 0x30 ++ ++/* Software's idea of interrupts handled by "CPU Interrupt Controller" */ ++#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 ++#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ ++#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ ++#define AR531X_IRQ_ENET1_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ ++#define AR531X_IRQ_WLAN1_INTRS MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */ ++#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ ++#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ ++ ++/* Miscellaneous interrupts, which share IP6 */ ++#define AR531X_MISC_IRQ_NONE AR531X_MISC_IRQ_BASE+0 ++#define AR531X_MISC_IRQ_TIMER AR531X_MISC_IRQ_BASE+1 ++#define AR531X_MISC_IRQ_AHB_PROC AR531X_MISC_IRQ_BASE+2 ++#define AR531X_MISC_IRQ_AHB_DMA AR531X_MISC_IRQ_BASE+3 ++#define AR531X_MISC_IRQ_GPIO AR531X_MISC_IRQ_BASE+4 ++#define AR531X_MISC_IRQ_UART0 AR531X_MISC_IRQ_BASE+5 ++#define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6 ++#define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7 ++#define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8 ++#define AR531X_MISC_IRQ_COUNT 9 ++ ++/* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */ ++#define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0 ++#define AR531X_GPIO_IRQ(n) AR531X_MISC_IRQ_BASE+(n)+1 ++#define AR531X_GPIO_IRQ_COUNT 9 ++ ++#define PHYS_TO_K1(physaddr) KSEG1ADDR(physaddr) ++#define PHYS_TO_K0(physaddr) KSEG0ADDR(physaddr) ++#define UNMAPPED_TO_PHYS(vaddr) PHYSADDR(vaddr) ++#define IS_UNMAPPED_VADDR(vaddr) \ ++ ((KSEGX(vaddr) == KSEG0) || (KSEGX(vaddr) == KSEG1)) ++ ++/* IOCTL commands for /proc/ar531x */ ++#define AR531X_CTRL_DO_BREAKPOINT 1 ++#define AR531X_CTRL_DO_MADWIFI 2 ++ ++/* ++ * Definitions for operating system portability. ++ * These are vxWorks-->Linux translations. ++ */ ++#define LOCAL static ++#define BOOL int ++#define TRUE 1 ++#define FALSE 0 ++#define UINT8 u8 ++#define UINT16 u16 ++#define UINT32 u32 ++#define PRINTF printk ++#if /* DEBUG */ 1 ++#define DEBUG_PRINTF printk ++#define INLINE ++#else ++DEBUG_PRINTF while (0) printk ++#define INLINE inline ++#endif ++#define sysUDelay(usecs) udelay(usecs) ++#define sysMsDelay(msecs) mdelay(msecs) ++typedef volatile UINT8 *VIRT_ADDR; ++#define MALLOC(sz) kmalloc(sz, GFP_KERNEL) ++#define MALLOC_NOSLEEP(sz) kmalloc(sz, GFP_ATOMIC) ++#define FREE(ptr) kfree((void *)ptr) ++#define BSP_BUG() do { printk("kernel BSP BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) ++#define BSP_BUG_ON(condition) do { if (unlikely((condition)!=0)) BSP_BUG(); } while(0) ++#define ASSERT(x) BSP_BUG_ON(!(x)) ++ ++extern struct ar531x_boarddata *ar531x_board_configuration; ++extern char *ar531x_radio_configuration; ++extern char *enet_mac_address_get(int MACUnit); ++ ++extern void kgdbInit(void); ++extern int kgdbEnabled(void); ++extern void breakpoint(void); ++extern int kgdbInterrupt(void); ++extern unsigned int ar531x_cpu_frequency(void); ++extern unsigned int ar531x_sys_frequency(void); ++ ++/* GPIO support */ ++extern struct irqaction spurious_gpio; ++extern unsigned int gpioIntMask; ++extern void ar531x_gpio_intr_init(int irq_base); ++extern void ar531x_gpio_ctrl_output(int gpio); ++extern void ar531x_gpio_ctrl_input(int gpio); ++extern void ar531x_gpio_set(int gpio, int val); ++extern int ar531x_gpio_get(int gpio); ++extern void ar531x_gpio_intr_enable(unsigned int irq); ++extern void ar531x_gpio_intr_disable(unsigned int irq); ++ ++/* Watchdog Timer support */ ++extern int watchdog_start(unsigned int milliseconds); ++extern int watchdog_stop(void); ++extern int watchdog_is_enabled(void); ++extern unsigned int watchdog_min_timer_reached(void); ++extern void watchdog_notify_alive(void); ++ ++#define A_DATA_CACHE_INVAL(start, length) \ ++ dma_cache_inv((UINT32)(start),(length)) ++ ++#define sysWbFlush() mb() ++ ++#define intDisable(x) cli() ++#define intEnable(x) sti() +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xprom.c linux-2.4.32.new/arch/mips/ar531x/ar531xprom.c +--- linux-2.4.32/arch/mips/ar531x/ar531xprom.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xprom.c 2005-12-24 20:29:42.133306616 +0000 +@@ -0,0 +1,84 @@ ++/* ++ * 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 MontaVista Software Inc ++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * Prom setup file for ar531x ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "ar531xlnx.h" ++ ++#define COMMAND_LINE_SIZE 512 ++ ++char arcs_cmdline[COMMAND_LINE_SIZE]; ++ ++void __init prom_init(int argc, char *argv[]) ++{ ++ int i; ++ unsigned int memcfg1; ++ int bank0AC, bank1AC; ++ int memsz_in_mb; ++ ++ strcpy(arcs_cmdline, "console=ttyS0,9600"); ++ for (i=0; i> MEM_CFG1_AC0_S; ++ bank1AC = (memcfg1 & MEM_CFG1_AC1) >> MEM_CFG1_AC1_S; ++ memsz_in_mb = (bank0AC ? (1 << (bank0AC+1)) : 0) ++ + (bank1AC ? (1 << (bank1AC+1)) : 0); ++ ++ /* ++ * By default, use all available memory. You can override this ++ * to use, say, 8MB by specifying "mem=8M" as an argument on the ++ * linux bootup command line. ++ */ ++ add_memory_region(0, memsz_in_mb << 20, BOOT_MEM_RAM); ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} +diff -urN linux-2.4.32/arch/mips/ar531x/ar531xsetup.c linux-2.4.32.new/arch/mips/ar531x/ar531xsetup.c +--- linux-2.4.32/arch/mips/ar531x/ar531xsetup.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/ar531xsetup.c 2005-12-24 20:29:42.133306616 +0000 +@@ -0,0 +1,240 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * Initialization for ar531x SOC. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++ ++void ++ar531x_restart(char *command) ++{ ++ for(;;) { ++ sysRegWrite(AR531X_RESET, AR531X_RESET_SYSTEM); ++ } ++} ++ ++void ++ar531x_halt(void) ++{ ++ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); ++ while (1); ++} ++ ++void ++ar531x_power_off(void) ++{ ++ ar531x_halt(); ++} ++ ++const char * ++get_system_type(void) ++{ ++ return "Atheros AR531X"; ++} ++ ++/* ++ * This table is indexed by bits 5..4 of the CLOCKCTL1 register ++ * to determine the predevisor value. ++ */ ++static int CLOCKCTL1_PREDIVIDE_TABLE[4] = { ++ 1, ++ 2, ++ 4, ++ 5 ++}; ++ ++unsigned int ++ar531x_cpu_frequency(void) ++{ ++ static unsigned int ar531x_calculated_cpu_freq; ++ unsigned int clockctl1_predivide_mask; ++ unsigned int clockctl1_predivide_shift; ++ unsigned int clockctl1_multiplier_mask; ++ unsigned int clockctl1_multiplier_shift; ++ unsigned int clockctl1_doubler_mask; ++ int wisoc_revision; ++ ++ /* ++ * Trust the bootrom's idea of cpu frequency. ++ */ ++ ar531x_calculated_cpu_freq = sysRegRead(AR5312_SCRATCH); ++ if (ar531x_calculated_cpu_freq) ++ return ar531x_calculated_cpu_freq; ++ ++ wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S; ++ if (wisoc_revision == AR531X_REV_MAJ_AR2313) { ++ clockctl1_predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK; ++ clockctl1_predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT; ++ clockctl1_multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK; ++ clockctl1_multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT; ++ clockctl1_doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK; ++ } else { /* AR5312 and AR2312 */ ++ clockctl1_predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK; ++ clockctl1_predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT; ++ clockctl1_multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK; ++ clockctl1_multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT; ++ clockctl1_doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK; ++ } ++ ++ /* ++ * Clocking is derived from a fixed 40MHz input clock. ++ * cpuFreq = InputClock * MULT (where MULT is PLL multiplier) ++ * ++ * sysFreq = cpuFreq / 4 (used for APB clock, serial, ++ * flash, Timer, Watchdog Timer) ++ * ++ * cntFreq = cpuFreq / 2 (use for CPU count/compare) ++ * ++ * So, for example, with a PLL multiplier of 5, we have ++ * cpuFrez = 200MHz ++ * sysFreq = 50MHz ++ * cntFreq = 100MHz ++ * ++ * We compute the CPU frequency, based on PLL settings. ++ */ ++ if (ar531x_calculated_cpu_freq == 0) { ++ unsigned int clockCtl1 = sysRegRead(AR5312_CLOCKCTL1); ++ ++ int preDivideSelect = (clockCtl1 & clockctl1_predivide_mask) >> ++ clockctl1_predivide_shift; ++ ++ int preDivisor = CLOCKCTL1_PREDIVIDE_TABLE[preDivideSelect]; ++ ++ int multiplier = (clockCtl1 & clockctl1_multiplier_mask) >> ++ clockctl1_multiplier_shift; ++ ++ if (clockCtl1 & clockctl1_doubler_mask) { ++ multiplier = multiplier << 1; ++ } ++ ++ ar531x_calculated_cpu_freq = (40000000 / preDivisor) * multiplier; ++ } ++ ++ return ar531x_calculated_cpu_freq; ++} ++ ++unsigned int ++ar531x_sys_frequency(void) ++{ ++ static unsigned int ar531x_calculated_sys_freq = 0; ++ ++ if (ar531x_calculated_sys_freq == 0) { ++ ar531x_calculated_sys_freq = ar531x_cpu_frequency() / 4; ++ } ++ ++ return ar531x_calculated_sys_freq; ++} ++ ++static void __init ++flash_setup(void) ++{ ++ UINT32 flash_ctl; ++ ++ /* Configure flash bank 0 */ ++ flash_ctl = FLASHCTL_E | ++ FLASHCTL_AC_8M | ++ FLASHCTL_RBLE | ++ (0x01 << FLASHCTL_IDCY_S) | ++ (0x07 << FLASHCTL_WST1_S) | ++ (0x07 << FLASHCTL_WST2_S) | ++ (sysRegRead(AR531X_FLASHCTL0) & FLASHCTL_MW); ++ ++ sysRegWrite(AR531X_FLASHCTL0, flash_ctl); ++ ++ /* Disable other flash banks */ ++ sysRegWrite(AR531X_FLASHCTL1, ++ sysRegRead(AR531X_FLASHCTL1) & ~(FLASHCTL_E | FLASHCTL_AC)); ++ ++ sysRegWrite(AR531X_FLASHCTL2, ++ sysRegRead(AR531X_FLASHCTL2) & ~(FLASHCTL_E | FLASHCTL_AC)); ++} ++ ++ ++ ++void __init ++serial_setup(void) ++{ ++ struct serial_struct s; ++ ++ memset(&s, 0, sizeof(s)); ++ ++ s.flags = STD_COM_FLAGS; ++ s.io_type = SERIAL_IO_MEM; ++ s.baud_base = ar531x_sys_frequency()/16; ++ s.irq = AR531X_MISC_IRQ_UART0; ++ s.iomem_reg_shift = 2; ++ s.iomem_base = (u8 *)0xbc000003; ++ ++ if (early_serial_setup(&s) != 0) ++ printk(KERN_ERR "early_serial_setup failed\n"); ++} ++ ++extern int setup_irq(unsigned int irq, struct irqaction *irqaction); ++static void __init ++ar531x_timer_setup(struct irqaction *irq) ++{ ++ unsigned int count; ++ ++ /* Usually irq is timer_irqaction (timer_interrupt) */ ++ setup_irq(AR531X_IRQ_CPU_CLOCK, irq); ++ ++ /* to generate the first CPU timer interrupt */ ++ count = read_c0_count(); ++ write_c0_compare(count + 1000); ++} ++ ++extern void (*board_time_init)(void); ++ ++static void __init ++ar531x_time_init(void) ++{ ++ mips_hpt_frequency = ar531x_cpu_frequency() / 2; ++} ++ ++void __init ++ar531x_setup(void) ++{ ++ /* Clear any lingering AHB errors */ ++ sysRegRead(AR531X_PROCADDR); ++ sysRegRead(AR531X_DMAADDR); ++ ++ sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION); ++ ++ /* Disable data watchpoints */ ++ write_c0_watchlo0(0); ++ ++ board_time_init = ar531x_time_init; ++ board_timer_setup = ar531x_timer_setup; ++ ++ _machine_restart = ar531x_restart; ++ _machine_halt = ar531x_halt; ++ _machine_power_off = ar531x_power_off; ++ ++ flash_setup(); ++ serial_setup(); ++} +diff -urN linux-2.4.32/arch/mips/ar531x/Makefile linux-2.4.32.new/arch/mips/ar531x/Makefile +--- linux-2.4.32/arch/mips/ar531x/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/Makefile 2005-12-24 20:29:42.010325312 +0000 +@@ -0,0 +1,33 @@ ++# ++# 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++# ++ ++# Makefile for Atheros ar531x boards ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++ ++.S.s: ++ $(CPP) $(CFLAGS) $< -o $*.s ++.S.o: ++ $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o ++ ++O_TARGET:= ar531x.o ++ ++export-objs = ar531xksyms.o ++ ++obj-y := ar531xdbg_io.o \ ++ ar531xsetup.o \ ++ ar531xprom.o \ ++ ar531xirq.o \ ++ ar531xintr.o \ ++ ar531xgpio.o \ ++ ar531xksyms.o ++ ++include $(TOPDIR)/Rules.make +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/backup-busybox.links linux-2.4.32.new/arch/mips/ar531x/RAMDISK/backup-busybox.links +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/backup-busybox.links 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/backup-busybox.links 2005-12-24 20:29:42.011325160 +0000 +@@ -0,0 +1,33 @@ ++/usr/bin/[ ++/sbin/brctl ++/bin/cat ++/bin/chmod ++/bin/cp ++/bin/df ++/bin/echo ++/bin/false ++/sbin/ifconfig ++/sbin/init ++/sbin/insmod ++/bin/kill ++/bin/ls ++/sbin/lsmod ++/bin/mkdir ++/sbin/modprobe ++/bin/mount ++/bin/msh ++/bin/mv ++/bin/ping ++/bin/ps ++/bin/pwd ++/sbin/reboot ++/bin/rm ++/bin/rmdir ++/sbin/rmmod ++/sbin/route ++/bin/sh ++/usr/bin/test ++/usr/bin/top ++/bin/true ++/bin/umount ++/usr/bin/wget +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/busybox.links linux-2.4.32.new/arch/mips/ar531x/RAMDISK/busybox.links +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/busybox.links 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/busybox.links 2005-12-24 20:29:42.011325160 +0000 +@@ -0,0 +1,33 @@ ++/usr/bin/[ ++/sbin/brctl ++/bin/cat ++/bin/chmod ++/bin/cp ++/bin/df ++/bin/echo ++/bin/false ++/sbin/ifconfig ++/sbin/init ++/sbin/insmod ++/bin/kill ++/bin/ls ++/sbin/lsmod ++/bin/mkdir ++/sbin/modprobe ++/bin/mount ++/bin/msh ++/bin/mv ++/bin/ping ++/bin/ps ++/bin/pwd ++/sbin/reboot ++/bin/rm ++/bin/rmdir ++/sbin/rmmod ++/sbin/route ++/bin/sh ++/usr/bin/test ++/bin/true ++/bin/umount ++/bin/uname ++/usr/bin/wget +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/Makefile linux-2.4.32.new/arch/mips/ar531x/RAMDISK/Makefile +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/Makefile 2005-12-24 20:29:42.011325160 +0000 +@@ -0,0 +1,53 @@ ++KERNEL_SOURCE=../../../.. ++ ++# The value for INITRDSIZE is extracted from linux/.config, ++# if it exists; otherwise, a default value is used. ++ ++CONFIG_FILE = $(KERNEL_SOURCE)/.config ++ ++ifeq ($(CONFIG_FILE),$(wildcard $(CONFIG_FILE))) ++ ++include $(CONFIG_FILE) ++ifdef CONFIG_BLK_DEV_RAM_SIZE ++INITRDSIZE := $(shell echo $(CONFIG_BLK_DEV_RAM_SIZE)) ++else ++INITRDSIZE := 8192 ++endif ++ ++else ++INITRDSIZE := 8192 ++endif ++ ++MOUNTPT = /mnt/xtmp ++ ++ramdisk.gz: ramdisk ++ gzip -f ramdisk ++ ++ramdisk: ++ ./makelinks ++ @echo "CREATING RAMDISK OF SIZE $(INITRDSIZE) on $@" ++ dd if=/dev/zero of=$@ bs=1k count=$(INITRDSIZE) ++ /sbin/mke2fs -vFm0 $@ $(INITRDSIZE) ++ if [ \! -e $(MOUNTPT) ]; then mkdir -p $(MOUNTPT) ; fi ++ mount -o loop $@ $(MOUNTPT) ++ @df $(MOUNTPT) ++ (cd rootdir; tar cf - . ) | (cd $(MOUNTPT) && tar xf - ) ++ (cd $(MOUNTPT) ; chown -R root.root . ) ++ @df $(MOUNTPT) ++ umount $(MOUNTPT) ++ ++install: ++ @(if [ -d $(KERNEL_SOURCE)/arch/mips/ramdisk ]; \ ++ then \ ++ if [ -f ramdisk.gz ]; \ ++ then \ ++ cp ramdisk.gz $(KERNEL_SOURCE)/arch/mips/ramdisk/; \ ++ else \ ++ echo "No ramdisk.gz image"; \ ++ fi; \ ++ else \ ++ echo "No ramdisk directory. Check KERNEL_SOURCE variable."; \ ++ fi) ++ ++clean: ++ rm -f ramdisk.gz ramdisk +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/makelinks linux-2.4.32.new/arch/mips/ar531x/RAMDISK/makelinks +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/makelinks 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/makelinks 2005-12-24 20:29:42.012325008 +0000 +@@ -0,0 +1,65 @@ ++#!/bin/sh ++ ++if [ -f busybox.links ] ++then ++ cat busybox.links | sed 's/\//ln -s -f \/bin\/busybox rootdir\//' | /bin/sh ++fi ++ ++cons=" root tty 622" ++disk=" root disk 660" ++mtd=" root root 640" ++makedev () { # usage: makedev name [bcu] major minor owner group mode ++ if [ "$opt_v" ] ++ then if [ "$opt_d" ] ++ then echo "rm -f $1" ++ else echo "$1 = $2 $3 $4 $5:$6 $7" ++ fi ++ fi ++ [ ! "$opt_n" ] && rm -f $1 && ++ [ ! "$opt_d" ] && mknod $1 $2 $3 $4 && ++ chown $5:$6 $1 && ++ chmod $7 $1 ++} ++ ++makedev rootdir/dev/console c 5 1 $cons ++makedev rootdir/dev/ram b 1 1 $disk ++makedev rootdir/dev/ram0 b 1 0 $disk ++makedev rootdir/dev/ram1 b 1 1 $disk ++makedev rootdir/dev/ram2 b 1 2 $disk ++makedev rootdir/dev/ram3 b 1 3 $disk ++makedev rootdir/dev/ram4 b 1 4 $disk ++makedev rootdir/dev/ram5 b 1 5 $disk ++makedev rootdir/dev/ram6 b 1 6 $disk ++makedev rootdir/dev/ram7 b 1 7 $disk ++makedev rootdir/dev/ram8 b 1 8 $disk ++makedev rootdir/dev/ram9 b 1 9 $disk ++makedev rootdir/dev/ram10 b 1 10 $disk ++makedev rootdir/dev/ram11 b 1 11 $disk ++makedev rootdir/dev/ram12 b 1 12 $disk ++makedev rootdir/dev/ram13 b 1 13 $disk ++makedev rootdir/dev/ram14 b 1 14 $disk ++makedev rootdir/dev/ram15 b 1 15 $disk ++ ++makedev rootdir/dev/mtd0 c 90 0 $mtd ++makedev rootdir/dev/mtd1 c 90 2 $mtd ++makedev rootdir/dev/mtd2 c 90 4 $mtd ++makedev rootdir/dev/mtd3 c 90 6 $mtd ++makedev rootdir/dev/mtd4 c 90 8 $mtd ++makedev rootdir/dev/mtd5 c 90 10 $mtd ++makedev rootdir/dev/mtd6 c 90 12 $mtd ++makedev rootdir/dev/mtdblock0 b 31 0 $mtd ++makedev rootdir/dev/mtdblock1 b 31 1 $mtd ++makedev rootdir/dev/mtdblock2 b 31 2 $mtd ++makedev rootdir/dev/mtdblock3 b 31 3 $mtd ++makedev rootdir/dev/mtdblock4 b 31 4 $mtd ++makedev rootdir/dev/mtdblock5 b 31 5 $mtd ++makedev rootdir/dev/mtdblock6 b 31 6 $mtd ++makedev rootdir/dev/mtdr0 c 90 1 $mtd ++makedev rootdir/dev/mtdr1 c 90 3 $mtd ++makedev rootdir/dev/mtdr2 c 90 5 $mtd ++makedev rootdir/dev/mtdr3 c 90 7 $mtd ++makedev rootdir/dev/mtdr4 c 90 9 $mtd ++makedev rootdir/dev/mtdr5 c 90 11 $mtd ++makedev rootdir/dev/mtdr6 c 90 13 $mtd ++ ++cd rootdir/dev;ln -sf ram1 ram +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/README linux-2.4.32.new/arch/mips/ar531x/RAMDISK/README +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/README 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/README 2005-12-24 20:29:42.011325160 +0000 +@@ -0,0 +1,40 @@ ++How to build a ramdisk image for use as a root filesystem with AR531X ++ ++Overview: ++In order to boot from a ramdisk root file system image, you will ++first create a root directory structure in the "rootdir" directory. ++Then run "make" to create a compressed root file system image in ++ramdisk.gz. Finally, copy this image into your kernel source tree ++and remake the kernel. The ramdisk image is then built into the ++kernel. When the kernel starts, it is uncompressed into RAM, and ++used as a root file system. ++ ++If you'd like to use a pre-built ramdisk.gz rather than build ++one yourself: ++ cp arch/mips/ar531x/RAMDISK/ramdisk.gz arch/mips/ramdisk/ramdisk.gz ++ ++Here are the detailed steps to build your own: ++ ++1) Modify Makefile to point KERNEL_SOURCE at your linux source tree. ++ ++2) Copy whatever additional files/directories/links you'd like to ++ under rootdir. Note that you're limited to CONFIG_BLK_DEV_RAM_SIZE ++ 1KB blocks, as specified in your linux/.config file. ++ Examples: ++ Copy busybox to rootdir/bin/ ++ [NOTE: Copy busybox.links to this directory to ++ cause the makelinks script to automatically ++ set up all of the necessary busybox command links ++ in the rootdir/bin directory]. ++ ++ Copy any wireless driver modules into rootdir tree ++ ++ You might want to make a copy of the rootdir directory ++ before you modify it, just in case you want to get back ++ to the original. ++ ++3) LOGIN AS ROOT (e.g. "su") and type "make" ++ ++4) Copy the resulting ramdisk.gz to your linux source tree under ++ arch/mips/ramdisk/ramdisk.gz ++ (or "make install" will do this step for you) +Binary files linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/bin/busybox and linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/bin/busybox differ +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/fstab linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/fstab +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/fstab 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/fstab 2005-12-24 20:29:42.063317256 +0000 +@@ -0,0 +1 @@ ++/proc /proc proc defaults 0 0 +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/group linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/group +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/group 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/group 2005-12-24 20:29:42.064317104 +0000 +@@ -0,0 +1,18 @@ ++root:x:0: ++wheel:x:10: ++bin:x:1:bin,daemon ++daemon:x:2:bin,daemon ++sys:x:3:bin,adm ++adm:x:4:adm,daemon ++tty:x:5: ++disk:x:6: ++lp:x:7:daemon,lp ++mem:x:8: ++kmem:x:9: ++operator:x:11: ++uucp:x:14:uucp ++dip:x:40: ++utmp:x:45: ++www:x:63: ++nobody:x:65534: ++users:x:100: +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/host.conf linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/host.conf +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/host.conf 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/host.conf 2005-12-24 20:29:42.064317104 +0000 +@@ -0,0 +1,2 @@ ++order hosts,bind ++multi on +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/inittab linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/inittab +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/inittab 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/inittab 2005-12-24 20:29:42.064317104 +0000 +@@ -0,0 +1,2 @@ ++::sysinit:/etc/rc.d/rcS ++::respawn:/bin/sh +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/nsswitch.conf linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/nsswitch.conf +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/nsswitch.conf 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/nsswitch.conf 2005-12-24 20:29:42.065316952 +0000 +@@ -0,0 +1,16 @@ ++# /etc/nsswitch.conf ++# ++# Name Service Switch configuration file. ++# ++ ++passwd: compat ++shadow: compat ++group: compat ++ ++hosts: files dns ++networks: files dns ++ ++ethers: files ++protocols: files ++rpc: files ++services: files +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/passwd linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/passwd +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/passwd 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/passwd 2005-12-24 20:29:42.065316952 +0000 +@@ -0,0 +1,11 @@ ++root:x:0:0:root:/root:/bin/ash ++bin:x:1:1:bin:/bin:/bin/sh ++daemon:x:2:2:daemon:/usr/sbin:/bin/sh ++adm:x:3:4:adm:/adm:/bin/sh ++lp:x:4:7:lp:/var/spool/lpd:/bin/sh ++sync:x:5:0:sync:/bin:/bin/sync ++shutdown:x:6:11:shutdown:/sbin:/sbin/shutdown ++halt:x:7:0:halt:/sbin:/sbin/halt ++uucp:x:10:14:uucp:/var/spool/uucp:/bin/sh ++operator:x:11:0:Operator:/var:/bin/sh ++nobody:x:65534:65534:nobody:/home:/bin/sh +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/rc.d/rcS linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/rc.d/rcS +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/rc.d/rcS 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/rc.d/rcS 2005-12-24 20:29:42.066316800 +0000 +@@ -0,0 +1,17 @@ ++#!/bin/sh ++ ++mount -a ++mount -t jffs2 -o remount +w / ++# mount -t ramfs /dev/ram /ramdisk ++ ++echo Load MADWiFi wlan module ++insmod ../../lib/modules/2.4.25/net/wlan.o ++ ++echo Load MADWiFi Atheros HAL module ++insmod ../../lib/modules/2.4.25/net/ath_hal.o ++ ++echo Load MADWiFi Atheros Driver module ++insmod ../../lib/modules/2.4.25/net/ath_lbus.o ++ ++exit ++ +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/resolv.conf linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/resolv.conf +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/resolv.conf 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/resolv.conf 2005-12-24 20:29:42.066316800 +0000 +@@ -0,0 +1,18 @@ ++# /etc/resolv.conf - DNS setup file ++# ++# possible entries are: ++# ++# domain Local domain name. If not present, the ++# gethostbyname syscall is used to ++# determine the local domain name. ++# ++# search Search list for hostname lookup. ++# The search list is normally determined ++# from the local domain name but it ++# can be set to a list of domains. ++# ++# nameserver Define which server to contact ++# for DNS lookups. If there are ++# multiple nameserver lines (Max=3), ++# they are queried in the listed order. ++# +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/securetty linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/securetty +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/securetty 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/securetty 2005-12-24 20:29:42.066316800 +0000 +@@ -0,0 +1,12 @@ ++tty1 ++tty2 ++tty3 ++tty4 ++tty5 ++tty6 ++tty7 ++tty8 ++ttyS0 ++ttyS1 ++ttyS2 ++ttyS3 +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/services linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/services +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/services 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/services 2005-12-24 20:29:42.066316800 +0000 +@@ -0,0 +1,193 @@ ++# $NetBSD: services,v 1.18 1996/03/26 00:07:58 mrg Exp $ ++# ++# Network services, Internet style ++# ++# Note that it is presently the policy of IANA to assign a single well-known ++# port number for both TCP and UDP; hence, most entries here have two entries ++# even if the protocol doesn't support UDP operations. ++# Updated from RFC 1340, ``Assigned Numbers'' (July 1992). Not all ports ++# are included, only the more common ones. ++# ++# from: @(#)services 5.8 (Berkeley) 5/9/91 ++# ++tcpmux 1/tcp # TCP port service multiplexer ++echo 7/tcp ++echo 7/udp ++discard 9/tcp sink null ++discard 9/udp sink null ++systat 11/tcp users ++daytime 13/tcp ++daytime 13/udp ++netstat 15/tcp ++qotd 17/tcp quote ++msp 18/tcp # message send protocol ++msp 18/udp # message send protocol ++chargen 19/tcp ttytst source ++chargen 19/udp ttytst source ++ftp-data 20/tcp # default ftp data port ++ftp 21/tcp ++ssh 22/tcp ++ssh 22/udp ++telnet 23/tcp ++# 24 - private ++smtp 25/tcp mail ++# 26 - unassigned ++time 37/tcp timserver ++time 37/udp timserver ++rlp 39/udp resource # resource location ++nameserver 42/tcp name # IEN 116 ++whois 43/tcp nicname ++domain 53/tcp nameserver # name-domain server ++domain 53/udp nameserver ++mtp 57/tcp # deprecated ++bootps 67/tcp # BOOTP server ++bootps 67/udp ++bootpc 68/tcp # BOOTP client ++bootpc 68/udp ++tftp 69/udp ++gopher 70/tcp # Internet Gopher ++gopher 70/udp ++rje 77/tcp netrjs ++finger 79/tcp ++www 80/tcp http # WorldWideWeb HTTP ++www 80/udp # HyperText Transfer Protocol ++link 87/tcp ttylink ++kerberos 88/tcp krb5 # Kerberos v5 ++kerberos 88/udp ++supdup 95/tcp ++# 100 - reserved ++hostnames 101/tcp hostname # usually from sri-nic ++iso-tsap 102/tcp tsap # part of ISODE. ++csnet-ns 105/tcp cso-ns # also used by CSO name server ++csnet-ns 105/udp cso-ns ++rtelnet 107/tcp # Remote Telnet ++rtelnet 107/udp ++pop2 109/tcp pop-2 postoffice # POP version 2 ++pop2 109/udp ++pop3 110/tcp pop-3 # POP version 3 ++pop3 110/udp ++sunrpc 111/tcp ++sunrpc 111/udp ++auth 113/tcp authentication tap ident ++sftp 115/tcp ++uucp-path 117/tcp ++nntp 119/tcp readnews untp # USENET News Transfer Protocol ++ntp 123/tcp ++ntp 123/udp # Network Time Protocol ++netbios-ns 137/tcp # NETBIOS Name Service ++netbios-ns 137/udp ++netbios-dgm 138/tcp # NETBIOS Datagram Service ++netbios-dgm 138/udp ++netbios-ssn 139/tcp # NETBIOS session service ++netbios-ssn 139/udp ++imap2 143/tcp imap # Interim Mail Access Proto v2 ++imap2 143/udp ++snmp 161/udp # Simple Net Mgmt Proto ++snmp-trap 162/udp snmptrap # Traps for SNMP ++cmip-man 163/tcp # ISO mgmt over IP (CMOT) ++cmip-man 163/udp ++cmip-agent 164/tcp ++cmip-agent 164/udp ++xdmcp 177/tcp # X Display Mgr. Control Proto ++xdmcp 177/udp ++nextstep 178/tcp NeXTStep NextStep # NeXTStep window ++nextstep 178/udp NeXTStep NextStep # server ++bgp 179/tcp # Border Gateway Proto. ++bgp 179/udp ++prospero 191/tcp # Cliff Neuman's Prospero ++prospero 191/udp ++irc 194/tcp # Internet Relay Chat ++irc 194/udp ++smux 199/tcp # SNMP Unix Multiplexer ++smux 199/udp ++at-rtmp 201/tcp # AppleTalk routing ++at-rtmp 201/udp ++at-nbp 202/tcp # AppleTalk name binding ++at-nbp 202/udp ++at-echo 204/tcp # AppleTalk echo ++at-echo 204/udp ++at-zis 206/tcp # AppleTalk zone information ++at-zis 206/udp ++z3950 210/tcp wais # NISO Z39.50 database ++z3950 210/udp wais ++ipx 213/tcp # IPX ++ipx 213/udp ++imap3 220/tcp # Interactive Mail Access ++imap3 220/udp # Protocol v3 ++ulistserv 372/tcp # UNIX Listserv ++ulistserv 372/udp ++# ++# UNIX specific services ++# ++exec 512/tcp ++biff 512/udp comsat ++login 513/tcp ++who 513/udp whod ++shell 514/tcp cmd # no passwords used ++syslog 514/udp ++printer 515/tcp spooler # line printer spooler ++talk 517/udp ++ntalk 518/udp ++route 520/udp router routed # RIP ++timed 525/udp timeserver ++tempo 526/tcp newdate ++courier 530/tcp rpc ++conference 531/tcp chat ++netnews 532/tcp readnews ++netwall 533/udp # -for emergency broadcasts ++uucp 540/tcp uucpd # uucp daemon ++remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem ++# ++webster 765/tcp # Network dictionary ++webster 765/udp ++# temporary entry (not officially registered by the Samba Team!) ++swat 901/tcp # Samba Web Administration Tool ++# ++# From ``Assigned Numbers'': ++# ++#> The Registered Ports are not controlled by the IANA and on most systems ++#> can be used by ordinary user processes or programs executed by ordinary ++#> users. ++# ++#> Ports are used in the TCP [45,106] to name the ends of logical ++#> connections which carry long term conversations. For the purpose of ++#> providing services to unknown callers, a service contact port is ++#> defined. This list specifies the port used by the server process as its ++#> contact port. While the IANA can not control uses of these ports it ++#> does register or list uses of these ports as a convienence to the ++#> community. ++# ++ingreslock 1524/tcp ++ingreslock 1524/udp ++prospero-np 1525/tcp # Prospero non-privileged ++prospero-np 1525/udp ++rfe 5002/tcp # Radio Free Ethernet ++rfe 5002/udp # Actually uses UDP only ++# ++# ++# Kerberos (Project Athena/MIT) services ++# Note that these are for Kerberos v4, and are unofficial. ++# ++klogin 543/tcp # Kerberos `rlogin' ++kshell 544/tcp krcmd # Kerberos `rsh' ++kerberos-adm 749/tcp # Kerberos `kadmin' (v5) ++kerberos4 750/udp kdc # Kerberos (server) udp ++kerberos4 750/tcp kdc # Kerberos (server) tcp ++kerberos-master 751/udp # Kerberos admin server udp ++kerberos-master 751/tcp # Kerberos admin server tcp ++krbupdate 760/tcp kreg # BSD Kerberos registration ++kpasswd 761/tcp kpwd # BSD Kerberos `passwd' ++eklogin 2105/tcp # Kerberos encrypted `rlogin' ++# ++# Unofficial but necessary (for NetBSD) services ++# ++supfilesrv 871/tcp # SUP server ++supfiledbg 1127/tcp # SUP debugging ++# ++# AppleTalk DDP entries (DDP: Datagram Delivery Protocol) ++# ++rtmp 1/ddp # Routing Table Maintenance Protocol ++nbp 2/ddp # Name Binding Protocol ++echo 4/ddp # AppleTalk Echo Protocol ++zip 6/ddp # Zone Information Protocol ++ +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/shadow linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/shadow +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/etc/shadow 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/etc/shadow 2005-12-24 20:29:42.067316648 +0000 +@@ -0,0 +1,11 @@ ++root::10933:0:99999:7::: ++bin:*:10933:0:99999:7::: ++daemon:*:10933:0:99999:7::: ++adm:*:10933:0:99999:7::: ++lp:*:10933:0:99999:7::: ++sync:*:10933:0:99999:7::: ++shutdown:*:10933:0:99999:7::: ++halt:*:10933:0:99999:7::: ++uucp:*:10933:0:99999:7::: ++operator:*:10933:0:99999:7::: ++nobody:*:10933:0:99999:7::: +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.generic_string linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.generic_string +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.generic_string 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.generic_string 2005-12-24 20:29:42.071316040 +0000 +@@ -0,0 +1 @@ ++# module id=string +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.ieee1394map linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.ieee1394map +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.ieee1394map 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.ieee1394map 2005-12-24 20:29:42.071316040 +0000 +@@ -0,0 +1 @@ ++# ieee1394 module match_flags vendor_id model_id specifier_id version +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.isapnpmap linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.isapnpmap +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.isapnpmap 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.isapnpmap 2005-12-24 20:29:42.079314824 +0000 +@@ -0,0 +1 @@ ++# isapnp module cardvendor carddevice driver_data vendor function ... +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.parportmap linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.parportmap +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.parportmap 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.parportmap 2005-12-24 20:29:42.079314824 +0000 +@@ -0,0 +1 @@ ++# module pattern +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pcimap linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pcimap +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pcimap 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pcimap 2005-12-24 20:29:42.080314672 +0000 +@@ -0,0 +1 @@ ++# pci module vendor device subvendor subdevice class class_mask driver_data +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pnpbiosmap linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pnpbiosmap +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pnpbiosmap 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.pnpbiosmap 2005-12-24 20:29:42.080314672 +0000 +@@ -0,0 +1 @@ ++# module id +diff -urN linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.usbmap linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.usbmap +--- linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.usbmap 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/lib/modules/2.4.25/modules.usbmap 2005-12-24 20:29:42.080314672 +0000 +@@ -0,0 +1 @@ ++# usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info +Binary files linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/sbin/iwconfig and linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/sbin/iwconfig differ +Binary files linux-2.4.32/arch/mips/ar531x/RAMDISK/rootdir/sbin/iwpriv and linux-2.4.32.new/arch/mips/ar531x/RAMDISK/rootdir/sbin/iwpriv differ +diff -urN linux-2.4.32/arch/mips/ar531x/README linux-2.4.32.new/arch/mips/ar531x/README +--- linux-2.4.32/arch/mips/ar531x/README 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/README 2005-12-24 20:29:42.101311480 +0000 +@@ -0,0 +1,68 @@ ++Basic information for the AR531X Board Support Package ++ ++This directory contains the "LBSP" -- Linux Board Support Package -- ++for Linux on the Atheros AR531X Wireless System-On-a-Chip. It is intended ++primarily as a building block for wireless products. At this time, the ++AR531X Linux BSP is experimental code, and is actively UNDER CONSTRUCTION. ++ ++Some components that are supported by this LBSP along with a standard 2.4 ++Linux MIPS kernel include ++ R4Kc CPU ++ instruction and data caches ++ SDRAM ++ flash (Macronix, AMD, STS, etc.) ++ 16550 serial port ++ ethernet MACs ++ ethernet PHY or PHY Switch (RealTek, Kendin, Marvell) ++ General-Purpose I/O pins ++ kernel debugging with kgdb ++ ++This LBSP code does NOT include drivers for the wireless components of the ++chip/boards! Drivers for those components may be distributed separately. ++In particular, the MADWiFi project under SourceForge supports (not yet!) ++wireless functions on the AR531X chipset. See ++ http://www.sourceforge.net/projects/madwifi ++ ++Files included in this BSP: ++ae531xlnx.c - Linux-specific portions of the ethernet driver ++ae531xmac.c - OS-independent AR531X ethernet MAC code ++ae531xmac.h - OS-independent AR531X ethernet MAC software definitions ++ae531xreg.h - OS-independent AR531X ethernet MAC hardware definitions ++ar531x.h - OS-independent AR531X system hardware definitions ++ar531xlnx.h - Linux-specific AR531X system definitions and externs ++defconfig-ar531x - Default Linux configuration file ++intr_recv.S - Linux interrupt "glue" code ++ar531xirq.c - Linux Interrupt Request management ++Makefile - Linux makefile ++mvPhy.c - OS-independent ethernet PHY code for Marvell Switch ++mvPhy.h - OS-independent ethernet PHY definitions for Marvell Switch ++ar531xprom.c - Linux prom "glue" code ++ar531xsetup.c - Linux startup code ++ar531xdbg_io.c - Support for kgdb-based debugging and for EARLY_PRINTK_HACK ++ar531xproc.c - Pseudo-device driver for /proc/ar531x device ++ar531xgpio.c - Support for General Purpose I/O pins ++ar531xwmacsl.c - Wireless MAC Support Layer ++ ++Additional files, distributed with the BSP: ++README - This file ++README.BUILD - Instructions for building a linux kernel from source ++README.EXECUTE - Instructions for testing your linux kernel ++README.RAMDISK - Instructions for building a root ramdisk image ++ ++ramdisk.gz - A binary ramdisk image, suitable for use with AR531X. ++DIFFS - Directory that contains "patch" files (See README.BUILD) ++ ++ ++There are several ways to boot a vmlinux image on an AR531X board: ++ -You can boot in over ethernet from the vxWorks bootrom, which is preloaded ++ on all Atheros boards ++ -You can use an ICE (e.g. VisionICE) to load the vmlinux image. You will ++ need appropriate register initialization (e.g. AP30.ini file) ++ -You can use the eCos RedBoot bootrom loader. This is a full-featured ++ bootrom which as been ported to AR531x. It can boot vmlinux over ethernet ++ or from flash. Source code is available from Atheros. ++ ++Please send comments, corrections, complaints, criticisms, suggestions, ++enhancements, requests, or any other reasonable communications regarding ++this effort, to "linux@atheros.com". Your email will be received by a ++couple of engineers, and redirected as appropriate. +diff -urN linux-2.4.32/arch/mips/ar531x/README.BUILD linux-2.4.32.new/arch/mips/ar531x/README.BUILD +--- linux-2.4.32/arch/mips/ar531x/README.BUILD 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/README.BUILD 2005-12-24 20:29:42.101311480 +0000 +@@ -0,0 +1,47 @@ ++ How to BUILD a linux kernel for an AR531X system ++ ++It is expected that you will build Linux on an existing Linux system, which ++has all of the standard Linux tools. ++ ++01) Obtain a MIPS BigEndian ELF gcc-compatible toolchain. For example, ++ if you're cross-compiling on a x86 Linux system, you could use: ++ ftp://ftp.mips.com/pub/tools/software/sde-for-linux/sdelinux-5.01-4eb.i386.rpm ++ ++02) Obtain the latest working MIPS Linux kernel ++ cvs -d :pserver:cvs@ftp.linux-mips.org:/home/cvs login (password "cvs") ++ cvs -d :pserver:cvs@ftp.linux-mips.org:/home/cvs co -r linux_2_4 linux ++ ++ Now "cd linux". The remainder of these instructions assume ++ that you are in the linux directory. ++ ++03) Place the contents of this directory at arch/mips/ar531x. ++ ++04) Use the patch command to patch generic linux files according ++ to the DIFFS directory ++ for i in arch/mips/ar531x/DIFFS/*.diff ++ do ++ patch -p1 < $i ++ done ++ NOTE: This version of the AR531X Linux BSP was tested with ++ MIPS Linux 2.4.22 as of 11/14/03. If you use a different ++ (e.g. more recent) version of Linux source, you may need to ++ resolve some minor patch and compilation issues. ++ ++05) Set up a RAMDISK image. ++ See the instructions in README.RAMDISK. ++ ++06) Set up a linux configuration using ar531x/defconfig-ar531x. ++ cp arch/mips/ar531x/defconfig-ar531x .config ++ make oldconfig (answer all questions that are asked) ++ NOTE: For development/debug purposes, you may want to ++ enable CONFIG_RUNTIME_DEBUG and CONFIG_KGDB. ++ ++07) Make dependencies. ++ make dep ++ ++08) Build the linux kernel ++ make ++ ++09) The linux image you just built is in vmlinux. ++ See instructions in README.EXECUTE to run your vmlinux ++ image on an AP531X-based board. +diff -urN linux-2.4.32/arch/mips/ar531x/README.EXECUTE linux-2.4.32.new/arch/mips/ar531x/README.EXECUTE +--- linux-2.4.32/arch/mips/ar531x/README.EXECUTE 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/README.EXECUTE 2005-12-24 20:29:42.101311480 +0000 +@@ -0,0 +1,23 @@ ++ How to EXECUTE a linux image on an AR531X system ++ ++There are currently three ways to run you vmlinux image: ++ 1) Load it using the vxWorks bootrom that is supplied with the board. ++ You can load it over ethernet or from the TFFS file system, if you ++ have sufficient flash to store the image. ++ 2) Load it using an ICE (e.g. VisionICE). ++ 3) Use a bootrom loader, such as eCos RedBoot. ++ ++After you have booted linux: ++ By default, the root filesystem on ramdisk is read-only. ++ To make it writable, use "mount -o remount w /". ++ ++ The user-level commands are slightly non-standard, as they ++ are based on "busybox". ++ ++ The "wget" command is included. You can use wget to fetch ++ files from any ftp server. So, for instance, you can fetch ++ a kernel module and then "insmod" it. ++ ++Note that the standard source-level kernel debugger, kgdb, works well ++over the serial line with this port. We use kgdb and the kgdb_demux perl ++script -- available over the www -- for debugging. +diff -urN linux-2.4.32/arch/mips/ar531x/README.VERSION linux-2.4.32.new/arch/mips/ar531x/README.VERSION +--- linux-2.4.32/arch/mips/ar531x/README.VERSION 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/arch/mips/ar531x/README.VERSION 2005-12-24 20:29:42.101311480 +0000 +@@ -0,0 +1 @@ ++Source release last modified: 12/16/03 +diff -urN linux-2.4.32/arch/mips/config-shared.in linux-2.4.32.new/arch/mips/config-shared.in +--- linux-2.4.32/arch/mips/config-shared.in 2005-12-24 16:11:21.000000000 +0000 ++++ linux-2.4.32.new/arch/mips/config-shared.in 2005-12-24 21:33:42.804435856 +0000 +@@ -31,6 +31,7 @@ + dep_bool 'Support for Alchemy PB1000 board' CONFIG_MIPS_PB1000 $CONFIG_MIPS32 + dep_bool 'Support for Alchemy PB1100 board' CONFIG_MIPS_PB1100 $CONFIG_MIPS32 + dep_bool 'Support for Alchemy PB1500 board' CONFIG_MIPS_PB1500 $CONFIG_MIPS32 ++dep_bool 'Support for Atheros AR5312/AR2312 WiSoC (EXPERIMENTAL)' CONFIG_AR531X $CONFIG_AR531X $CONFIG_EXPERIMENTAL + dep_bool 'Support for Alchemy PB1550 board' CONFIG_MIPS_PB1550 $CONFIG_MIPS32 + dep_bool 'Support for Alchemy PB1200 board' CONFIG_MIPS_PB1200 $CONFIG_MIPS32 + dep_bool 'Support for Alchemy Hydrogen3 board' CONFIG_MIPS_HYDROGEN3 $CONFIG_MIPS32 +@@ -196,7 +197,7 @@ + bool ' Support for ZBbus profiling' CONFIG_SIBYTE_TBPROF + + if [ "$CONFIG_SIBYTE_SWARM" = "y" -o \ +- "$CONFIG_SIBYTE_LITTLESUR" = "y" -o \ ++O5B "$CONFIG_SIBYTE_LITTLESUR" = "y" -o \ + "$CONFIG_SIBYTE_PTSWARM" = "y" -o \ + "$CONFIG_SIBYTE_CARMEL" = "y" ]; then + define_bool CONFIG_SIBYTE_GENBUS_IDE y +@@ -239,6 +240,43 @@ + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PC_KEYB y + fi ++if [ "$CONFIG_AR531X" = "y" ]; then ++ define_bool CONFIG_IRQ_CPU y ++ define_bool CONFIG_CPU_VR4100 y ++ define_bool CONFIG_SERIAL y ++ define_bool CONFIG_NEW_IRQ y ++ define_bool CONFIG_NEW_TIME_C y ++ define_bool CONFIG_AR5312 ++ define_bool CONFIG_NONCOHERENT_IO y ++ bool 'Enable early printk hack' CONFIG_EARLY_PRINTK_HACK ++ define_bool CONFIG_SCSI n ++ mainmenu_option next_comment ++ comment 'Board selection' ++ choice 'Board type' \ ++ "UNKNOWN CONFIG_APUNKNOWN \ ++ AP30 CONFIG_AP30 \ ++ AP31 CONFIG_AP31 \ ++ AP33 CONFIG_AP33 \ ++ AP38 CONFIG_AP38 \ ++ AP43 CONFIG_AP43 \ ++ AP48 CONFIG_AP48" AP30 ++ if [ "$CONFIG_AP30" = "y" ]; then ++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 2 ++ fi ++ if [ "$CONFIG_AP33" = "y" ]; then ++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 ++ fi ++ if [ "$CONFIG_AP38" = "y" ]; then ++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 ++ fi ++ if [ "$CONFIG_AP43" = "y" ]; then ++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 ++ fi ++ if [ "$CONFIG_AP48" = "y" ]; then ++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 ++ fi ++ endmenu ++fi + if [ "$CONFIG_CASIO_E55" = "y" ]; then + define_bool CONFIG_IRQ_CPU y + define_bool CONFIG_NONCOHERENT_IO y +diff -urN linux-2.4.32/arch/mips/kernel/setup.c linux-2.4.32.new/arch/mips/kernel/setup.c +--- linux-2.4.32/arch/mips/kernel/setup.c 2005-12-24 16:08:53.000000000 +0000 ++++ linux-2.4.32.new/arch/mips/kernel/setup.c 2005-12-24 21:28:51.779678344 +0000 +@@ -494,6 +494,7 @@ + void hp_setup(void); + void au1x00_setup(void); + void frame_info_init(void); ++ void ar531x_setup(void); + + frame_info_init(); + #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE) +@@ -691,6 +692,12 @@ + pmc_yosemite_setup(); + break; + #endif ++ ++#ifdef CONFIG_AR531X ++ case MACH_GROUP_AR531X: ++ ar531x_setup(); ++ break; ++#endif + default: + panic("Unsupported architecture"); + } +diff -urN linux-2.4.32/arch/mips/Makefile linux-2.4.32.new/arch/mips/Makefile +--- linux-2.4.32/arch/mips/Makefile 2005-12-24 16:09:51.000000000 +0000 ++++ linux-2.4.32.new/arch/mips/Makefile 2005-12-24 21:28:51.780678192 +0000 +@@ -725,6 +725,12 @@ + LOADADDR += 0x80020000 + endif + ++ifdef CONFIG_AR531X ++SUBDIRS += arch/mips/ar531x ++LIBS += arch/mips/ar531x/ar531x.o ++LOADADDR += 0x80002000 ++endif ++ + # + # Choosing incompatible machines durings configuration will result in + # error messages during linking. Select a default linkscript if +diff -urN linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.4.32.new/drivers/mtd/chips/cfi_cmdset_0002.c +--- linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0002.c 2004-11-17 11:54:21.000000000 +0000 ++++ linux-2.4.32.new/drivers/mtd/chips/cfi_cmdset_0002.c 2005-12-24 21:28:51.795675912 +0000 +@@ -510,7 +510,7 @@ + or tells us why it failed. */ + dq6 = CMD(1<<6); + dq5 = CMD(1<<5); +- timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */ ++ timeo = jiffies + (HZ/1000) + 1; /* setting timeout to 1ms for now */ + + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); +@@ -535,12 +535,14 @@ + if( (status & dq5) == dq5 ) { + /* When DQ5 raises, we must check once again + if DQ6 is toggling. If not, the erase has been +- completed OK. If not, reset chip. */ ++ completed OK. But if so, reset chip. */ + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + + if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) { ++#if 0 + printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" ); ++#endif + } else { + /* DQ5 is active so we can do a reset and stop the erase */ + cfi_write(map, CMD(0xF0), chip->start); +diff -urN linux-2.4.32/drivers/mtd/chips/jedec_probe.c linux-2.4.32.new/drivers/mtd/chips/jedec_probe.c +--- linux-2.4.32/drivers/mtd/chips/jedec_probe.c 2003-06-13 15:51:34.000000000 +0100 ++++ linux-2.4.32.new/drivers/mtd/chips/jedec_probe.c 2005-12-24 21:28:51.797675608 +0000 +@@ -900,7 +900,16 @@ + NumEraseRegions: 1, + regions: {ERASEINFO(0x01000,256), + } +- } ++ }, { ++ mfr_id: MANUFACTURER_SST, ++ dev_id: SST39LF160, ++ name: "SST 39LF160", ++ DevSize: SIZE_2MiB, ++ CmdSet: P_ID_AMD_STD, ++ NumEraseRegions: 1, ++ regions: {ERASEINFO(0x01000,512), ++ } ++ } + }; + + +diff -urN linux-2.4.32/drivers/mtd/Config.in linux-2.4.32.new/drivers/mtd/Config.in +--- linux-2.4.32/drivers/mtd/Config.in 2003-06-13 15:51:34.000000000 +0100 ++++ linux-2.4.32.new/drivers/mtd/Config.in 2005-12-24 21:28:51.803674696 +0000 +@@ -14,6 +14,9 @@ + dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD + dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD + dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS ++ if [ "$CONFIG_MTD_END_RESERVED" != "" ]; then ++ define_int CONFIG_MTD_END_RESERVED $CONFIG_MTD_END_RESERVED ++ fi + dep_tristate ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS + if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS +diff -urN linux-2.4.32/drivers/mtd/maps/physmap.c linux-2.4.32.new/drivers/mtd/maps/physmap.c +--- linux-2.4.32/drivers/mtd/maps/physmap.c 2003-06-13 15:51:34.000000000 +0100 ++++ linux-2.4.32.new/drivers/mtd/maps/physmap.c 2005-12-24 21:28:51.811673480 +0000 +@@ -80,12 +80,18 @@ + }; + + #ifdef CONFIG_MTD_PARTITIONS +-#ifdef CONFIG_MTD_CMDLINE_PARTS ++#if defined(CONFIG_MTD_CMDLINE_PARTS) || defined(CONFIG_MTD_REDBOOT_PARTS) + static struct mtd_partition *mtd_parts = 0; + static int mtd_parts_nb = 0; + #else + static struct mtd_partition physmap_partitions[] = { + /* Put your own partition definitions here */ ++ { ++ name: "rootfs", ++ size: 0x000e0000, ++ offset: 0x000f0000, ++ /* Allow file system to be mounted for writing */ ++ } + #if 0 + { + name: "bootROM", +@@ -138,6 +144,22 @@ + + add_mtd_device(mymtd); + #ifdef CONFIG_MTD_PARTITIONS ++#ifdef CONFIG_MTD_REDBOOT_PARTS ++ { ++ extern int parse_redboot_partitions(struct mtd_info *master, ++ struct mtd_partition **pparts); ++ ++ struct mtd_partition *rb_parts = 0; ++ int rb_parts_nb = 0; ++ ++ rb_parts_nb = parse_redboot_partitions(mymtd, &rb_parts); ++ if (rb_parts_nb > 0) { ++ printk(KERN_NOTICE ++ "Using redboot flash partitioning"); ++ add_mtd_partitions (mymtd, rb_parts, rb_parts_nb); ++ } ++ } ++#endif + #ifdef CONFIG_MTD_CMDLINE_PARTS + mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, + "phys"); +@@ -147,7 +169,8 @@ + "Using command line partition definition\n"); + add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); + } +-#else ++#endif ++#if !defined(CONFIG_MTD_CMDLINE_PARTS) && !defined(CONFIG_MTD_REDBOOT_PARTS) + if (NUM_PARTITIONS != 0) + { + printk(KERN_NOTICE +diff -urN linux-2.4.32/drivers/mtd/redboot.c linux-2.4.32.new/drivers/mtd/redboot.c +--- linux-2.4.32/drivers/mtd/redboot.c 2001-11-09 22:01:22.000000000 +0000 ++++ linux-2.4.32.new/drivers/mtd/redboot.c 2005-12-24 21:28:51.821671960 +0000 +@@ -51,8 +51,14 @@ + return -ENOMEM; + + /* Read the start of the last erase block */ +- ret = master->read(master, master->size - master->erasesize, ++ { ++ u_int32_t part_table_start = master->size - master->erasesize; ++#if defined(CONFIG_MTD_END_RESERVED) ++ part_table_start -= CONFIG_MTD_END_RESERVED; ++#endif ++ ret = master->read(master, part_table_start, + PAGE_SIZE, &retlen, (void *)buf); ++ } + + if (ret) + goto out; +diff -urN linux-2.4.32/drivers/net/Config.in linux-2.4.32.new/drivers/net/Config.in +--- linux-2.4.32/drivers/net/Config.in 2005-12-24 16:16:53.000000000 +0000 ++++ linux-2.4.32.new/drivers/net/Config.in 2005-12-24 21:28:51.856666640 +0000 +@@ -30,6 +30,8 @@ + comment 'Ethernet (10 or 100Mbit)' + bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET + if [ "$CONFIG_NET_ETHERNET" = "y" ]; then ++ define_bool CONFIG_VENETDEV n ++ define_bool CONFIG_MARVELL_ENET_PHY y + if [ "$CONFIG_ARM" = "y" ]; then + dep_bool ' ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110 + tristate ' Cirrus Logic CS8900A support' CONFIG_ARM_CIRRUS +diff -urN linux-2.4.32/drivers/net/wireless/Config.in linux-2.4.32.new/drivers/net/wireless/Config.in +--- linux-2.4.32/drivers/net/wireless/Config.in 2004-11-17 11:54:21.000000000 +0000 ++++ linux-2.4.32.new/drivers/net/wireless/Config.in 2005-12-24 21:28:51.898660256 +0000 +@@ -38,7 +38,8 @@ + + # yes, this works even when no drivers are selected + if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" -o \ +- "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PCMCIA" != "n" ]; then ++ "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PCMCIA" != "n" -o \ ++ "$CONFIG_NET_WIRELESS" = "y" ]; then + define_bool CONFIG_NET_WIRELESS y + else + define_bool CONFIG_NET_WIRELESS n +diff -urN linux-2.4.32/include/asm-mips/atheros/ar531xbsp.h linux-2.4.32.new/include/asm-mips/atheros/ar531xbsp.h +--- linux-2.4.32/include/asm-mips/atheros/ar531xbsp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/include/asm-mips/atheros/ar531xbsp.h 2005-12-24 20:29:06.898663096 +0000 +@@ -0,0 +1,16 @@ ++#ifndef __ASM_ATHEROS_BSP_SUPPORT_H ++#define __ASM_ATHEROS_BSP_SUPPORT_H ++/* ++ * These are definitions and functions provided by the bsp to support the ++ * AR5312 WiSoC running LSDK. For different BSP implementations, different ++ * BSP functions will be needed. ++ */ ++ ++extern unsigned int ar531x_sys_frequency(void); ++ ++#ifdef CONFIG_KGDB ++extern void kgdbInit(void); ++extern int kgdbEnabled(void); ++#endif ++ ++#endif /* __ASM_ATHEROS_BSP_SUPPORT_H */ +diff -urN linux-2.4.32/include/asm-mips/bootinfo.h linux-2.4.32.new/include/asm-mips/bootinfo.h +--- linux-2.4.32/include/asm-mips/bootinfo.h 2005-12-24 16:08:53.000000000 +0000 ++++ linux-2.4.32.new/include/asm-mips/bootinfo.h 2005-12-24 21:28:51.899660104 +0000 +@@ -37,6 +37,7 @@ + #define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */ + #define MACH_GROUP_LASAT 21 + #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */ ++#define MACH_GROUP_AR531X 23 /* Atheros AR531X */ + + /* + * Valid machtype values for group unknown (low order halfword of mips_machtype) +@@ -201,6 +202,17 @@ + */ + #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */ + ++/* ++ * Valid machtype for group MACH_GROUP_AR5312 ++ */ ++#define MACH_ATHEROS_UNUSED 0 ++#define MACH_ATHEROS_AP30 1 /* AP30 */ ++#define MACH_ATHEROS_AP33 2 /* AP33 */ ++#define MACH_ATHEROS_AP38 3 /* AP38 */ ++#define MACH_ATHEROS_AP43 4 /* AP43 */ ++#define MACH_ATHEROS_AP48 5 /* AP48 */ ++#define MACH_ATHEROS_PB32 6 /* PB32 */ ++ + #define CL_SIZE (256) + + const char *get_system_type(void); +diff -urN linux-2.4.32/include/asm-mips/serial.h linux-2.4.32.new/include/asm-mips/serial.h +--- linux-2.4.32/include/asm-mips/serial.h 2005-01-19 14:10:12.000000000 +0000 ++++ linux-2.4.32.new/include/asm-mips/serial.h 2005-12-24 21:28:51.901659800 +0000 +@@ -467,6 +467,11 @@ + #define DDB5477_SERIAL_PORT_DEFNS + #endif + ++#if defined(CONFIG_AR531X) ++#undef RS_TABLE_SIZE ++#define RS_TABLE_SIZE 1 ++#endif ++ + #define SERIAL_PORT_DFNS \ + ATLAS_SERIAL_PORT_DEFNS \ + AU1000_SERIAL_PORT_DEFNS \ +diff -urN linux-2.4.32/kernel/printk.c linux-2.4.32.new/kernel/printk.c +--- linux-2.4.32/kernel/printk.c 2004-11-17 11:54:22.000000000 +0000 ++++ linux-2.4.32.new/kernel/printk.c 2005-12-24 21:28:51.929655544 +0000 +@@ -384,6 +384,18 @@ + _call_console_drivers(start_print, end, msg_level); + } + ++#if CONFIG_EARLY_PRINTK_HACK ++void putDebugChar(char byte); ++static void emit_log_char(char c) ++{ ++ if (c == '\n') { ++ putDebugChar('\r'); ++ putDebugChar('\n'); ++ } else { ++ putDebugChar(c); ++ } ++} ++#else + static void emit_log_char(char c) + { + LOG_BUF(log_end) = c; +@@ -395,6 +407,7 @@ + if (logged_chars < LOG_BUF_LEN) + logged_chars++; + } ++#endif + + /* + * This is printk. It can be called from any context. We want it to work. +@@ -700,3 +713,4 @@ + tty->driver.write(tty, 0, msg, strlen(msg)); + return; + } ++ diff --git a/target/linux/linux-2.4/patches/ar531x/001-ar531x-ethernet.patch b/target/linux/linux-2.4/patches/ar531x/001-ar531x-ethernet.patch new file mode 100644 index 0000000000..15dd777ec4 --- /dev/null +++ b/target/linux/linux-2.4/patches/ar531x/001-ar531x-ethernet.patch @@ -0,0 +1,4890 @@ +diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xlnx.c linux-2.4.32.new-eth/arch/mips/ar531x/ae531xlnx.c +--- linux-2.4.32.new/arch/mips/ar531x/ae531xlnx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xlnx.c 2005-12-25 11:54:20.756273952 +0000 +@@ -0,0 +1,1534 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * Ethernet driver for Atheros' ae531x ethernet MAC. ++ * This is a fairly generic driver, but it's intended ++ * for use in typical Atheros products. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++#include "ae531xreg.h" ++#include "ae531xmac.h" ++ ++/* ++ * A word about CONFIG_VENETDEV: It's intended to support two ++ * "virtualized ethernet devices" that share a single underlying MAC. ++ * To upper layers, it appears that the hardware supports two MACs, ++ * with enet0 used for LAN ports and enet1 used for a WAN port. This ++ * is useful, for instance, when building a 5-port router on hardware ++ * that uses only one of the AR5312's ethernet MACs. ++ * ++ * Virtualization is accomplished through trickery at the ethernet ++ * PHY layer. We use PHY hardware to determine which port a packet ++ * was received on, and in order to direct a packet to a particular ++ * port or set of ports. ++ * ++ * The code is mostly written to be generalized to more than two ++ * virtual devices; but it's intended for one multi-port LAN enet ++ * device and one single-port WAN enet device. ++ */ ++ ++#define AE531X_LAN_PORT 0 ++#ifdef CONFIG_VENETDEV ++#define AE531X_DEV_PER_MAC 2 ++#define AE531X_WAN_PORT 1 ++#else ++#define AE531X_DEV_PER_MAC 1 ++#endif ++ ++ ++/* ++ * ae531x_MAC_state contains driver-specific linux-specific per-MAC information. ++ * The OSinfo member of ae531x_MAC_t points to one of these. ++ */ ++typedef struct ae531x_MAC_state { ++ int irq; ++ struct tq_struct restart_task; ++ struct net_device_stats stats; ++ struct ae531x_dev_sw_state *dev_sw_state[AE531X_DEV_PER_MAC]; ++ int primary_dev; ++ ae531x_MAC_t MACInfo; /* hardware state */ ++} ae531x_MAC_state_t; ++ ++/* ++ * ae531x_dev_sw_state contains driver-specific linux-specific per-device ++ * information. The net_device priv member points to one of these, and ++ * this structure contains a pointer to the associated MAC information. ++ * In the case of CONFIG_VENETDEV, each virtual device has its own ++ * ae531x_dev_sw_state, and virtual devices that share a physical MAC ++ * point to the same ae531x_MAC_state. ++ */ ++typedef struct ae531x_dev_sw_state { ++ int enetUnit; /* system unit number "eth%d" */ ++ int unit_on_MAC; /* MAC-relative unit number */ ++ struct net_device *dev; ++ ae531x_MAC_state_t *MAC_state; /* underlying MAC hw/sw state */ ++#ifdef CONFIG_VENETDEV ++ BOOL isLAN; /* 0-->WAN; 1-->LAN */ ++#endif ++} ae531x_dev_sw_state_t; ++ ++/* ++ * Driver-independent linux-specific per-ethernet device software information. ++ * Regarding CONFIG_VENETDEV: If a system has 2 physical MACs, and each ++ * physical MAC has 2 virtual ethernet devices (one for LAN and one for WAN), ++ * then there are a total of 4 ethernet devices. ++ */ ++static struct net_device *ae531x_MAC_dev[AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC]; ++ ++/* Driver-dependent per-MAC information */ ++static ae531x_MAC_state_t per_MAC_info[AR531X_NUM_ENET_MAC]; ++ ++/* ++ * Receive buffers need enough room to hold the following: ++ * 1) a max MTU-sized packet. ++ * 2) space for an ethernet header ++ * 3) room at the beginning of the receive buffer in order ++ * to facilitate cooperating drivers that need to PREpend ++ * data. ++ * 4) Depending on configuration, we may need some additional ++ * room at the END of the rx buffer for phy-supplied ++ * trailers (if any). (c.f. CONFIG_VENETDEV) ++ * ++ * The DMA engine insists on 32-bit aligned RX buffers. ++ * TBDXXX: With current code, the IP stack ends up looking ++ * at misaligned headers with word operations. The misaligned ++ * reads are software-emulated via handle_adel_int. We'd ++ * rather align the buffers on a 16-bit boundary, but the ++ * DMA engine doesn't permit it??? ++ */ ++ ++#ifdef CONFIG_VLAN_8021Q ++#define ETH_MAX_MTU 1522 ++#define HLEN 18 ++#else ++#define ETH_MAX_MTU 1518 ++#define HLEN ETH_HLEN ++#endif ++ ++#define AE531X_RX_BUF_SIZE \ ++ (((2 + RXBUFF_RESERVE + HLEN + ETH_MAX_MTU + PHY_TRAILER_SIZE) + 3) & ~3) ++ ++/* Forward references to local functions */ ++static void ae531x_TxReap(ae531x_MAC_state_t *MAC_state); ++static int ae531x_phy_poll(void *data); ++static int ae531x_MAC_stop(struct net_device *dev); ++static int ae531x_MAC_open(struct net_device *dev); ++ ++/* Global to track number of MACs */ ++ ++int ar531x_num_enet_macs; ++ ++#undef DEBUG_VENETDEV ++#define AR531X_NAPI ++ ++#if defined(CONFIG_VENETDEV) && defined(DEBUG_VENETDEV) ++static int cloned_counter; ++static int expand_counter; ++static int both_counter; ++#endif ++ ++#ifdef AR531X_NAPI ++/******************************************************************************* ++* ae531x_MAC_poll checks for received packets, and sends data ++* up the stack. ++*/ ++int ++ae531x_MAC_poll(struct net_device *dev, int *budget) ++{ ++ struct sk_buff *skb; ++ struct sk_buff *newskb; ++ char *rxBufp; ++ int unused_length; ++ VIRT_ADDR rxDesc; ++ int length; ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ae531x_MAC_t *MACInfo; ++ u32 cmdsts; ++ int rx_limit; ++ int rx_received; ++ int rxDescCount; ++ struct net_device *rxdev; ++ int early_stop; ++ int retval; ++#ifdef CONFIG_VENETDEV ++ int i; ++#endif ++ ++ ARRIVE(); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ MAC_state = dev_sw_state->MAC_state; ++ MACInfo = &MAC_state->MACInfo; ++ rx_limit = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev->quota; ++ rx_received = 0; ++ ++#ifdef CONFIG_VENETDEV ++ /* ++ * Non-primary devs don't explicitly get polled by the upper layers; ++ * rather, they rely on primary_dev polling to feed packets. But in ++ * order to keep netif_receive_skb happy, we need to temporarily put the ++ * net_devices into "polling mode". We pull them back out before ++ * leaving this function. ++ */ ++ for (i=0; idev_sw_state[i]->dev) && ++ (MAC_state->dev_sw_state[i]->unit_on_MAC != MAC_state->primary_dev)) { ++ netif_rx_schedule(MAC_state->dev_sw_state[i]->dev); ++ } ++ } ++#endif ++ rxDescCount = 0; ++ ++ early_stop = 0; ++ do { ++ for(;;) { ++ // ae531x_AckIntr(MACInfo, (DmaIntRxCompleted | DmaIntRxNoBuffer)); ++ ++ rxDesc = MACInfo->rxQueue.curDescAddr; ++ cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc)); ++ ++ AE531X_PRINT(AE531X_DEBUG_RX, ++ ("examine rxDesc %p with cmdsts=0x%x\n", ++ (void *)rxDesc, cmdsts)); ++ ++ if (cmdsts & DescOwnByDma) { ++ /* There's nothing left to process in the RX ring */ ++ goto rx_all_done; ++ } ++ ++ rxDescCount++; ++ ++ AE531X_CONSUME_DESC((&MACInfo->rxQueue)); ++ ++ // A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE); ++ ++ /* Process a packet */ ++ length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN; ++ if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) == ++ (DescRxFirst | DescRxLast) ) { ++ /* Descriptor status indicates "NO errors" */ ++ skb = AE531X_DESC_SWPTR_GET(rxDesc); ++ ++ /* ++ * Allocate a replacement skb. ++ * We want to get another buffer ready for Rx ASAP. ++ */ ++ newskb = (struct sk_buff *)ae531x_rxbuf_alloc(MACInfo, &rxBufp, &unused_length); ++ if(newskb == NULL ) { ++ /* ++ * Give this descriptor back to the DMA engine, ++ * and drop the received packet. ++ */ ++ MAC_state->stats.rx_dropped++; ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("Can't allocate new skb\n")); ++ } else { ++ AE531X_DESC_BUFPTR_SET(rxDesc, rxBufp); ++ AE531X_DESC_SWPTR_SET(rxDesc, newskb); ++ } ++ ++ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma); ++ A_DATA_CACHE_FLUSH_INVAL(rxDesc, AE531X_DESC_SIZE); ++ // rxDesc = NULL; /* sanity -- cannot use rxDesc now */ ++ sysWbFlush(); ++ ++ if (newskb == NULL) { ++ retval = 1; ++ goto rx_no_skbs; ++ } else { ++ /* Sync data cache w.r.t. DMA */ ++ // A_DATA_CACHE_INVAL(skb->data, length); ++ ++#ifdef CONFIG_VENETDEV ++ /* Determine which associated device owns this rx buffer */ ++ { ++ int fromLAN; ++ ++ fromLAN = phyDetermineSource(skb->data, length); ++ ++ if (fromLAN == -1) { ++ /* ++ * Could not determine source, so drop the packet ++ */ ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++ length -= PHY_TRAILER_SIZE; ++ if (fromLAN) { ++ dev_sw_state = MAC_state->dev_sw_state[AE531X_LAN_PORT]; ++ } else { ++ dev_sw_state = MAC_state->dev_sw_state[AE531X_WAN_PORT]; ++ } ++ } ++#endif ++ rxdev = dev_sw_state->dev; ++ ++ if (rxdev == NULL) { ++ /* ++ * We received a packet for a virtual enet device ++ * that is no longer up. Ignore it. ++ */ ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++ /* Advance data pointer to show that there's data here */ ++ skb_put(skb, length); ++ skb->protocol = eth_type_trans(skb, rxdev); ++ skb->dev = rxdev; ++ rxdev->last_rx = jiffies; ++ rxdev->quota--; ++ ++ if (rx_limit-- < 0) { ++ early_stop=1; ++ /* We've done enough for now -- more later */ ++ AE531X_PRINT(AE531X_DEBUG_RX_STOP, ++ ("Enet%d RX early stop. Quota=%d rxDescCount=%d budget=%d\n", ++ MACInfo->unit, dev->quota, rxDescCount, *budget)); ++ } ++ rx_received++; ++ ++ /* Send the data up the stack */ ++ AE531X_PRINT(AE531X_DEBUG_RX, ++ ("Send data up stack: skb=%p data=%p length=%d\n", ++ (void *)skb, (void *)skb->data, length)); ++ ++ netif_receive_skb(skb); ++ ++ MAC_state->stats.rx_packets++; ++ MAC_state->stats.rx_bytes += length; ++ } ++ } else { ++ /* Descriptor status indicates ERRORS */ ++ MAC_state->stats.rx_errors++; ++ ++ if (cmdsts & (DescRxRunt | DescRxLateColl)) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("Runt | RX Late Collision Error\n")); ++ MAC_state->stats.collisions++; ++ } ++ ++ if (cmdsts & DescRxLengthError) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("RX Length Error\n")); ++ MAC_state->stats.rx_length_errors++; ++ } ++ ++ if (cmdsts & DescRxCrc) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("RX CRC Error\n")); ++ MAC_state->stats.rx_crc_errors++; ++ } ++ ++ if (cmdsts & DescRxDribbling) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("Dribbling Error\n")); ++ MAC_state->stats.rx_frame_errors++; ++ } ++ ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("Bad receive. rxDesc=%p cmdsts=0x%8.8x\n", ++ (void *)rxDesc, cmdsts)); ++ ++ /* Give this one back */ ++ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma); ++ A_DATA_CACHE_FLUSH_INVAL(rxDesc, AE531X_DESC_SIZE); ++ sysWbFlush(); ++ } ++ } ++ } while ((!early_stop) && ++ ae531x_ReadDmaReg(MACInfo, DmaStatus) & DmaIntRxCompleted); ++ ++rx_all_done: ++ AE531X_PRINT(AE531X_DEBUG_RX, ++ ("rx done (%d)\n", rxDescCount)); ++ *budget -= rxDescCount; ++ ++ if (!early_stop) { ++ netif_rx_complete(dev); ++ ++ ae531x_SetDmaReg(MACInfo, DmaIntrEnb, ++ DmaIeRxCompleted | DmaIeRxNoBuffer); ++ ae531x_WriteDmaReg(MACInfo, DmaRxPollDemand, 0); ++ } ++ ++ retval = early_stop; ++ ++rx_no_skbs: ++ ++#ifdef CONFIG_VENETDEV ++ for (i=0; idev_sw_state[i]->dev) && ++ (MAC_state->dev_sw_state[i]->unit_on_MAC != ++ MAC_state->primary_dev)) { ++ netif_rx_complete(MAC_state->dev_sw_state[i]->dev); ++ } ++ } ++#endif ++ ++ LEAVE(); ++ return retval; ++} ++#endif ++ ++#ifndef AR531X_NAPI ++/******************************************************************************* ++* ae531x_MAC_recv checks for received packets, and sends data ++* up the stack. ++*/ ++static void ++ae531x_MAC_recv(struct net_device *dev) ++{ ++ struct sk_buff *skb; ++ struct sk_buff *newskb; ++ char *rxBufp; ++ int unused_length; ++ VIRT_ADDR rxDesc; ++ int length; ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ae531x_MAC_t *MACInfo; ++ u32 cmdsts; ++ int rx_limit; ++ int rx_received; ++ struct net_device *rxdev; ++ int retval; ++ ++ ARRIVE(); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ MAC_state = dev_sw_state->MAC_state; ++ MACInfo = &MAC_state->MACInfo; ++ rx_limit = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev->quota; ++ rx_received = 0; ++ ++ for(;;) { ++ rxDesc = MACInfo->rxQueue.curDescAddr; ++ cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc)); ++ ++ AE531X_PRINT(AE531X_DEBUG_RX, ++ ("examine rxDesc %p with cmdsts=0x%x\n", ++ (void *)rxDesc, cmdsts)); ++ ++ if (cmdsts & DescOwnByDma) { ++ /* There's nothing left to process in the RX ring */ ++ break; ++ } ++ ++ AE531X_CONSUME_DESC((&MACInfo->rxQueue)); ++ ++ // A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE); ++ ++ /* Process a packet */ ++ length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN; ++ if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) == ++ (DescRxFirst | DescRxLast) ) { ++ /* Descriptor status indicates "NO errors" */ ++ skb = AE531X_DESC_SWPTR_GET(rxDesc); ++ ++ /* ++ * Allocate a replacement skb. ++ * We want to get another buffer ready for Rx ASAP. ++ */ ++ newskb = (struct sk_buff *)ae531x_rxbuf_alloc(MACInfo, ++ &rxBufp, ++ &unused_length); ++ if(newskb == NULL ) { ++ /* ++ * Give this descriptor back to the DMA engine, ++ * and drop the received packet. ++ */ ++ MAC_state->stats.rx_dropped++; ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("Can't allocate new skb\n")); ++ } else { ++ AE531X_DESC_BUFPTR_SET(rxDesc, rxBufp); ++ AE531X_DESC_SWPTR_SET(rxDesc, newskb); ++ } ++ ++ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma); ++ A_DATA_CACHE_FLUSH_INVAL(rxDesc, AE531X_DESC_SIZE); ++ sysWbFlush(); ++ ++ if (newskb == NULL) { ++ break; ++ } else { ++#ifdef CONFIG_VENETDEV ++ /* Determine which associated device owns this rx buffer */ ++ { ++ int fromLAN; ++ ++ fromLAN = phyDetermineSource(skb->data, length); ++ ++ if (fromLAN == -1) { ++ /* ++ * Could not determine source, so drop the packet ++ */ ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++ length -= PHY_TRAILER_SIZE; ++ if (fromLAN) { ++ dev_sw_state = ++ MAC_state->dev_sw_state[AE531X_LAN_PORT]; ++ } else { ++ dev_sw_state = ++ MAC_state->dev_sw_state[AE531X_WAN_PORT]; ++ } ++ } ++#endif ++ rxdev = dev_sw_state->dev; ++ ++ if (rxdev == NULL) { ++ /* ++ * We received a packet for a virtual enet device ++ * that is no longer up. Ignore it. ++ */ ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++ /* Advance data pointer to show that there's data here */ ++ skb_put(skb, length); ++ skb->protocol = eth_type_trans(skb, rxdev); ++ skb->dev = rxdev; ++ rxdev->last_rx = jiffies; ++ rxdev->quota--; ++ ++ rx_received++; ++ ++ /* Send the data up the stack */ ++ AE531X_PRINT(AE531X_DEBUG_RX, ++ ("Send data up stack: skb=%p data=%p length=%d\n", ++ (void *)skb, (void *)skb->data, length)); ++ ++ netif_rx(skb); ++ ++ MAC_state->stats.rx_packets++; ++ MAC_state->stats.rx_bytes += length; ++ } ++ } else { ++ /* Descriptor status indicates ERRORS */ ++ MAC_state->stats.rx_errors++; ++ ++ if (cmdsts & (DescRxRunt | DescRxLateColl)) { ++ MAC_state->stats.collisions++; ++ } ++ ++ if (cmdsts & DescRxLengthError) { ++ MAC_state->stats.rx_length_errors++; ++ } ++ ++ if (cmdsts & DescRxCrc) { ++ MAC_state->stats.rx_crc_errors++; ++ } ++ ++ if (cmdsts & DescRxDribbling) { ++ MAC_state->stats.rx_frame_errors++; ++ } ++ ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("Bad receive. rxDesc=%p cmdsts=0x%8.8x\n", ++ (void *)rxDesc, cmdsts)); ++ } ++ } ++ ++ LEAVE(); ++ return; ++} ++#endif ++ ++/******************************************************************************* ++* ae531x_restart stops all ethernet devices associated with a physical MAC, ++* then shuts down the MAC. Then it re-opens all devices that were in use. ++* TBDXXX: needs testing! ++*/ ++static void ++ae531x_restart(void *data) ++{ ++ ae531x_MAC_t *MACInfo = (ae531x_MAC_t *)data; ++ ae531x_MAC_state_t *MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo; ++ struct net_device *saved_dev[AE531X_DEV_PER_MAC]; ++ int i; ++ ++ for (i=0; idev_sw_state[i]->dev) != NULL) { ++ ae531x_MAC_stop(saved_dev[i]); ++ } ++ } ++ ++ for (i=0; iOSinfo; ++ primary_dev = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev; ++ ++ for(;;) { ++ /* Clear any unhandled intr causes. */ ++ ae531x_WriteDmaReg(MACInfo, DmaStatus, UnhandledIntrMask); ++ ++ regIsr = ae531x_ReadDmaReg(MACInfo, DmaStatus); ++ ++ regImr = ae531x_ReadDmaReg(MACInfo, DmaIntrEnb); ++ pendIntrs = regIsr & regImr; ++ ++ AE531X_PRINT(AE531X_DEBUG_INT, ++ ("ethmac%d: intIsr=0x%8.8x intImr=0x%8.8x\n", ++ MACInfo->unit, regIsr, regImr)); ++ ++ if ((pendIntrs & DmaAllIntCauseMask) == 0) ++ break; ++ ++ if ((pendIntrs & DmaIntRxCompleted) || ++ (pendIntrs & DmaIntRxNoBuffer)) { ++#ifdef AR531X_NAPI ++ if (netif_rx_schedule_prep(primary_dev)) { ++ ae531x_ClearDmaReg(MACInfo, ++ DmaIntrEnb, ++ DmaIeRxCompleted | DmaIeRxNoBuffer); ++ ae531x_AckIntr(MACInfo, ++ DmaIntRxCompleted | DmaIntRxNoBuffer); ++ (void)ae531x_ReadDmaReg(MACInfo, DmaIntrEnb); ++ __netif_rx_schedule(primary_dev); ++ } else { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("%s: Interrupt (0x%8.8x/0x%8.8x) while in poll. regs@%p, pc=%p, ra=%p\n", ++ __FILE__, ++ regIsr, ++ ae531x_ReadDmaReg(MACInfo, DmaIntrEnb), ++ (void *)regs, ++ (void *)regs->cp0_epc, ++ (void *)regs->regs[31])); ++ ae531x_ClearDmaReg(MACInfo, ++ DmaIntrEnb, ++ DmaIeRxCompleted | DmaIeRxNoBuffer); ++ ae531x_AckIntr(MACInfo, ++ DmaIntRxCompleted | DmaIntRxNoBuffer); ++ } ++#else ++ ae531x_MAC_recv(primary_dev); ++ ae531x_AckIntr(MACInfo, ++ DmaIntRxCompleted | DmaIntRxNoBuffer); ++#endif ++ } ++ ++ if (pendIntrs & ++ (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow)) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("ethmac%d: TX Error Intr (0x%x)\n", ++ MACInfo->unit, pendIntrs)); ++ ae531x_AckIntr(MACInfo, ++ (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow)); ++ } ++ ++ if (pendIntrs & DmaIntBusError) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("ethmac%d: DMA Bus Error Intr (0x%x)\n", ++ MACInfo->unit, pendIntrs)); ++ ae531x_AckIntr(MACInfo, DmaIntBusError); ++ /* Reset the chip, if it's not already being done */ ++ if (ae531x_IsInResetMode(MACInfo)) { ++ goto intr_done; ++ } ++ ae531x_BeginResetMode(MACInfo); ++ schedule_task(&MAC_state->restart_task); ++ } ++ ++ if (pendIntrs & DmaIntRxStopped) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("ethmac%d: RX Stopped Intr (0x%x)\n", ++ MACInfo->unit, pendIntrs)); ++ ae531x_AckIntr(MACInfo, DmaIntRxStopped); ++ } ++ } ++ ++ ae531x_DmaIntEnable(MACInfo); ++ ++intr_done: ++ LEAVE(); ++} ++ ++/******************************************************************************* ++* ae531x_MAC_get_stats returns statistics for a specified device ++*/ ++static struct net_device_stats* ++ae531x_MAC_get_stats(struct net_device *dev) ++{ ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ++ ARRIVE(); ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ MAC_state = dev_sw_state->MAC_state; ++ ++ LEAVE(); ++ return &MAC_state->stats; ++} ++ ++#define AE531X_PHY_POLL_SECONDS 2 ++ ++/******************************************************************************* ++* ae531x_phy_poll periodically checks for changes in phy status ++* (e.g. dropped link). ++*/ ++static int ++ae531x_phy_poll(void *data) ++{ ++ ae531x_dev_sw_state_t *dev_sw_state = (ae531x_dev_sw_state_t *)data; ++ ae531x_MAC_t *MACInfo = &dev_sw_state->MAC_state->MACInfo; ++ int unit = dev_sw_state->enetUnit; ++ ++#if defined(CONFIG_VENETDEV) && defined(DEBUG_VENETDEV) ++ int previous_cloned = 0; ++ int previous_expand = 0; ++ int previous_both = 0; ++#endif ++ ++ daemonize(); ++ reparent_to_init(); ++ spin_lock_irq(¤t->sigmask_lock); ++ sigemptyset(¤t->blocked); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ snprintf(current->comm, sizeof(current->comm), "%s", ++ dev_sw_state->dev->name); ++ ++ for(;;) { ++ if (MACInfo->port_is_up) { ++ phyCheckStatusChange(unit); ++ } ++ ++#if defined(CONFIG_VENETDEV) && defined(DEBUG_VENETDEV) ++ if (cloned_counter != previous_cloned) { ++ printk("Cloned Counter: %d (delta %d)\n", ++ cloned_counter, cloned_counter - previous_cloned); ++ previous_cloned = cloned_counter; ++ } ++ if (expand_counter != previous_expand) { ++ printk("Expand Counter: %d (delta %d)\n", ++ expand_counter, expand_counter - previous_expand); ++ previous_expand = expand_counter; ++ } ++ if (both_counter != previous_both) { ++ printk("Expand & Cloned Counter: %d (delta %d)\n", ++ both_counter, both_counter - previous_both); ++ previous_both = both_counter; ++ } ++#endif ++ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(AE531X_PHY_POLL_SECONDS * HZ); ++ } ++ ++ return 0; ++} ++ ++ ++/******************************************************************************* ++* ae531x_MAC_set_rx_mode is used to set the RX mode options, such as ++* promiscuous or multicast. ++*/ ++static void ++ae531x_MAC_set_rx_mode(struct net_device *dev) ++{ ++ ae531x_dev_sw_state_t *dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ ae531x_MAC_state_t *MAC_state=dev_sw_state->MAC_state; ++ ae531x_MAC_t *MACInfo = &MAC_state->MACInfo; ++ ++ if (dev->flags & IFF_PROMISC) { ++ ae531x_SetMacReg(MACInfo, MacControl, MacPromiscuousModeOn); ++ } else { ++ ae531x_ClearMacReg(MACInfo, MacControl, MacPromiscuousModeOn); ++ } ++ ++ if (dev->flags & IFF_MULTICAST) { ++ ae531x_SetMacReg(MACInfo, MacControl, MacMulticastFilterOff); ++ } else { ++ ae531x_ClearMacReg(MACInfo, MacControl, MacMulticastFilterOff); ++ } ++} ++ ++/******************************************************************************* ++* ae531x_MAC_open is the standard Linux open function. It puts ++* hardware into a known good state, allocates queues, starts ++* the phy polling task, and arranges for interrupts to be handled. ++*/ ++static int ++ae531x_MAC_open(struct net_device *dev) ++{ ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ae531x_MAC_t *MACInfo; ++ int rv; ++ struct tq_struct *restart_task; ++ pid_t phy_poll_pid; ++ ++ ARRIVE(); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ dev_sw_state->dev = dev; ++ MAC_state = dev_sw_state->MAC_state; ++ MACInfo = &MAC_state->MACInfo; ++ ++ restart_task = &MAC_state->restart_task; ++ restart_task->routine = ae531x_restart; ++ restart_task->data = (void *)MACInfo; ++ ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ae531x_MAC_open eth%d ethmac%d macBase=0x%x dmaBase=0x%x irq=0x%x\n", ++ dev_sw_state->enetUnit, ++ MACInfo->unit, ++ MACInfo->macBase, ++ MACInfo->dmaBase, ++ MAC_state->irq)); ++ ++ if (!MACInfo->port_is_up) { ++ /* Bring MAC and PHY out of reset */ ++ ae531x_reset(MACInfo); ++ ++ /* Attach interrupt handler */ ++ rv = request_irq(MAC_state->irq, ae531x_MAC_intr, SA_INTERRUPT, ++ "ae531x_MAC_intr", (void *)MACInfo); ++ if (rv < 0) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("request_irq(0x%x) failed (%d)\n", ++ MAC_state->irq, rv)); ++ goto open_failure; ++ } ++ ++ /* Initialize PHY */ ++ phySetup(MACInfo->unit, MACInfo->phyBase); ++ ++ /* Start thread to poll for phy link status changes */ ++ phy_poll_pid = kernel_thread(ae531x_phy_poll, ++ dev_sw_state, ++ CLONE_FS | CLONE_FILES); ++ if (phy_poll_pid < 0) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("ethmac%d unable to start Phy Poll thread\n", ++ MACInfo->unit)); ++ } ++ ++ /* Allocate RX/TX Queues */ ++ if (ae531x_AllocateQueues(MACInfo) < 0) { ++ AE531X_PRINT(AE531X_DEBUG_RESET, ("Queue allocation failed")); ++ free_irq(MAC_state->irq, (void *)MACInfo); ++ goto open_failure; ++ } ++ ++ /* Initialize DMA and descriptors */ ++ ae531x_DmaReset(MACInfo); ++ ++ /* Initialize MAC */ ++ ae531x_MACReset(MACInfo); ++ ++ /* Set RX mode */ ++ ae531x_MAC_set_rx_mode(dev); ++ ++ /* Enable Receive/Transmit */ ++ ae531x_EnableComm(MACInfo); ++ ++ MAC_state->primary_dev = dev_sw_state->unit_on_MAC; ++ MACInfo->port_is_up = TRUE; ++ } ++ ++ dev->trans_start = jiffies; ++ ++ LEAVE(); ++ return 0; ++ ++open_failure: ++ LEAVE(); ++ return -1; ++} ++ ++/* ++ * Shut down MAC hardware. ++ */ ++static void ++ae531x_MAC_shutdown(ae531x_MAC_state_t *MAC_state) ++{ ++ ae531x_MAC_t *MACInfo; ++ ++ MACInfo = &MAC_state->MACInfo; ++ MACInfo->port_is_up = FALSE; ++ ++ /* Disable Receive/Transmit */ ++ ae531x_DisableComm(MACInfo); ++ ++ /* Disable Interrupts */ ++ ae531x_DmaIntDisable(MACInfo); ++ sysWbFlush(); ++ free_irq(MAC_state->irq, (void *)MACInfo); ++ ++ /* Free Transmit & Receive skb's/descriptors */ ++ ae531x_TxReap(MAC_state); /* one last time */ ++ ae531x_FreeQueues(MACInfo); ++} ++ ++/******************************************************************************* ++* ae531x_MAC_stop is the standard Linux stop function. It undoes ++* everything set up by ae531x_MAC_open. ++*/ ++static int ++ae531x_MAC_stop(struct net_device *dev) ++{ ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ae531x_MAC_t *MACInfo; ++ int i; ++ ++ ARRIVE(); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ MAC_state = dev_sw_state->MAC_state; ++ MACInfo = &MAC_state->MACInfo; ++ ++ for (i=0; idev_sw_state[i]->dev) && ++ (MAC_state->dev_sw_state[i]->dev != dev_sw_state->dev)) { ++ break; ++ } ++ } ++ ++ if (i < AE531X_DEV_PER_MAC) { ++ /* Physical MAC is still in use */ ++ if (MAC_state->primary_dev == dev_sw_state->unit_on_MAC) { ++ /* ++ * If the primary_dev is being stopped ++ * then we need to assign a new one. ++ */ ++ MAC_state->primary_dev = i; ++ } ++ } else { ++ /* Physical MAC is no longer in use */ ++ ae531x_MAC_shutdown(MAC_state); ++ } ++ ++ dev_sw_state->dev = NULL; ++ ++ LEAVE(); ++ return 0; ++} ++ ++/******************************************************************************* ++* ae531x_rxbuf_alloc - Allocate an skb to be associated with an RX descriptor. ++* ++* RETURNS: A pointer to the skb. Also returns a pointer to the underlying ++* buffer and the size of that buffer. ++*/ ++void * ++ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBuffp, int *rxBuffSizep) ++{ ++ struct sk_buff *skb; ++ char *rxBuff; ++ int rxBuffSize; ++ ++ skb = dev_alloc_skb(AE531X_RX_BUF_SIZE); ++ if (skb) { ++ /* Add 2 to align the IP header on a DWORD boundary */ ++ skb_reserve(skb, RXBUFF_RESERVE + 2); ++ ++ rxBuffSize = skb_tailroom(skb); ++ rxBuff = skb->tail; ++ ++ *rxBuffp = rxBuff; ++ *rxBuffSizep = rxBuffSize; ++ ++ A_DATA_CACHE_INVAL(rxBuff, rxBuffSize); ++ } ++ ++ return skb; ++} ++ ++/******************************************************************************* ++* ae531x_swptr_free - Free the skb, if any, associated with a descriptor. ++*/ ++void ++ae531x_swptr_free(VIRT_ADDR desc) ++{ ++ struct sk_buff *skb; ++ ++ skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(desc); ++ if (skb) { ++ AE531X_DESC_SWPTR_SET(desc, NULL); ++ kfree_skb(skb); ++ } ++} ++ ++/******************************************************************************* ++* ++* ae531x_TxReap - the driver Tx completion routine. ++* ++* This routine reaps sk_buffs which have already been transmitted. ++* ++*/ ++static void ++ae531x_TxReap(ae531x_MAC_state_t *MAC_state) ++{ ++ AE531X_QUEUE *txq; ++ VIRT_ADDR txDesc; ++ UINT32 cmdsts; ++ struct sk_buff *skb; ++ int reaped; ++ ae531x_MAC_t *MACInfo; ++ static int aeUselessReap = 0; ++ ++ ARRIVE(); ++ ++ MACInfo = &MAC_state->MACInfo; ++ txq = &MACInfo->txQueue; ++ reaped = 0; ++ ++ while (1) { ++ txDesc = AE531X_QUEUE_ELE_NEXT_GET(txq, txq->reapDescAddr); ++ if (txDesc == txq->curDescAddr) { ++ break; ++ } ++ ++ cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(txDesc)); ++ if (cmdsts & DescOwnByDma) { ++ break; ++ } ++ ++ /* Release sk_buff associated with completed transmit */ ++ skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(txDesc); ++ ++ if (skb) { ++ kfree_skb(skb); ++ AE531X_DESC_SWPTR_SET(txDesc, NULL); ++ } ++ ++ /* Update statistics according to completed transmit desc */ ++ if (cmdsts & DescTxErrors) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("enetmac%d Tx prior error: 0x%8.8x <0x%8.8x> 0x%8.8x\n", ++ MACInfo->unit, ++ cmdsts, ++ DescTxErrors, ++ (int)txDesc)); ++ MAC_state->stats.tx_errors++; ++ if (cmdsts & (DescTxLateCollision | DescTxExcCollisions)) { ++ MAC_state->stats.tx_aborted_errors++; ++ } ++ if (cmdsts & (DescTxLostCarrier | DescTxNoCarrier)) { ++ MAC_state->stats.tx_carrier_errors++; ++ } ++ } else { ++ MAC_state->stats.tx_bytes += AE531X_DESC_STATUS_RX_SIZE(cmdsts); ++ MAC_state->stats.tx_packets++; ++ } ++ ++ MAC_state->stats.collisions += ++ ((cmdsts & DescTxCollMask) >> DescTxCollShift); ++ ++ txq->reapDescAddr = txDesc; ++ reaped++; ++ } ++ ++ if (reaped > 0) { ++ int i; ++ ++ AE531X_PRINT(AE531X_DEBUG_TX_REAP, ++ ("reaped %d\n", reaped)); ++ ++ /* ++ * Re-start transmit queues for all ethernet devices ++ * associated with this MAC. ++ */ ++ for (i=0; idev_sw_state[i]->dev) ++ netif_start_queue(MAC_state->dev_sw_state[i]->dev); ++ } ++ } else { ++ aeUselessReap++; ++ } ++ ++ LEAVE(); ++} ++ ++/******************************************************************************* ++* ae531x_MAC_start_xmit sends a packet. ++*/ ++static int ++ae531x_MAC_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ae531x_MAC_t *MACInfo; ++ u32 buf; ++ u32 ctrlen; ++ u32 length; ++ int mtu; ++ int max_buf_size; ++ VIRT_ADDR txDesc; ++ ++ ARRIVE(); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ MAC_state = dev_sw_state->MAC_state; ++ MACInfo = &MAC_state->MACInfo; ++ ++ length = skb->len; ++ ++ /* Check if this port is up, else toss packet */ ++ if (!MACInfo->port_is_up) { ++ buf = virt_to_bus(skb->data); ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("eth%d Tx Down, dropping buf=0x%8.8x, length=0x%8.8x, skb=%p\n", ++ dev_sw_state->enetUnit, buf, length, (void *)skb)); ++ ++ MAC_state->stats.tx_dropped++; ++ MAC_state->stats.tx_carrier_errors++; ++ goto dropFrame; ++ } ++ ++ if (ae531x_IsInResetMode(MACInfo)) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("eth%d Tx: In Chip reset - drop frame\n", ++ dev_sw_state->enetUnit)); ++ ++ MAC_state->stats.tx_dropped++; ++ MAC_state->stats.tx_aborted_errors++; ++ goto dropFrame; ++ } ++ ++ /* Check if we can transport this packet */ ++ length = max((u32)60, length); /* total length */ ++ mtu = dev->mtu; ++ max_buf_size = mtu + HLEN; ++ if (length > max_buf_size) { ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("eth%d Tx: length %d too long. mtu=%d, trailer=%d\n", ++ dev_sw_state->enetUnit, length, mtu, PHY_TRAILER_SIZE)); ++ ++ MAC_state->stats.tx_errors++; ++ MAC_state->stats.tx_aborted_errors++; ++ ++ goto dropFrame; ++ } ++ ++ /* Reap any old, completed Tx descriptors */ ++ ae531x_TxReap(MAC_state); ++ ++ txDesc = MACInfo->txQueue.curDescAddr; ++ if (txDesc == MACInfo->txQueue.reapDescAddr) { ++ int i; ++ ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("eth%d Tx: cannot get txDesc\n", ++ dev_sw_state->enetUnit)); ++ ++ MAC_state->stats.tx_dropped++; ++ MAC_state->stats.tx_fifo_errors++; ++ ++ /* ++ * Stop transmit queues for any ethernet devices ++ * associated with this MAC. ++ */ ++ for (i=0; idev_sw_state[i]->dev) ++ netif_stop_queue(MAC_state->dev_sw_state[i]->dev); ++ } ++ goto dropFrame; ++ } ++ ++#ifdef CONFIG_VENETDEV ++ { ++ struct sk_buff *newskb; ++ ++ if (skb_cloned(skb) || (skb_tailroom(skb) < PHY_TRAILER_SIZE)) { ++#ifdef DEBUG_VENETDEV ++ if (skb_cloned(skb)) { ++ cloned_counter++; ++ if (skb_tailroom(skb) < PHY_TRAILER_SIZE) { ++ both_counter++; ++ } ++ } else { ++ expand_counter++; ++ } ++#endif ++ newskb = skb_copy_expand(skb, 0, PHY_TRAILER_SIZE, GFP_ATOMIC); ++ if (newskb == NULL) { ++ goto dropFrame; ++ } ++ ++ dev_kfree_skb(skb); ++ skb = newskb; ++ } ++ ++ phySetDestinationPort(skb->data, length, dev_sw_state->isLAN); ++ skb_put(skb, PHY_TRAILER_SIZE); ++ length += PHY_TRAILER_SIZE; ++ } ++#endif ++ ++ /* We won't fail now; so consume this descriptor */ ++ AE531X_CONSUME_DESC((&MACInfo->txQueue)); ++ ++ /* Update the descriptor */ ++ buf = virt_to_bus(skb->data); ++ A_DATA_CACHE_FLUSH(skb->data, skb->len); ++ AE531X_DESC_BUFPTR_SET(txDesc, buf); ++ AE531X_DESC_SWPTR_SET(txDesc, skb); ++ ctrlen = AE531X_DESC_CTRLEN_GET(txDesc); ++ ctrlen = (ctrlen & (DescEndOfRing)) | ++ DescTxFirst | ++ DescTxLast | ++ DescTxIntEnable; ++ ++ ctrlen |= ((length << DescSize1Shift) & DescSize1Mask); ++ ++ AE531X_DESC_CTRLEN_SET(txDesc, ctrlen); ++ AE531X_DESC_STATUS_SET(txDesc, DescOwnByDma); ++ ++ AE531X_PRINT(AE531X_DEBUG_TX, ++ ("eth%d Tx: Desc=0x%8.8x, L=0x%8.8x, D=0x%8.8x, d=0x%8.8x, length=0x%8.8x\n", ++ dev_sw_state->enetUnit, ++ (UINT32)txDesc, ++ AE531X_DESC_CTRLEN_GET(txDesc), ++ buf, ++ AE531X_DESC_LNKBUF_GET(txDesc), ++ length)); ++ ++ /* Must not use txDesc after this point */ ++ A_DATA_CACHE_FLUSH_INVAL(txDesc, AE531X_DESC_SIZE); ++ ++ /* Alert DMA engine to resume Tx */ ++ ae531x_WriteDmaReg(MACInfo, DmaTxPollDemand, 0); ++ sysWbFlush(); ++ ++ MAC_state->stats.tx_packets++; ++ MAC_state->stats.tx_bytes += length; ++ ++ /* Tell upper layers to keep it coming */ ++ dev->trans_start = jiffies; ++ ++ LEAVE(); ++ return 0; ++ ++dropFrame: ++ dev_kfree_skb(skb); ++ ++ LEAVE(); ++ return 0; ++} ++ ++ ++/******************************************************************************* ++* ae531x_MAC_tx_timeout handles transmit timeouts ++*/ ++static void ++ae531x_MAC_tx_timeout(struct net_device *dev) ++{ ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ae531x_MAC_t *MACInfo; ++ ++ ARRIVE(); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ MAC_state = dev_sw_state->MAC_state; ++ MACInfo = &MAC_state->MACInfo; ++ ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("enet%d: Tx timeout\n", dev_sw_state->enetUnit)); ++ ++ ae531x_restart(MACInfo); ++ ++ LEAVE(); ++} ++ ++ ++/******************************************************************************* ++* ae531x_MAC_do_ioctl is a placeholder for future ioctls. ++*/ ++static int ++ae531x_MAC_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ int rv; ++ ae531x_MAC_t *MACInfo; ++ struct ioctl_data { ++ u32 unit; ++ u32 addr; ++ u32 data; ++ } *req; ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ++ ARRIVE(); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ MAC_state = dev_sw_state->MAC_state; ++ MACInfo = &MAC_state->MACInfo; ++ ++ req = (struct ioctl_data *)ifr->ifr_data; ++ ++ switch( cmd ) { ++ default: ++ AE531X_PRINT(AE531X_DEBUG_ERROR, ++ ("Unsupported ioctl: 0x%x\n", cmd)); ++ rv = -EOPNOTSUPP; ++ } ++ ++ LEAVE(); ++ return rv; ++} ++ ++/******************************************************************************* ++* ae531x_MAC_set_mac_address sets a new hardware address for the device ++*/ ++static int ++ae531x_MAC_set_mac_address(struct net_device *dev, void *addr) ++{ ++ struct sockaddr *saddr = (struct sockaddr *)addr; ++ ++ /* update dev struct */ ++ memcpy(dev->dev_addr, &saddr->sa_data[0], dev->addr_len); ++ ++ return 0; ++} ++ ++/****************************************************************************** ++* macAddrGet - Given a MACInfo pointer, return a pointer to an ++* array of chars that holds the corresponding MAC address. ++*/ ++char *macAddrGet(ae531x_MAC_t *MACInfo) ++{ ++ // return enet_mac_address_get(MACInfo->unit); ++ return ae531x_MAC_dev[MACInfo->unit]->dev_addr; ++} ++ ++static void ++ae531x_MAC_setup_fntable(struct net_device *dev) ++{ ++ /* Set a default (should be overridden by software) */ ++ u8 default_MAC_address[] = { 0x00, 0x03, 0x7f, 0xe0, 0x02, 0xbF }; ++ ++ ARRIVE(); ++ ++ dev->get_stats = ae531x_MAC_get_stats; ++ dev->open = ae531x_MAC_open; ++ dev->stop = ae531x_MAC_stop; ++ dev->hard_start_xmit = ae531x_MAC_start_xmit; ++ dev->do_ioctl = ae531x_MAC_do_ioctl; ++#ifdef AR531X_NAPI ++ dev->poll = ae531x_MAC_poll; ++ dev->weight = 16; ++#endif ++ dev->tx_timeout = ae531x_MAC_tx_timeout; ++ dev->features = NETIF_F_HW_CSUM |\ ++ NETIF_F_HIGHDMA; ++ dev->set_mac_address = ae531x_MAC_set_mac_address; ++ dev->set_multicast_list = ae531x_MAC_set_rx_mode; ++ ++ /* Copy default MAC address into device descriptor */ ++ memcpy(dev->dev_addr, default_MAC_address, dev->addr_len ); ++ ++ LEAVE(); ++} ++ ++/* ++ * ae531x_twisted_enet() returns 1 for chips where there is only one usable ++ * MAC, and that MAC is 1. ++ */ ++static BOOL ++ae531x_twisted_enet(void) ++{ ++ int wisoc_revision; ++ int flash_bus_width; ++ ++ wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> ++ AR531X_REV_MAJ_S; ++ if (wisoc_revision == AR531X_REV_MAJ_AR2313) ++ return TRUE; ++ ++ flash_bus_width = sysRegRead(AR531X_FLASHCTL0) & FLASHCTL_MWx16; ++ ++ if (flash_bus_width == 0) { ++ printk("Found AR2312-01\n"); ++ return TRUE; /* AR2312-01 has 8 bit flash bus */ ++ } else { ++ printk("Found AR2312-00\n"); ++ return FALSE; ++ } ++} ++ ++int ++ae531x_MAC_setup(void) ++{ ++ int i; ++ int next_dev; ++ int rev; ++ struct net_device *dev; ++ ae531x_dev_sw_state_t *dev_sw_state; ++ ae531x_MAC_state_t *MAC_state; ++ ae531x_MAC_t *MACInfo; ++ ++ ARRIVE(); ++ ++#if 0 ++ /* ++ * This does not work since the AR2312 and AR5312 both have the same ++ * revision information in the CPU :-( ++ */ ++ rev = (sysRegRead(AR531X_REV) & AR531X_REV_CHIP); ++ ++ if ((rev & AR531X_REV_MIN) == AR5312_REV_MIN_SINGLE_ENET) { ++ ar531x_num_enet_macs = 1; ++ } else { ++ ar531x_num_enet_macs = 2; ++ } ++#else ++ /* ++ * Need to select the number of ethernet MACs based on the config ++ * information (sadly) ++ */ ++#ifdef CONFIG_AR5312 ++ ar531x_num_enet_macs = 2; ++#else ++ ar531x_num_enet_macs = 1; ++#endif ++#endif ++ ++ next_dev = 0; ++ for (i=0; ipriv; ++ dev_sw_state->enetUnit = next_dev; ++ dev_sw_state->unit_on_MAC = 0; ++ MAC_state = &per_MAC_info[i]; ++ dev_sw_state->MAC_state = MAC_state; ++ MAC_state->dev_sw_state[AE531X_LAN_PORT] = dev_sw_state; ++ MAC_state->primary_dev = -1; ++ ++ next_dev++; ++ ++#ifdef CONFIG_VENETDEV ++ { ++ ae531x_dev_sw_state_t *lan_dev_sw_state; ++ ++ lan_dev_sw_state = dev_sw_state; ++ ++ dev = ae531x_MAC_dev[next_dev] = ++ init_etherdev(NULL, sizeof(ae531x_dev_sw_state_t)); ++ ++ if (dev == NULL) { ++ LEAVE(); ++ return -1; ++ } ++ ++ ae531x_MAC_setup_fntable(dev); ++ ++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; ++ dev_sw_state->enetUnit = next_dev; ++ dev_sw_state->unit_on_MAC = 1; ++ dev_sw_state->MAC_state = MAC_state; ++ MAC_state->dev_sw_state[AE531X_WAN_PORT] = dev_sw_state; ++ lan_dev_sw_state->isLAN = TRUE; /* enet0 is LAN */ ++ dev_sw_state->isLAN = FALSE ; /* enet1 is WAN */ ++ ++ next_dev++; ++ } ++#endif ++ ++ /* Initialize per-MAC information */ ++ MACInfo = &MAC_state->MACInfo; ++ MACInfo->unit = i; ++ ++ if (ar531x_num_enet_macs == 1) { ++ if (ae531x_twisted_enet()) { ++ MACInfo->macBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_MAC_OFFSET); ++ MACInfo->dmaBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_DMA_OFFSET); ++ MACInfo->phyBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); ++ MAC_state->irq = AR531X_IRQ_ENET1_INTRS; ++ } else { ++ MACInfo->macBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_MAC_OFFSET); ++ MACInfo->dmaBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_DMA_OFFSET); ++ MACInfo->phyBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); ++ MAC_state->irq = AR531X_IRQ_ENET0_INTRS; ++ } ++ } else { ++ if (MACInfo->unit == 0) { ++ MACInfo->macBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_MAC_OFFSET); ++ MACInfo->dmaBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_DMA_OFFSET); ++ MACInfo->phyBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); ++ MAC_state->irq = AR531X_IRQ_ENET0_INTRS; ++ } else { ++ MACInfo->macBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_MAC_OFFSET); ++ MACInfo->dmaBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_DMA_OFFSET); ++ MACInfo->phyBase = ++ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_PHY_OFFSET); ++ MAC_state->irq = AR531X_IRQ_ENET1_INTRS; ++ } ++ } ++ MACInfo->OSinfo = (void *)MAC_state; ++ } ++ ++ LEAVE(); ++ return 0; ++} ++ ++module_init(ae531x_MAC_setup); ++ +diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xmac.c linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.c +--- linux-2.4.32.new/arch/mips/ar531x/ae531xmac.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.c 2005-12-25 11:54:20.771271672 +0000 +@@ -0,0 +1,942 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++ ++/* ++ * Ethernet driver for Atheros' ae531x ethernet MAC. ++ */ ++ ++#if linux ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++#endif /* linux */ ++ ++#include "ae531xreg.h" ++#include "ae531xmac.h" ++ ++int ae531x_MAC_debug = AE531X_DEBUG_ERROR; ++ ++/* ++ * These externs are for functions that this layer relies on ++ * that have OS-dependent implementations. ++ */ ++extern UINT8 *macAddrGet(ae531x_MAC_t *MACInfo); ++ ++/* Forward references to local functions */ ++static void ae531x_QueueDestroy(AE531X_QUEUE *q); ++ ++ ++/****************************************************************************** ++* ++* ae531x_ReadMacReg - read AE MAC register ++* ++* RETURNS: register value ++*/ ++UINT32 ++ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg) ++{ ++ UINT32 addr = MACInfo->macBase+reg; ++ UINT32 data; ++ ++ data = RegRead(addr); ++ return data; ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_WriteMacReg - write AE MAC register ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data) ++{ ++ UINT32 addr = MACInfo->macBase+reg; ++ ++ RegWrite(data, addr); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_SetMacReg - set bits in AE MAC register ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) ++{ ++ UINT32 addr = MACInfo->macBase+reg; ++ UINT32 data = RegRead(addr); ++ ++ data |= val; ++ RegWrite(data, addr); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_ClearMacReg - clear bits in AE MAC register ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) ++{ ++ UINT32 addr = MACInfo->macBase+reg; ++ UINT32 data = RegRead(addr); ++ ++ data &= ~val; ++ RegWrite(data, addr); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_ReadDmaReg - read AE DMA register ++* ++* RETURNS: register value ++*/ ++UINT32 ++ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg) ++{ ++ UINT32 addr = MACInfo->dmaBase+reg; ++ UINT32 data = RegRead(addr); ++ ++ return data; ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_WriteDmaReg - write AE DMA register ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data) ++{ ++ UINT32 addr = MACInfo->dmaBase+reg; ++ ++ RegWrite(data, addr); ++} ++ ++ ++/****************************************************************************** ++ * ++ * ae531x_AckIntr - clear interrupt bits in the status register. ++ * Note: Interrupt bits are *cleared* by writing a 1. ++ */ ++void ++ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 data) ++{ ++ ae531x_WriteDmaReg(MACInfo, DmaStatus, data); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_SetDmaReg - set bits in an AE DMA register ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) ++{ ++ UINT32 addr = MACInfo->dmaBase+reg; ++ UINT32 data = RegRead(addr); ++ ++ data |= val; ++ RegWrite(data, addr); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_ClearDmaReg - clear bits in an AE DMA register ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) ++{ ++ UINT32 addr = MACInfo->dmaBase+reg; ++ UINT32 data = RegRead(addr); ++ ++ data &= ~val; ++ RegWrite(data, addr); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_ReadMiiReg - read PHY registers via AE MAC Mii addr/data registers ++* ++* RETURNS: register value ++*/ ++UINT32 ++ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg) ++{ ++ UINT32 data; ++ UINT32 addr = phyBase+reg; ++ ++ data = RegRead(addr); ++ return data; ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_WriteMiiReg - write PHY registers via AE MAC Mii addr/data registers ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data) ++{ ++ UINT32 addr = phyBase+reg; ++ ++ RegWrite(data, addr); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_MiiRead - read AE Mii register ++* ++* RETURNS: register value ++*/ ++UINT16 ++ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg) ++{ ++ UINT32 addr; ++ UINT16 data; ++ ++ addr = ((phyAddr << MiiDevShift) & MiiDevMask) | ((reg << MiiRegShift) & MiiRegMask); ++ ++ ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr ); ++ do { ++ /* nop */ ++ } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy); ++ ++ data = ae531x_ReadMiiReg(phyBase, MacMiiData) & 0xFFFF; ++ ++ return data; ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_MiiWrite - write AE Mii register ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data) ++{ ++ UINT32 addr; ++ ++ ae531x_WriteMiiReg(phyBase, MacMiiData, data ); ++ ++ addr = ((phyAddr << MiiDevShift) & MiiDevMask) | ++ ((reg << MiiRegShift) & MiiRegMask) | MiiWrite; ++ ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr ); ++ ++ do { ++ /* nop */ ++ } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy); ++} ++ ++ ++/******************************************************************************* ++* ae531x_BeginResetMode - enter a special "reset mode" in which ++* -no interrupts are expected from the device ++* -the device will not transmit nor receive ++* -attempts to send or receive will return with an error and ++* -the device will be reset at the next convenient opportunity. ++*/ ++void ++ae531x_BeginResetMode(ae531x_MAC_t *MACInfo) ++{ ++ /* Set the reset flag */ ++ MACInfo->aeProcessRst = 1; ++} ++ ++ ++/******************************************************************************* ++* ae531x_EndResetMode - exit the special "reset mode" entered ++* earlier via a call to ae531x_BeginResetMode. ++*/ ++void ++ae531x_EndResetMode(ae531x_MAC_t *MACInfo) ++{ ++ MACInfo->aeProcessRst = 0; ++} ++ ++ ++/******************************************************************************* ++* ae531x_IsInResetMode - determine whether or not the device is ++* currently in "reset mode" (i.e. that a device reset is pending) ++*/ ++BOOL ++ae531x_IsInResetMode(ae531x_MAC_t *MACInfo) ++{ ++ return MACInfo->aeProcessRst; ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_DmaRxStart - Start Rx ++* ++* RETURNS: N/A ++*/ ++static void ++ae531x_DmaRxStart(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_SetDmaReg(MACInfo, DmaControl, DmaRxStart); ++ sysWbFlush(); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_DmaRxStop - Stop Rx ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_DmaRxStop(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_ClearDmaReg(MACInfo, DmaControl, DmaRxStart); ++ sysWbFlush(); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_DmaTxStart - Start Tx ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_DmaTxStart(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_SetDmaReg(MACInfo, DmaControl, DmaTxStart); ++ sysWbFlush(); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_DmaTxStop - Stop Tx ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_DmaTxStop(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_ClearDmaReg(MACInfo, DmaControl, DmaTxStart); ++ sysWbFlush(); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_DmaIntEnable - Enable DMA interrupts ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntEnable); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_DmaIntDisable - Disable DMA interrupts ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_DmaIntClear - Clear DMA interrupts ++* ++* RETURNS: N/A ++*/ ++static void ++ae531x_DmaIntClear(ae531x_MAC_t *MACInfo) ++{ ++ /* clear all interrupt requests */ ++ ae531x_WriteDmaReg(MACInfo, DmaStatus, ++ ae531x_ReadDmaReg(MACInfo, DmaStatus)); ++} ++ ++ ++/****************************************************************************** ++* Initialize generic queue data ++*/ ++void ++ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count) ++{ ++ ARRIVE(); ++ q->firstDescAddr = pMem; ++ q->lastDescAddr = (VIRT_ADDR)((UINT32)q->firstDescAddr + ++ (count - 1) * AE531X_QUEUE_ELE_SIZE); ++ q->curDescAddr = q->firstDescAddr; ++ q->count = count; ++ LEAVE(); ++} ++ ++ ++/****************************************************************************** ++* ae531x_TxQueueCreate - create a circular queue of descriptors for Transmit ++*/ ++static int ++ae531x_TxQueueCreate(ae531x_MAC_t *MACInfo, ++ AE531X_QUEUE *q, ++ char *pMem, ++ int count) ++{ ++ int i; ++ VIRT_ADDR descAddr; ++ ++ ARRIVE(); ++ ++ ae531x_QueueInit(q, pMem, count); ++ q->reapDescAddr = q->lastDescAddr; ++ ++ /* Initialize Tx buffer descriptors. */ ++ for (i=0, descAddr=q->firstDescAddr; ++ ilastDescAddr, ++ DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr)); ++ ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Txbuf begin = %x, end = %x\n", ++ MACInfo->unit, ++ (UINT32)q->firstDescAddr, ++ (UINT32)q->lastDescAddr)); ++ ++ LEAVE(); ++ return 0; ++} ++ ++ ++/****************************************************************************** ++* ae531x_RxQueueCreate - create a circular queue of Rx descriptors ++*/ ++int ++ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo, ++ AE531X_QUEUE *q, ++ char *pMem, ++ int count) ++{ ++ int i; ++ VIRT_ADDR descAddr; ++ ++ ARRIVE(); ++ ++ ae531x_QueueInit(q, pMem, count); ++ q->reapDescAddr = NULL; ++ ++ ++ /* Initialize Rx buffer descriptors */ ++ for (i=0, descAddr=q->firstDescAddr; ++ iunit)); ++ ae531x_QueueDestroy(q); ++ return -1; ++ } ++ AE531X_DESC_SWPTR_SET(descAddr, swptr); ++ ++ AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma); ++ AE531X_DESC_CTRLEN_SET(descAddr, rxBufferSize); ++ AE531X_DESC_BUFPTR_SET(descAddr, virt_to_bus(rxBuffer)); ++ AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0); ++ } /* for each desc */ ++ ++ /* Make the queue circular */ ++ AE531X_DESC_CTRLEN_SET(q->lastDescAddr, ++ DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr)); ++ ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Rxbuf begin = %x, end = %x\n", ++ MACInfo->unit, ++ (UINT32)q->firstDescAddr, ++ (UINT32)q->lastDescAddr)); ++ ++ LEAVE(); ++ return 0; ++} ++ ++ ++/****************************************************************************** ++* ae531x_QueueDestroy -- Free all buffers and descriptors associated ++* with a queue. ++*/ ++static void ++ae531x_QueueDestroy(AE531X_QUEUE *q) ++{ ++ int i; ++ int count; ++ VIRT_ADDR descAddr; ++ ++ ARRIVE(); ++ ++ count = q->count; ++ ++ for (i=0, descAddr=q->firstDescAddr; ++ itxQueue); ++} ++ ++static void ++ae531x_RxQueueDestroy(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_QueueDestroy(&MACInfo->rxQueue); ++} ++ ++ ++/****************************************************************************** ++* ae531x_AllocateQueues - Allocate receive and transmit queues ++*/ ++int ++ae531x_AllocateQueues(ae531x_MAC_t *MACInfo) ++{ ++ size_t QMemSize; ++ char *pTxBuf = NULL; ++ char *pRxBuf = NULL; ++ ++ ARRIVE(); ++ ++ MACInfo->txDescCount = AE531X_TX_DESC_COUNT_DEFAULT; ++ QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->txDescCount; ++ pTxBuf = MALLOC(QMemSize); ++ if (pTxBuf == NULL) { ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Failed to allocate TX queue\n", MACInfo->unit)); ++ goto AllocQFail; ++ } ++ ++ if (ae531x_TxQueueCreate(MACInfo, &MACInfo->txQueue, pTxBuf, ++ MACInfo->txDescCount) < 0) ++ { ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Failed to create TX queue\n", MACInfo->unit)); ++ goto AllocQFail; ++ } ++ ++ MACInfo->rxDescCount = AE531X_RX_DESC_COUNT_DEFAULT; ++ QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->rxDescCount; ++ pRxBuf = MALLOC(QMemSize); ++ if (pRxBuf == NULL) { ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Failed to allocate RX queue\n", MACInfo->unit)); ++ goto AllocQFail; ++ } ++ ++ if (ae531x_RxQueueCreate(MACInfo, &MACInfo->rxQueue, pRxBuf, ++ MACInfo->rxDescCount) < 0) ++ { ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Failed to create RX queue\n", MACInfo->unit)); ++ goto AllocQFail; ++ } ++ ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Memory setup complete.\n", MACInfo->unit)); ++ ++ LEAVE(); ++ return 0; ++ ++AllocQFail: ++ MACInfo->txDescCount = 0; /* sanity */ ++ MACInfo->rxDescCount = 0; /* sanity */ ++ ++ if (pTxBuf) { ++ FREE(pTxBuf); ++ } ++ if (pRxBuf) { ++ FREE(pRxBuf); ++ } ++ ++ LEAVE(); ++ return -1; ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_FreeQueues - Free Transmit & Receive queues ++*/ ++void ++ae531x_FreeQueues(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_TxQueueDestroy(MACInfo); ++ FREE(MACInfo->txQueue.firstDescAddr); ++ ++ ae531x_RxQueueDestroy(MACInfo); ++ FREE(MACInfo->rxQueue.firstDescAddr); ++} ++ ++/****************************************************************************** ++* ++* ae531x_DmaReset - Reset DMA and TLI controllers ++* ++* RETURNS: N/A ++*/ ++void ++ae531x_DmaReset(ae531x_MAC_t *MACInfo) ++{ ++ int i; ++ UINT32 descAddr; ++ ++ ARRIVE(); ++ ++ /* Disable device interrupts prior to any errors during stop */ ++ intDisable(MACInfo->ilevel); ++ ++ /* Disable MAC rx and tx */ ++ ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable)); ++ ++ /* Reset dma controller */ ++ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaResetOn); ++ ++ /* Delay 2 usec */ ++ sysUDelay(2); ++ ++ /* Flush the rx queue */ ++ descAddr = (UINT32)MACInfo->rxQueue.firstDescAddr; ++ MACInfo->rxQueue.curDescAddr = MACInfo->rxQueue.firstDescAddr; ++ for (i=0; ++ i<(MACInfo->rxDescCount); ++ i++, descAddr += AE531X_QUEUE_ELE_SIZE) { ++ AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma); ++ } ++ ++ /* Flush the tx queue */ ++ descAddr = (UINT32)MACInfo->txQueue.firstDescAddr; ++ MACInfo->txQueue.curDescAddr = MACInfo->txQueue.firstDescAddr; ++ MACInfo->txQueue.reapDescAddr = MACInfo->txQueue.lastDescAddr; ++ for (i=0; ++ i<(MACInfo->txDescCount); ++ i++, descAddr += AE531X_QUEUE_ELE_SIZE) { ++ AE531X_DESC_STATUS_SET (descAddr, 0); ++ } ++ ++ /* Set init register values */ ++ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaBusModeInit); ++ ++ /* Install the first Tx and Rx queues on the device */ ++ ae531x_WriteDmaReg(MACInfo, DmaRxBaseAddr, ++ (UINT32)MACInfo->rxQueue.firstDescAddr); ++ ae531x_WriteDmaReg(MACInfo, DmaTxBaseAddr, ++ (UINT32)MACInfo->txQueue.firstDescAddr); ++ ++ ae531x_WriteDmaReg(MACInfo, DmaControl, DmaStoreAndForward); ++ ++ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable); ++ ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d: DMA RESET!\n", MACInfo->unit)); ++ ++ /* Turn on device interrupts -- enable most errors */ ++ ae531x_DmaIntClear(MACInfo); /* clear interrupt requests */ ++ ae531x_DmaIntEnable(MACInfo); /* enable interrupts */ ++ /* Enable receive interrupts separately (they are not part ++ * of the main group since they are enabled & disabled by ++ * the polling routine. ++ */ ++ ae531x_SetDmaReg(MACInfo, DmaIntrEnb, ++ (DmaIntRxNoBuffer | DmaIntRxCompleted)); ++ ++ ae531x_EndResetMode(MACInfo); ++ ++ intEnable(MACInfo->ilevel); ++ ++ LEAVE(); ++} ++ ++ ++/****************************************************************************** ++* ++* ae531x_MACAddressSet - Set the ethernet address ++* ++* Sets the ethernet address according to settings in flash. ++* ++* RETURNS: void ++*/ ++static void ++ae531x_MACAddressSet(ae531x_MAC_t *MACInfo) ++{ ++ unsigned int data; ++ UINT8 *macAddr; ++ ++ ARRIVE(); ++ ++ macAddr = macAddrGet(MACInfo); ++ ++ /* set our MAC address */ ++ data = (macAddr[5]<<8) | macAddr[4]; ++ ae531x_WriteMacReg(MACInfo, MacAddrHigh, data ); ++ ++ data = (macAddr[3]<<24) | (macAddr[2]<<16) | (macAddr[1]<<8) | macAddr[0]; ++ ae531x_WriteMacReg(MACInfo, MacAddrLow, data ); ++ ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ ("ethmac%d Verify MAC address %8.8X %8.8X \n", ++ MACInfo->unit, ++ ae531x_ReadMacReg(MACInfo, MacAddrLow), ++ ae531x_ReadMacReg(MACInfo, MacAddrHigh))); ++ ++ AE531X_PRINT(AE531X_DEBUG_RESET, ++ (" sb = %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", ++ 0xff&macAddr[0], ++ 0xff&macAddr[1], ++ 0xff&macAddr[2], ++ 0xff&macAddr[3], ++ 0xff&macAddr[4], ++ 0xff&macAddr[5])); ++ LEAVE(); ++} ++ ++ ++/****************************************************************************** ++* ++* ae_SetMACFromPhy - read Phy settings and update Mac ++* with current duplex and speed. ++* ++* RETURNS: ++*/ ++static void ++ae531x_SetMACFromPhy(ae531x_MAC_t *MACInfo) ++{ ++ UINT32 macCtl; ++ BOOL fullDuplex; ++ ++ ARRIVE(); ++ ++ /* Get duplex mode from Phy */ ++ fullDuplex = phyIsFullDuplex(MACInfo->unit); ++ ++ /* Flag is set for full duplex mode, else cleared */ ++ macCtl = ae531x_ReadMacReg(MACInfo, MacControl); ++ ++ if (fullDuplex) { ++ /* set values of control registers */ ++ macCtl &= ~MacDisableRxOwn; ++ macCtl |= MacFullDuplex; ++ ae531x_WriteMacReg(MACInfo, MacControl, macCtl); ++ ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitFdx); ++#if 0 ++ printk ("[Full Duplex] CTRL=%#x FLOW=%#x\n", macCtl, ++ MacFlowControlInitFdx); ++#endif ++ } else { ++ /* set values of control registers */ ++ ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitHdx); ++ macCtl |= MacDisableRxOwn; ++ macCtl &= ~MacFullDuplex; ++ ae531x_WriteMacReg(MACInfo, MacControl, macCtl); ++#if 0 ++ printk ("[Half Duplex] CTRL=%#x FLOW=%#x\n", macCtl, ++ MacFlowControlInitHdx); ++#endif ++ } ++ ++ LEAVE(); ++} ++ ++ ++/****************************************************************************** ++* ae531x_MACReset -- sets MAC address and duplex. ++*/ ++void ++ae531x_MACReset(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_MACAddressSet(MACInfo); ++ ++ ae531x_SetMACFromPhy(MACInfo); ++} ++ ++ ++/****************************************************************************** ++* ae531x_EnableComm -- enable Transmit and Receive ++*/ ++void ++ae531x_EnableComm(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_SetMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable)); ++ ae531x_DmaRxStart(MACInfo); /* start receiver */ ++ ae531x_DmaTxStart(MACInfo); /* start transmitter */ ++} ++ ++ ++/****************************************************************************** ++* ae531x_DisableComm -- disable Transmit and Receive ++*/ ++void ++ae531x_DisableComm(ae531x_MAC_t *MACInfo) ++{ ++ ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable)); ++} ++ ++ ++/****************************************************************************** ++* ae531x_reset -- Cold reset ethernet interface ++*/ ++void ++ae531x_reset(ae531x_MAC_t *MACInfo) ++{ ++ UINT32 mask = 0; ++ UINT32 regtmp; ++ ++ if (ar531x_num_enet_macs == 2) { ++ if (MACInfo->unit == 0) { ++ mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0; ++ } else { ++ mask = AR531X_RESET_ENET1 | AR531X_RESET_EPHY1; ++ } ++ } else { ++ mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0 | ++ AR531X_RESET_ENET1 | AR531X_RESET_EPHY1; ++ } ++ ++ /* Put into reset */ ++ regtmp = sysRegRead(AR531X_RESET); ++ sysRegWrite(AR531X_RESET, regtmp | mask); ++ sysMsDelay(15); ++ ++ /* Pull out of reset */ ++ regtmp = sysRegRead(AR531X_RESET); ++ sysRegWrite(AR531X_RESET, regtmp & ~mask); ++ sysUDelay(25); ++ ++ /* Enable */ ++ if (ar531x_num_enet_macs == 2) { ++ if (MACInfo->unit == 0) { ++ mask = AR531X_ENABLE_ENET0; ++ } else { ++ mask = AR531X_ENABLE_ENET1; ++ } ++ } else { ++ mask = AR531X_ENABLE_ENET0 | AR531X_ENABLE_ENET1; ++ } ++ regtmp = sysRegRead(AR531X_ENABLE); ++ sysRegWrite(AR531X_ENABLE, regtmp | mask); ++} ++ ++ ++/****************************************************************************** ++* ae531x_unitLinkLost -- Called from PHY layer to notify the MAC layer ++* that there are no longer any live links associated with a MAC. ++*/ ++void ++ae531x_unitLinkLost(int ethUnit) ++{ ++ AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE, ++ ("enetmac%d link down\n", ethUnit)); ++} ++ ++ ++/****************************************************************************** ++* ae531x_unitLinkGained -- Called from PHY layer to notify the MAC layer ++* that there are 1 or more live links associated with a MAC. ++*/ ++void ++ae531x_unitLinkGained(int ethUnit) ++{ ++ AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE, ++ ("enet%d link up\n", ethUnit)); ++} ++ ++/****************************************************************************** ++* ae531x_ethMacDefault -- Called from PHY layer to determine the default ++* ethernet MAC. On some "twisted" platforms, the only usable MAC is 1, ++* while on others the usable MAC is 0. Future boards may allow both MACs ++* to be used; in this case, return -1 to indicate that there IS NO default ++* MAC. ++* ++* Note: one some AR2312 platforms the PHY needs to be accessed through ++* MAC 0, even though the MAC itself is addressed through MAC 1. Since this ++* function is used by the PHY layer to determine which MAC it should use, ++* the twisted case is limited to the one where the PHY is actually addressed ++* through MAC 1 rather than MAC 0. ++*/ ++int ++ae531x_ethMacDefault(void) ++{ ++ /* ++ * Where there are two MACs, there is no real default ++ */ ++ if (ar531x_num_enet_macs == 2) ++ return -1; ++ ++ /* ++ * All single MAC platforms seem to address the PHY through MAC 0, ++ * even when they use MAC 1 for the actual MAC functions. ++ */ ++ return 0; ++} +diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xmac.h linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.h +--- linux-2.4.32.new/arch/mips/ar531x/ae531xmac.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.h 2005-12-25 11:54:20.819264376 +0000 +@@ -0,0 +1,208 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * See README to understand the decomposition of the ethernet driver. ++ * ++ * This file contains OS-independent pure software definitions for ++ * ethernet support on the AR531X platform. ++ */ ++ ++#ifndef _AE531XMAC_H_ ++#define _AE531XMAC_H_ ++ ++/* ++ * DEBUG switches to control verbosity. ++ * Just modify the value of ae531x_MAC_debug. ++ */ ++#define AE531X_DEBUG_ALL 0xffffffff ++#define AE531X_DEBUG_ERROR 0x00000001 /* Unusual conditions and Errors */ ++#define AE531X_DEBUG_ARRIVE 0x00000002 /* Arrive into a function */ ++#define AE531X_DEBUG_LEAVE 0x00000004 /* Leave a function */ ++#define AE531X_DEBUG_RESET 0x00000008 /* Reset */ ++#define AE531X_DEBUG_TX 0x00000010 /* Transmit */ ++#define AE531X_DEBUG_TX_REAP 0x00000020 /* Transmit Descriptor Reaping */ ++#define AE531X_DEBUG_RX 0x00000040 /* Receive */ ++#define AE531X_DEBUG_RX_STOP 0x00000080 /* Receive Early Stop */ ++#define AE531X_DEBUG_INT 0x00000100 /* Interrupts */ ++#define AE531X_DEBUG_LINK_CHANGE 0x00000200 /* PHY Link status changed */ ++ ++extern int ae531x_MAC_debug; ++ ++extern int ar531x_num_enet_macs; ++ ++#define AE531X_PRINT(FLG, X) \ ++{ \ ++ if (ae531x_MAC_debug & (FLG)) { \ ++ DEBUG_PRINTF("%s#%d:%s ", \ ++ __FILE__, \ ++ __LINE__, \ ++ __FUNCTION__); \ ++ DEBUG_PRINTF X; \ ++ } \ ++} ++ ++#define ARRIVE() AE531X_PRINT(AE531X_DEBUG_ARRIVE, ("Arrive{\n")) ++#define LEAVE() AE531X_PRINT(AE531X_DEBUG_LEAVE, ("}Leave\n")) ++ ++#define RegRead(addr) \ ++ (*(volatile unsigned int *)(addr)) ++ ++#define RegWrite(val,addr) \ ++ ((*(volatile unsigned int *)(addr)) = (val)) ++ ++/***************************************************************** ++ * Phy code is broken out into a separate layer, so that different ++ * PHY hardware can easily be supported. ++ * ++ * These functions are provided by the PHY layer for use by the MAC layer. ++ * phySetup -- Set phy hardware appropriately for a MAC unit ++ * ++ * phyCheckStatusChange -- Look for dropped/initiated links on any ++ * phy port associated with a MAC unit ++ * ++ * phyIsSpeed100 -- Determines whether or not a PHY is up and ++ * running at 100Mbit ++ * ++ * phyIsFullDuplex -- Determines whether or not a PHY is up and ++ * running in Full Duplex mode ++ * ++ */ ++#ifdef CONFIG_MARVELL_ENET_PHY ++/* ++ * Mapping of generic phy APIs to Marvell Ethernet Switch phy functions. ++ */ ++#include "mvPhy.h" ++#define phySetup(ethUnit, phyBase) mv_phySetup((ethUnit), (phyBase)) ++#define phyCheckStatusChange(ethUnit) mv_phyCheckStatusChange(ethUnit) ++#define phyIsSpeed100(ethUnit) mv_phyIsSpeed100(ethUnit) ++#define phyIsFullDuplex(ethUnit) mv_phyIsFullDuplex(ethUnit) ++ ++#ifdef CONFIG_VENETDEV ++#define PHY_TRAILER_SIZE MV_PHY_TRAILER_SIZE ++extern int mv_phyDetermineSource(char *data, int len); ++extern void mv_phySetDestinationPort(char *data, int len, int fromLAN); ++#define phyDetermineSource(data, len) mv_phyDetermineSource((data), (len)) ++#define phySetDestinationPort(data, len, fromLAN) mv_phySetDestinationPort((data), (len), (fromLAN)) ++#else ++#define PHY_TRAILER_SIZE 0 ++#endif ++#endif /* CONFIG_MARVELL_ENET_PHY */ ++ ++#if defined(CONFIG_KENDIN_ENET_PHY) || defined(CONFIG_REALTEK_ENET_PHY) ++/* ++ * Mapping of generic phy APIs to Kendin KS8721B and RealTek RTL8201BL phys. ++ */ ++#include "rtPhy.h" ++#define phySetup(ethUnit, phyBase) rt_phySetup((ethUnit), (phyBase)) ++#define phyCheckStatusChange(ethUnit) rt_phyCheckStatusChange(ethUnit) ++#define phyIsSpeed100(ethUnit) rt_phyIsSpeed100(ethUnit) ++#define phyIsFullDuplex(ethUnit) rt_phyIsFullDuplex(ethUnit) ++#endif ++ ++#if !defined(PHY_TRAILER_SIZE) ++#define PHY_TRAILER_SIZE 0 ++#endif ++ ++/***************************************************************** ++ * MAC-independent interface to be used by PHY code ++ * ++ * These functions are provided by the MAC layer for use by the PHY layer. ++ */ ++#define phyRegRead ae531x_MiiRead ++#define phyRegWrite ae531x_MiiWrite ++#define phyLinkLost(ethUnit) ae531x_unitLinkLost(ethUnit) ++#define phyLinkGained(ethUnit) ae531x_unitLinkGained(ethUnit) ++#define phyEthMacDefault() ae531x_ethMacDefault() ++ ++void ae531x_unitLinkLost(int unit); ++void ae531x_unitLinkGained(int unit); ++int ae531x_ethMacDefault(void); ++ ++ ++/* RXBUFF_RESERVE enables building header on WLAN-side in place */ ++#define RXBUFF_RESERVE 96 ++#define ETH_CRC_LEN 4 ++ ++/***************************************************************** ++ * Descriptor queue ++ */ ++typedef struct ae531x_queue { ++ VIRT_ADDR firstDescAddr; /* descriptor array address */ ++ VIRT_ADDR lastDescAddr; /* last descriptor address */ ++ VIRT_ADDR curDescAddr; /* current descriptor address */ ++ VIRT_ADDR reapDescAddr; /* current tail of tx descriptors reaped */ ++ UINT16 count; /* number of elements */ ++} AE531X_QUEUE; ++ ++/* Given a descriptor, return the next one in a circular list */ ++#define AE531X_QUEUE_ELE_NEXT_GET(q, descAddr) \ ++ ((descAddr) == (q)->lastDescAddr) ? (q)->firstDescAddr : \ ++ (VIRT_ADDR)((UINT32)(descAddr) + AE531X_QUEUE_ELE_SIZE) ++ ++/* Move the "current descriptor" forward to the next one */ ++#define AE531X_CONSUME_DESC(q) \ ++ q->curDescAddr = AE531X_QUEUE_ELE_NEXT_GET(q, q->curDescAddr) ++ ++/***************************************************************** ++ * Per-ethernet-MAC OS-independent information ++ */ ++typedef struct ae531x_MAC_s { ++ u32 unit; /* MAC unit ID */ ++ u32 macBase; /* MAC base address */ ++ u32 dmaBase; /* DMA base address */ ++ u32 phyBase; /* PHY base address */ ++ AE531X_QUEUE txQueue; /* Transmit descriptor queue */ ++ AE531X_QUEUE rxQueue; /* Receive descriptor queue */ ++ UINT16 txDescCount; /* Transmit descriptor count */ ++ UINT16 rxDescCount; /* Receive descriptor count */ ++ BOOL aeProcessRst; /* flag to indicate reset in progress */ ++ BOOL port_is_up; /* flag to indicate port is up */ ++ void *OSinfo; /* OS-dependent data */ ++} ae531x_MAC_t; ++ ++#define AE531X_TX_DESC_COUNT_DEFAULT 64 /* Transmit descriptors */ ++#define AE531X_RX_DESC_COUNT_DEFAULT 64 /* Receive descriptors */ ++ ++ ++/***************************************************************** ++ * Interfaces exported by the OS-independent MAC layer ++ */ ++void ae531x_BeginResetMode(ae531x_MAC_t *MACInfo); ++void ae531x_EndResetMode(ae531x_MAC_t *MACInfo); ++BOOL ae531x_IsInResetMode(ae531x_MAC_t *MACInfo); ++int ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo, AE531X_QUEUE *q, ++ char *pMem, int count); ++int ae531x_QueueDelete(struct ae531x_queue *q); ++void ae531x_DmaReset(ae531x_MAC_t *MACInfo); ++void ae531x_MACReset(ae531x_MAC_t *MACInfo); ++void ae531x_EnableComm(ae531x_MAC_t *MACInfo); ++void ae531x_DisableComm(ae531x_MAC_t *MACInfo); ++void ae531x_reset(ae531x_MAC_t *MACInfo); ++int ae531x_AllocateQueues(ae531x_MAC_t *MACInfo); ++void ae531x_FreeQueues(ae531x_MAC_t *MACInfo); ++void ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count); ++UINT32 ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg); ++void ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data); ++void ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); ++void ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); ++void ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); ++void ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); ++UINT32 ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg); ++void ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data); ++UINT32 ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg); ++void ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data); ++UINT16 ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg); ++void ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data); ++void ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo); ++void ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo); ++void ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 val); ++void *ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBptr, int *rxBSize); ++void ae531x_swptr_free(VIRT_ADDR txDesc); ++ ++#endif /* _AE531XMAC_H_ */ +diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xreg.h linux-2.4.32.new-eth/arch/mips/ar531x/ae531xreg.h +--- linux-2.4.32.new/arch/mips/ar531x/ae531xreg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xreg.h 2005-12-25 11:54:20.834262096 +0000 +@@ -0,0 +1,437 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * See README to understand the decomposition of the ethernet driver. ++ * ++ * Register definitions for Atheros AR531X Ethernet MAC. ++ */ ++ ++#ifndef _AE531XREG_H_ ++#define _AE531XREG_H_ ++ ++#define AE531X_MAC_OFFSET 0x0000 ++#define AE531X_PHY_OFFSET 0x0000 /* Same as MAC offset */ ++#define AE531X_DMA_OFFSET 0x1000 ++ ++/***********************************************************/ ++/* MAC110 registers, base address is BAR+AE531X_MAC_OFFSET */ ++/***********************************************************/ ++#define MacControl 0x00 /* control */ ++#define MacAddrHigh 0x04 /* address high */ ++#define MacAddrLow 0x08 /* address low */ ++#define MacMultiHashHigh 0x0C /* multicast hash table high */ ++#define MacMultiHashLow 0x10 /* multicast hash table low */ ++#define MacMiiAddr 0x14 /* MII address */ ++#define MacMiiData 0x18 /* MII data */ ++#define MacFlowControl 0x1C /* Flow control */ ++#define MacVlan1Tag 0x4C /* VLAN1 tag */ ++#define MacVlan2Tag 0x50 /* VLAN2 tag */ ++ ++ ++/***************************************************************/ ++/* DMA engine registers, base address is BAR+AE531X_DMA_OFFSET */ ++/***************************************************************/ ++#define DmaBusMode 0x00 /* CSR0 - Bus Mode */ ++#define DmaTxPollDemand 0x04 /* CSR1 - Transmit Poll Demand */ ++#define DmaRxPollDemand 0x08 /* CSR2 - Receive Poll Demand */ ++#define DmaRxBaseAddr 0x0C /* CSR3 - Receive list base address */ ++#define DmaTxBaseAddr 0x10 /* CSR4 - Transmit list base address */ ++#define DmaStatus 0x14 /* CSR5 - Dma status */ ++#define DmaControl 0x18 /* CSR6 - Dma control */ ++#define DmaIntrEnb 0x1C /* CSR7 - Interrupt enable */ ++#define DmaOverflowCnt 0x20 /* CSR8 - Missed Frame and Buff Overflow counter */ ++#define DmaTxCurrAddr 0x50 /* CSR20 - Current host transmit buffer address */ ++#define DmaRxCurrAddr 0x54 /* CSR21 - Current host receive buffer address */ ++ ++/**********************************************************/ ++/* MAC Control register layout */ ++/**********************************************************/ ++#define MacFilterOff 0x80000000 /* Receive all incoming packets RW */ ++#define MacFilterOn 0 /* Receive filtered packets only 0 */ ++#define MacBigEndian 0x40000000 /* Big endian mode RW */ ++#define MacLittleEndian 0 /* Little endian 0 */ ++#define MacHeartBeatOff 0x10000000 /* Heartbeat signal qual disable RW*/ ++#define MacHeartBeatOn 0 /* Heartbeat signal qual enable 0 */ ++#define MacSelectSrl 0x08000000 /* Select SRL port RW */ ++#define MacSelectMii 0 /* Select MII port 0 */ ++#define MacDisableRxOwn 0x00800000 /* Disable receive own packets RW */ ++#define MacEnableRxOwn 0 /* Enable receive own packets 0 */ ++#define MacLoopbackExt 0x00400000 /* External loopback RW */ ++#define MacLoopbackInt 0x00200000 /* Internal loopback */ ++#define MacLoopbackOff 0 /* Normal mode 00 */ ++#define MacFullDuplex 0x00100000 /* Full duplex mode RW */ ++#define MacHalfDuplex 0 /* Half duplex mode 0 */ ++#define MacMulticastFilterOff 0x00080000 /* Pass all multicast packets RW */ ++#define MacMulticastFilterOn 0 /* Pass filtered mcast packets 0 */ ++#define MacPromiscuousModeOn 0x00040000 /* Receive all valid packets RW 1 */ ++#define MacPromiscuousModeOff 0 /* Receive filtered packets only */ ++#define MacFilterInverse 0x00020000 /* Inverse filtering RW */ ++#define MacFilterNormal 0 /* Normal filtering 0 */ ++#define MacBadFramesEnable 0x00010000 /* Pass bad frames RW */ ++#define MacBadFramesDisable 0 /* Do not pass bad frames 0 */ ++#define MacPerfectFilterOff 0x00008000 /* Hash filtering only RW */ ++#define MacPerfectFilterOn 0 /* Both perfect and hash filtering 0 */ ++#define MacHashFilterOn 0x00002000 /* perform hash filtering RW */ ++#define MacHashFilterOff 0 /* perfect filtering only 0 */ ++#define MacLateCollisionOn 0x00001000 /* Enable late collision control RW */ ++#define MacLateCollisionOff 0 /* Disable late collision control 0 */ ++#define MacBroadcastDisable 0x00000800 /* Disable reception of bcast frames RW */ ++#define MacBroadcastEnable 0 /* Enable broadcast frames 0 */ ++#define MacRetryDisable 0x00000400 /* Disable retransmission RW */ ++#define MacRetryEnable 0 /* Enable retransmission 0 */ ++#define MacPadStripEnable 0x00000100 /* Pad stripping enable RW */ ++#define MacPadStripDisable 0 /* Pad stripping disable 0 */ ++#define MacBackoff 0 /* Backoff Limit RW 00 */ ++#define MacDeferralCheckEnable 0x00000020 /* Deferral check enable RW */ ++#define MacDeferralCheckDisable 0 /* Deferral check disable 0 */ ++#define MacTxEnable 0x00000008 /* Transmitter enable RW */ ++#define MacTxDisable 0 /* Transmitter disable 0 */ ++#define MacRxEnable 0x00000004 /* Receiver enable RW */ ++#define MacRxDisable 0 /* Receiver disable 0 */ ++ ++ ++/**********************************************************/ ++/* MII address register layout */ ++/**********************************************************/ ++#define MiiDevMask 0x0000F800 /* MII device address */ ++#define MiiDevShift 11 ++#define MiiRegMask 0x000007C0 /* MII register */ ++#define MiiRegShift 6 ++#define MiiWrite 0x00000002 /* Write to register */ ++#define MiiRead 0 /* Read from register */ ++#define MiiBusy 0x00000001 /* MII interface is busy */ ++ ++/**********************************************************/ ++/* MII Data register layout */ ++/**********************************************************/ ++#define MiiDataMask 0x0000FFFF /* MII Data */ ++ ++/**********************************************************/ ++/* MAC flow control register layout */ ++/**********************************************************/ ++#define MacPauseTimeMask 0xFFFF0000 /* PAUSE TIME field in ctrl frame */ ++#define MacPauseTimeShift 15 ++#define MacControlFrameEnable 0x00000004 /* Enable pass ctrl frames to host */ ++#define MacControlFrameDisable 0 /* Do not pass ctrl frames to host */ ++#define MacFlowControlEnable 0x00000002 /* Enable flow control */ ++#define MacFlowControlDisable 0 /* Disable flow control */ ++#define MacSendPauseFrame 0x00000001 /* send pause frame */ ++ ++/**********************************************************/ ++/* DMA bus mode register layout */ ++/**********************************************************/ ++#define DmaRxAlign16 0x01000000 /* Force all rx buffers to align on odd hw bndry */ ++#define DmaBigEndianDes 0x00100000 /* Big endian data buffer descriptors RW */ ++#define DmaLittleEndianDesc 0 /* Little endian data descriptors */ ++#define DmaBurstLength32 0x00002000 /* Dma burst length 32 RW */ ++#define DmaBurstLength16 0x00001000 /* Dma burst length 16 */ ++#define DmaBurstLength8 0x00000800 /* Dma burst length 8 */ ++#define DmaBurstLength4 0x00000400 /* Dma burst length 4 */ ++#define DmaBurstLength2 0x00000200 /* Dma burst length 2 */ ++#define DmaBurstLength1 0x00000100 /* Dma burst length 1 */ ++#define DmaBurstLength0 0x00000000 /* Dma burst length 0 */ ++#define DmaBigEndianData 0x00000080 /* Big endian data buffers RW */ ++#define DmaLittleEndianData 0 /* Little endian data buffers 0 */ ++#define DmaDescriptorSkip16 0x00000040 /* number of dwords to skip RW */ ++#define DmaDescriptorSkip8 0x00000020 /* between two unchained descriptors */ ++#define DmaDescriptorSkip4 0x00000010 ++#define DmaDescriptorSkip2 0x00000008 ++#define DmaDescriptorSkip1 0x00000004 ++#define DmaDescriptorSkip0 0 ++#define DmaReceivePriorityOff 0x00000002 /* equal rx and tx priorities RW */ ++#define DmaReceivePriorityOn 0 /* Rx has prioryty over Tx 0 */ ++#define DmaResetOn 0x00000001 /* Reset DMA engine RW */ ++#define DmaResetOff 0 ++ ++/**********************************************************/ ++/* DMA Status register layout */ ++/**********************************************************/ ++#define DmaRxAbort 0x01000000 /* receiver bus abort R 0 */ ++#define DmaTxAbort 0x00800000 /* transmitter bus abort R 0 */ ++#define DmaTxState 0x00700000 /* Transmit process state R 000 */ ++#define DmaTxStopped 0x00000000 /* Stopped */ ++#define DmaTxFetching 0x00100000 /* Running - fetching the descriptor */ ++#define DmaTxWaiting 0x00200000 /* Running - waiting for end of transmission */ ++#define DmaTxReading 0x00300000 /* Running - reading the data from memory */ ++#define DmaTxSuspended 0x00600000 /* Suspended */ ++#define DmaTxClosing 0x00700000 /* Running - closing descriptor */ ++#define DmaRxState 0x000E0000 /* Receive process state 000 */ ++#define DmaRxStopped 0x00000000 /* Stopped */ ++#define DmaRxFetching 0x00020000 /* Running - fetching the descriptor */ ++#define DmaRxChecking 0x00040000 /* Running - checking for end of packet */ ++#define DmaRxWaiting 0x00060000 /* Running - waiting for packet */ ++#define DmaRxSuspended 0x00080000 /* Suspended */ ++#define DmaRxClosing 0x000A0000 /* Running - closing descriptor */ ++#define DmaRxFlushing 0x000C0000 /* Running - flushing the current frame */ ++#define DmaRxQueuing 0x000E0000 /* Running - queuing the recieve frame into host memory */ ++#define DmaIntNormal 0x00010000 /* Normal interrupt summary RW 0 */ ++#define DmaIntAbnormal 0x00008000 /* Abnormal interrupt summary RW 0 */ ++#define DmaIntEarlyRx 0x00004000 /* Early receive interrupt (Normal) RW 0 */ ++#define DmaIntBusError 0x00002000 /* Fatal bus error (Abnormal) RW 0 */ ++#define DmaIntEarlyTx 0x00000400 /* Early transmit interrupt RW 0 */ ++#define DmaIntRxStopped 0x00000100 /* Receive process stopped (Abnormal) RW 0 */ ++#define DmaIntRxNoBuffer 0x00000080 /* Receive buffer unavailable (Abnormal) RW 0*/ ++#define DmaIntRxCompleted 0x00000040 /* Completion of frame reception(Normal) RW 0*/ ++#define DmaIntTxUnderflow 0x00000020 /* Transmit underflow (Abnormal) RW 0 */ ++#define DmaIntTxJabber 0x00000008 /* Transmit Jabber Timeout (Abnormal) RW 0 */ ++#define DmaIntTxNoBuffer 0x00000004 /* Transmit buffer unavailable (Normal) RW 0*/ ++#define DmaIntTxStopped 0x00000002 /* Transmit process stopped (Abnormal) RW 0 */ ++#define DmaIntTxCompleted 0x00000001 /* Transmit completed (Normal) RW 0 */ ++ ++/**********************************************************/ ++/* DMA control register layout */ ++/**********************************************************/ ++#define DmaStoreAndForward 0x00200000 /* Store and forward RW 0 */ ++#define DmaTxThreshCtl256 0x0000c000 /* Non-SF threshold is 256 words */ ++#define DmaTxThreshCtl128 0x00008000 /* Non-SF threshold is 128 words */ ++#define DmaTxThreshCtl064 0x00004000 /* Non-SF threshold is 64 words */ ++#define DmaTxThreshCtl032 0x00000000 /* Non-SF threshold is 32 words */ ++#define DmaTxStart 0x00002000 /* Start/Stop transmission RW 0 */ ++#define DmaTxSecondFrame 0x00000004 /* Operate on second frame RW 0 */ ++#define DmaRxStart 0x00000002 /* Start/Stop reception RW 0 */ ++ ++/**********************************************************/ ++/* DMA interrupt enable register layout */ ++/**********************************************************/ ++#define DmaIeNormal DmaIntNormal /* Normal interrupt enable RW 0 */ ++#define DmaIeAbnormal DmaIntAbnormal /* Abnormal interrupt enable RW 0 */ ++#define DmaIeEarlyRx DmaIntEarlyRx /* Early receive interrupt enable RW 0 */ ++#define DmaIeBusError DmaIntBusError /* Fatal bus error enable RW 0 */ ++#define DmaIeEarlyTx DmaIntEarlyTx /* Early transmit interrupt enable RW 0 */ ++#define DmaIeRxStopped DmaIntRxStopped /* Receive process stopped enable RW 0 */ ++#define DmaIeRxNoBuffer DmaIntRxNoBuffer /* Receive buffer unavailable enable RW 0 */ ++#define DmaIeRxCompleted DmaIntRxCompleted /* Completion of frame reception enable RW 0 */ ++#define DmaIeTxUnderflow DmaIntTxUnderflow /* Transmit underflow enable RW 0 */ ++#define DmaIeTxJabber DmaIntTxJabber /* Transmit jabber timeout RW 0 */ ++#define DmaIeTxNoBuffer DmaIntTxNoBuffer /* Transmit buffer unavailable enable RW 0 */ ++#define DmaIeTxStopped DmaIntTxStopped /* Transmit process stopped enable RW 0 */ ++#define DmaIeTxCompleted DmaIntTxCompleted /* Transmit completed enable RW 0 */ ++ ++/****************************************************************/ ++/* DMA Missed Frame and Buffer Overflow Counter register layout */ ++/****************************************************************/ ++#define DmaRxBufferMissedFrame 0xffff0000 /* cleared on read */ ++#define DmaMissedFrameShift 16 ++#define DmaRxBufferOverflowCnt 0x0000ffff /* cleared on read */ ++#define DmaMissedFrameCountMask 0x0000ffff ++ ++/**********************************************************/ ++/* DMA Engine descriptor layout */ ++/**********************************************************/ ++/* status word of DMA descriptor */ ++#define DescOwnByDma 0x80000000 /* Descriptor is owned by DMA engine */ ++#define DescFrameLengthMask 0x3FFF0000 /* Receive descriptor frame length */ ++#define DescFrameLengthShift 16 ++#define DescError 0x00008000 /* Error summary bit OR of following bits */ ++#define DescRxTruncated 0x00004000 /* Rx - no more descs for receive frame */ ++#define DescRxLengthError 0x00001000 /* Rx - frame size not matching with length field */ ++#define DescRxRunt 0x00000800 /* Rx - runt frame, damaged by a ++ collision or term before 64 bytes */ ++#define DescRxMulticast 0x00000400 /* Rx - received frame is multicast */ ++#define DescRxFirst 0x00000200 /* Rx - first descriptor of the frame */ ++#define DescRxLast 0x00000100 /* Rx - last descriptor of the frame */ ++#define DescRxLongFrame 0x00000080 /* Rx - frame is longer than 1518 bytes */ ++#define DescRxLateColl 0x00000040 /* Rx - frame was damaged by a late collision */ ++#define DescRxFrameEther 0x00000020 /* Rx - Frame type Ethernet 802.3*/ ++#define DescRxMiiError 0x00000008 /* Rx - error reported by MII interface */ ++#define DescRxDribbling 0x00000004 /* Rx - frame contains noninteger multiple of 8 bits */ ++#define DescRxCrc 0x00000002 /* Rx - CRC error */ ++#define DescTxTimeout 0x00004000 /* Tx - Transmit jabber timeout */ ++#define DescTxLostCarrier 0x00000800 /* Tx - carrier lost during tramsmission */ ++#define DescTxNoCarrier 0x00000400 /* Tx - no carrier signal from tranceiver */ ++#define DescTxLateCollision 0x00000200 /* Tx - transmission aborted due to collision */ ++#define DescTxExcCollisions 0x00000100 /* Tx - transmission aborted after 16 collisions */ ++#define DescTxHeartbeatFail 0x00000080 /* Tx - heartbeat collision check failure */ ++#define DescTxCollMask 0x00000078 /* Tx - Collision count */ ++#define DescTxCollShift 3 ++#define DescTxExcDeferral 0x00000004 /* Tx - excessive deferral */ ++#define DescTxUnderflow 0x00000002 /* Tx - late data arrival from memory */ ++#define DescTxDeferred 0x00000001 /* Tx - frame transmision deferred */ ++ ++/* length word of DMA descriptor */ ++#define DescTxIntEnable 0x80000000 /* Tx - interrupt on completion */ ++#define DescTxLast 0x40000000 /* Tx - Last segment of the frame */ ++#define DescTxFirst 0x20000000 /* Tx - First segment of the frame */ ++#define DescTxDisableCrc 0x04000000 /* Tx - Add CRC disabled (first segment only) */ ++#define DescEndOfRing 0x02000000 /* End of descriptors ring */ ++#define DescChain 0x01000000 /* Second buffer address is chain address */ ++#define DescTxDisablePadd 0x00800000 /* disable padding */ ++#define DescSize2Mask 0x003FF800 /* Buffer 2 size */ ++#define DescSize2Shift 11 ++#define DescSize1Mask 0x000007FF /* Buffer 1 size */ ++#define DescSize1Shift 0 ++ ++/**********************************************************/ ++/* Initial register values */ ++/**********************************************************/ ++/* Full-duplex mode with perfect filter on */ ++#define MacControlInitFdx \ ++ ( MacFilterOn \ ++ | MacLittleEndian \ ++ | MacHeartBeatOn \ ++ | MacSelectMii \ ++ | MacEnableRxOwn \ ++ | MacLoopbackOff \ ++ | MacFullDuplex \ ++ | MacMulticastFilterOn \ ++ | MacPromiscuousModeOff \ ++ | MacFilterNormal \ ++ | MacBadFramesDisable \ ++ | MacPerfectFilterOn \ ++ | MacHashFilterOff \ ++ | MacLateCollisionOff \ ++ | MacBroadcastEnable \ ++ | MacRetryEnable \ ++ | MacPadStripDisable \ ++ | MacDeferralCheckDisable \ ++ | MacTxEnable \ ++ | MacRxEnable) ++ ++/* Full-duplex mode */ ++#define MacFlowControlInitFdx \ ++ ( MacControlFrameDisable \ ++ | MacFlowControlEnable) ++ ++/* Half-duplex mode with perfect filter on */ ++#define MacControlInitHdx \ ++ ( MacFilterOn \ ++ | MacLittleEndian \ ++ | MacHeartBeatOn \ ++ | MacSelectMii \ ++ | MacDisableRxOwn \ ++ | MacLoopbackOff \ ++ | MacHalfDuplex \ ++ | MacMulticastFilterOn \ ++ | MacPromiscuousModeOff \ ++ | MacFilterNormal \ ++ | MacBadFramesDisable \ ++ | MacPerfectFilterOn \ ++ | MacHashFilterOff \ ++ | MacLateCollisionOff \ ++ | MacBroadcastEnable \ ++ | MacRetryEnable \ ++ | MacPadStripDisable \ ++ | MacDeferralCheckDisable \ ++ | MacTxEnable \ ++ | MacRxEnable) ++ ++/* Half-duplex mode */ ++#define MacFlowControlInitHdx \ ++ ( MacControlFrameDisable \ ++ | MacFlowControlDisable) ++ ++/* Bus Mode Rx odd half word align */ ++#define DmaBusModeInit \ ++ ( DmaLittleEndianDesc \ ++ | DmaRxAlign16 \ ++ | DmaBurstLength4 \ ++ | DmaBigEndianData \ ++ | DmaDescriptorSkip1 \ ++ | DmaReceivePriorityOn \ ++ | DmaResetOff) ++ ++#define DmaControlInit (DmaStoreAndForward) ++ ++/* Interrupt groups */ ++#define DmaIntEnable \ ++ ( DmaIeNormal \ ++ | DmaIeAbnormal \ ++ | DmaIntBusError \ ++ | DmaIntRxStopped \ ++ | DmaIntTxUnderflow \ ++ | DmaIntTxStopped) ++ ++#define DmaIntDisable 0 ++ ++#define DmaAllIntCauseMask \ ++ ( DmaIeNormal \ ++ | DmaIeAbnormal \ ++ | DmaIntEarlyRx \ ++ | DmaIntBusError \ ++ | DmaIntEarlyTx \ ++ | DmaIntRxStopped \ ++ | DmaIntRxNoBuffer \ ++ | DmaIntRxCompleted \ ++ | DmaIntTxUnderflow \ ++ | DmaIntTxJabber \ ++ | DmaIntTxNoBuffer \ ++ | DmaIntTxStopped \ ++ | DmaIntTxCompleted) ++ ++#define UnhandledIntrMask \ ++ (DmaAllIntCauseMask \ ++ & ~(DmaIntRxNoBuffer \ ++ | DmaIntTxStopped \ ++ | DmaIntTxJabber \ ++ | DmaIntTxUnderflow \ ++ | DmaIntBusError \ ++ | DmaIntRxCompleted )) ++ ++#define DescRxErrors \ ++ (DescRxTruncated \ ++ | DescRxRunt \ ++ | DescRxLateColl \ ++ | DescRxMiiError \ ++ | DescRxCrc) ++ ++#define DescTxErrors \ ++ ( DescTxTimeout \ ++ | DescTxLateCollision \ ++ | DescTxExcCollisions \ ++ | DescTxExcDeferral \ ++ | DescTxUnderflow) ++ ++/**********************************************************/ ++/* Descriptor Layout */ ++/**********************************************************/ ++#define AE531X_DESC_STATUS 0x00 /* Status offset */ ++#define AE531X_DESC_CTRLEN 0x04 /* Control and Length offset */ ++#define AE531X_DESC_BUFPTR 0x08 /* Buffer pointer offset */ ++#define AE531X_DESC_LNKBUF 0x0c /* Link field offset, or ptr to 2nd buf */ ++#define AE531X_DESC_SWPTR 0x10 /* OS-Dependent software pointer */ ++ ++#define AE531X_DESC_SIZE 0x10 /* 4 words, 16 bytes */ ++#define AE531X_QUEUE_ELE_SIZE 0x14 /* with software pointer extension */ ++ ++/* Accessors to the dma descriptor fields */ ++#define AE531X_DESC_STATUS_GET(ptr) \ ++ *(volatile UINT32 *)((UINT32)(ptr) + AE531X_DESC_STATUS) ++ ++#define AE531X_DESC_STATUS_SET(ptr, val) \ ++ AE531X_DESC_STATUS_GET(ptr) = (val) ++ ++#define AE531X_DESC_CTRLEN_GET(ptr) \ ++ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_CTRLEN) ++ ++#define AE531X_DESC_CTRLEN_SET(ptr, val) \ ++ AE531X_DESC_CTRLEN_GET(ptr) = (val) ++ ++#define AE531X_DESC_BUFPTR_GET(ptr) \ ++ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_BUFPTR) ++ ++#define AE531X_DESC_BUFPTR_SET(ptr,val) \ ++ AE531X_DESC_BUFPTR_GET(ptr) = (UINT32)(val) ++ ++#define AE531X_DESC_LNKBUF_GET(ptr) \ ++ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_LNKBUF) ++ ++#define AE531X_DESC_LNKBUF_SET(ptr, val) \ ++ AE531X_DESC_LNKBUF_GET(ptr) = (val) ++ ++#define AE531X_DESC_SWPTR_GET(ptr) \ ++ (void *)(*(volatile UINT32 *) ((UINT32)ptr + AE531X_DESC_SWPTR)) ++ ++#define AE531X_DESC_SWPTR_SET(ptr,val) \ ++ AE531X_DESC_SWPTR_GET(ptr) = (void *)(val) ++ ++/* Get size of Rx data from desc, in bytes */ ++#define AE531X_DESC_STATUS_RX_SIZE(x) \ ++ (((x) & DescFrameLengthMask) >> DescFrameLengthShift) ++ ++#endif /* _AE531XREG_H_ */ +diff -urN linux-2.4.32.new/arch/mips/ar531x/Makefile linux-2.4.32.new-eth/arch/mips/ar531x/Makefile +--- linux-2.4.32.new/arch/mips/ar531x/Makefile 2005-12-24 20:29:42.010325312 +0000 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/Makefile 2005-12-25 12:03:16.213872024 +0000 +@@ -28,6 +28,13 @@ + ar531xirq.o \ + ar531xintr.o \ + ar531xgpio.o \ +- ar531xksyms.o ++ ar531xksyms.o \ ++ ae531xlnx.o \ ++ ae531xmac.o + + include $(TOPDIR)/Rules.make ++obj-$(CONFIG_MARVELL_ENET_PHY) += mvPhy.o ++obj-$(CONFIG_KENDIN_ENET_PHY)) += rtPhy.o ++obj-$(CONFIG_REALTEK_ENET_PHY) += rtPhy.o ++ ++ +diff -urN linux-2.4.32.new/arch/mips/ar531x/mvPhy.c linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.c +--- linux-2.4.32.new/arch/mips/ar531x/mvPhy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.c 2005-12-25 11:54:39.730389448 +0000 +@@ -0,0 +1,1237 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++* Manage the ethernet PHY switch, Marvell 88E6060. ++* ++* This module is intended to be largely OS and platform-independent. ++*/ ++ ++#if defined(linux) ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++#endif ++ ++#if defined(__ECOS) ++#include "ae531xecos.h" ++#endif ++ ++ ++#include "ae531xmac.h" ++#include "ae531xreg.h" ++#include "mvPhy.h" ++ ++#if /* DEBUG */ 1 ++#define MV_DEBUG_ERROR 0x00000001 ++#define MV_DEBUG_PHYSETUP 0x00000002 ++#define MV_DEBUG_PHYCHANGE 0x00000004 ++ ++int mvPhyDebug = MV_DEBUG_ERROR; ++ ++#define MV_PRINT(FLG, X) \ ++{ \ ++ if (mvPhyDebug & (FLG)) { \ ++ DEBUG_PRINTF X; \ ++ } \ ++} ++#else ++#define MV_PRINT(FLG, X) ++#endif ++ ++#ifdef CONFIG_VENETDEV ++/* ++ * On AR5312 with CONFIG_VENETDEV==1, ++ * ports 0..3 are LAN ports (accessed through ae0) ++ * port 4 is the WAN port. (accessed through ae1) ++ * ++ * The phy switch settings in the mvPhyInfo table are set accordingly. ++ */ ++#define MV_WAN_PORT 4 ++#define MV_IS_LAN_PORT(port) ((port) < MV_WAN_PORT) ++#define MV_IS_WAN_PORT(port) ((port) == MV_WAN_PORT) ++#endif ++ ++/* ++ * Track per-PHY port information. ++ */ ++typedef struct { ++ BOOL isEnetPort; /* normal enet port */ ++ BOOL isPhyAlive; /* last known state of link */ ++ int ethUnit; /* MAC associated with this phy port */ ++ UINT32 phyBase; ++ UINT32 phyAddr; /* PHY registers associated with this phy port */ ++ UINT32 switchPortAddr; /* switch port regs assoc'ed with this phy port */ ++ UINT32 VLANTableSetting; /* Value to be written to VLAN table */ ++} mvPhyInfo_t; ++ ++/****************************************************************************** ++ * Per-PHY information, indexed by PHY unit number. ++ * ++ * This table is board-dependent. It includes information ++ * about which enet MAC controls which PHY port. ++ */ ++mvPhyInfo_t mvPhyInfo[] = { ++ /* ++ * On AP30/AR5312, all PHYs are associated with MAC0. ++ * AP30/AR5312's MAC1 isn't used for anything. ++ * CONFIG_VENETDEV==1 (router) configuration: ++ * Ports 0,1,2, and 3 are "LAN ports" ++ * Port 4 is a WAN port ++ * Port 5 connects to MAC0 in the AR5312 ++ * CONFIG_VENETDEV==0 (bridge) configuration: ++ * Ports 0,1,2,3,4 are "LAN ports" ++ * Port 5 connects to the MAC0 in the AR5312 ++ */ ++ {isEnetPort: TRUE, /* phy port 0 -- LAN port 0 */ ++ isPhyAlive: FALSE, ++ ethUnit: 0, ++ phyBase: 0, ++ phyAddr: 0x10, ++ switchPortAddr: 0x18, ++#ifdef CONFIG_VENETDEV ++ VLANTableSetting: 0x2e ++#else ++ VLANTableSetting: 0x3e ++#endif ++ }, ++ ++ {isEnetPort: TRUE, /* phy port 1 -- LAN port 1 */ ++ isPhyAlive: FALSE, ++ ethUnit: 0, ++ phyBase: 0, ++ phyAddr: 0x11, ++ switchPortAddr: 0x19, ++#ifdef CONFIG_VENETDEV ++ VLANTableSetting: 0x2d ++#else ++ VLANTableSetting: 0x3d ++#endif ++ }, ++ ++ {isEnetPort: TRUE, /* phy port 2 -- LAN port 2 */ ++ isPhyAlive: FALSE, ++ ethUnit: 0, ++ phyBase: 0, ++ phyAddr: 0x12, ++ switchPortAddr: 0x1a, ++#ifdef CONFIG_VENETDEV ++ VLANTableSetting: 0x2b ++#else ++ VLANTableSetting: 0x3b ++#endif ++ }, ++ ++ {isEnetPort: TRUE, /* phy port 3 -- LAN port 3 */ ++ isPhyAlive: FALSE, ++ ethUnit: 0, ++ phyBase: 0, ++ phyAddr: 0x13, ++ switchPortAddr: 0x1b, ++#ifdef CONFIG_VENETDEV ++ VLANTableSetting: 0x27 ++#else ++ VLANTableSetting: 0x37 ++#endif ++ }, ++ ++ {isEnetPort: TRUE, /* phy port 4 -- WAN port or LAN port 4 */ ++ isPhyAlive: FALSE, ++ ethUnit: 0, ++ phyBase: 0, ++ phyAddr: 0x14, ++ switchPortAddr: 0x1c, ++#ifdef CONFIG_VENETDEV ++ VLANTableSetting: 0x1020 /* WAN port */ ++#else ++ VLANTableSetting: 0x2f /* LAN port 4 */ ++#endif ++ }, ++ ++ {isEnetPort: FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */ ++ isPhyAlive: TRUE, ++ ethUnit: 0, ++ phyBase: 0, ++ phyAddr: 0x15, ++ switchPortAddr: 0x1d, ++#ifdef CONFIG_VENETDEV ++ VLANTableSetting: 0x0f /* Send only to LAN ports */ ++#else ++ VLANTableSetting: 0x1f /* Send to all ports */ ++#endif ++ }, ++}; ++ ++#define MV_PHY_MAX (sizeof(mvPhyInfo) / sizeof(mvPhyInfo[0])) ++ ++/* Range of valid PHY IDs is [MIN..MAX] */ ++#define MV_ID_MIN 0 ++#define MV_ID_MAX (MV_PHY_MAX-1) ++ ++/* Convenience macros to access myPhyInfo */ ++#define MV_IS_ENET_PORT(phyUnit) (mvPhyInfo[phyUnit].isEnetPort) ++#define MV_IS_PHY_ALIVE(phyUnit) (mvPhyInfo[phyUnit].isPhyAlive) ++#define MV_ETHUNIT(phyUnit) (mvPhyInfo[phyUnit].ethUnit) ++#define MV_PHYBASE(phyUnit) (mvPhyInfo[phyUnit].phyBase) ++#define MV_PHYADDR(phyUnit) (mvPhyInfo[phyUnit].phyAddr) ++#define MV_SWITCH_PORT_ADDR(phyUnit) (mvPhyInfo[phyUnit].switchPortAddr) ++#define MV_VLAN_TABLE_SETTING(phyUnit) (mvPhyInfo[phyUnit].VLANTableSetting) ++ ++#define MV_IS_ETHUNIT(phyUnit, ethUnit) \ ++ (MV_IS_ENET_PORT(phyUnit) && \ ++ MV_ETHUNIT(phyUnit) == (ethUnit)) ++ ++ ++/* Forward references */ ++BOOL mv_phyIsLinkAlive(int phyUnit); ++LOCAL void mv_VLANInit(int ethUnit); ++LOCAL void mv_enableConfiguredPorts(int ethUnit); ++LOCAL void mv_verifyReady(int ethUnit); ++BOOL mv_phySetup(int ethUnit, UINT32 phyBase); ++BOOL mv_phyIsFullDuplex(int ethUnit); ++BOOL mv_phyIsSpeed100(int phyUnit); ++LOCAL BOOL mv_validPhyId(int phyUnit); ++void mv_flushATUDB(int phyUnit); ++void mv_phyCheckStatusChange(int ethUnit); ++#if DEBUG ++void mv_phyShow(int phyUnit); ++void mv_phySet(int phyUnit, UINT32 regnum, UINT32 value); ++void mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value); ++void mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value); ++void mv_showATUDB(int phyUnit); ++void mv_countGoodFrames(int phyUnit); ++void mv_countBadFrames(int phyUnit); ++void mv_showFrameCounts(int phyUnit); ++#endif ++ ++ ++/****************************************************************************** ++* ++* mv_phyIsLinkAlive - test to see if the specified link is alive ++* ++* RETURNS: ++* TRUE --> link is alive ++* FALSE --> link is down ++*/ ++BOOL ++mv_phyIsLinkAlive(int phyUnit) ++{ ++ UINT16 phyHwStatus; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); ++ ++ if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) { ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++/****************************************************************************** ++* ++* mv_VLANInit - initialize "port-based VLANs" for the specified enet unit. ++*/ ++LOCAL void ++mv_VLANInit(int ethUnit) ++{ ++ int phyUnit; ++ UINT32 phyBase; ++ UINT32 switchPortAddr; ++ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (MV_ETHUNIT(phyUnit) != ethUnit) { ++ continue; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); ++ ++ phyRegWrite(phyBase, switchPortAddr, MV_PORT_BASED_VLAN_MAP, ++ MV_VLAN_TABLE_SETTING(phyUnit)); ++ } ++} ++ ++#define phyPortConfigured(phyUnit) TRUE /* TBDFREEDOM2 */ ++ ++/****************************************************************************** ++* ++* mv_enableConfiguredPorts - enable whichever PHY ports are supposed ++* to be enabled according to administrative configuration. ++*/ ++LOCAL void ++mv_enableConfiguredPorts(int ethUnit) ++{ ++ int phyUnit; ++ UINT32 phyBase; ++ UINT32 switchPortAddr; ++ UINT16 portControl; ++ UINT16 portAssociationVector; ++ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (MV_ETHUNIT(phyUnit) != ethUnit) { ++ continue; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); ++ ++ if (phyPortConfigured(phyUnit)) { ++ ++ portControl = MV_PORT_CONTROL_PORT_STATE_FORWARDING; ++#ifdef CONFIG_VENETDEV ++ if (!MV_IS_ENET_PORT(phyUnit)) { /* CPU port */ ++ portControl |= MV_PORT_CONTROL_INGRESS_TRAILER ++ | MV_PORT_CONTROL_EGRESS_MODE; ++ } ++#endif ++ phyRegWrite(phyBase, switchPortAddr, MV_PORT_CONTROL, portControl); ++ ++ if (MV_IS_ENET_PORT(phyUnit)) { ++ portAssociationVector = 1 << phyUnit; ++ } else { ++ /* Disable learning on the CPU port */ ++ portAssociationVector = 0; ++ } ++ phyRegWrite(phyBase, switchPortAddr, ++ MV_PORT_ASSOCIATION_VECTOR, portAssociationVector); ++ } ++ } ++} ++ ++/****************************************************************************** ++* ++* mv_verifyReady - validates that we're dealing with the device ++* we think we're dealing with, and that it's ready. ++*/ ++LOCAL void ++mv_verifyReady(int ethUnit) ++{ ++ int phyUnit; ++ UINT16 globalStatus; ++ UINT32 phyBase = 0; ++ UINT32 phyAddr; ++ UINT32 switchPortAddr; ++ UINT16 phyID1; ++ UINT16 phyID2; ++ UINT16 switchID; ++ ++ /* ++ * The first read to the Phy port registers always fails and ++ * returns 0. So get things started with a bogus read. ++ */ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { ++ continue; ++ } ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ (void)phyRegRead(phyBase, phyAddr, MV_PHY_ID1); /* returns 0 */ ++ break; ++ } ++ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { ++ continue; ++ } ++ ++ /*******************/ ++ /* Verify phy port */ ++ /*******************/ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ phyID1 = phyRegRead(phyBase, phyAddr, MV_PHY_ID1); ++ if (phyID1 != MV_PHY_ID1_EXPECTATION) { ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("Invalid PHY ID1 for ethmac%d port%d. Expected 0x%04x, read 0x%04x\n", ++ ethUnit, ++ phyUnit, ++ MV_PHY_ID1_EXPECTATION, ++ phyID1)); ++ return; ++ } ++ ++ phyID2 = phyRegRead(phyBase, phyAddr, MV_PHY_ID2); ++ if ((phyID2 & MV_OUI_LSB_MASK) != MV_OUI_LSB_EXPECTATION) { ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("Invalid PHY ID2 for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n", ++ ethUnit, ++ phyUnit, ++ MV_OUI_LSB_EXPECTATION, ++ phyID2)); ++ return; ++ } ++ ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("Found PHY ethmac%d port%d: model 0x%x revision 0x%x\n", ++ ethUnit, ++ phyUnit, ++ (phyID2 & MV_MODEL_NUM_MASK) >> MV_MODEL_NUM_SHIFT, ++ (phyID2 & MV_REV_NUM_MASK) >> MV_REV_NUM_SHIFT)); ++ ++ ++ /**********************/ ++ /* Verify switch port */ ++ /**********************/ ++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); ++ ++ switchID = phyRegRead(phyBase, switchPortAddr, MV_SWITCH_ID); ++ if ((switchID & MV_SWITCH_ID_DEV_MASK) != ++ MV_SWITCH_ID_DEV_EXPECTATION) { ++ ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("Invalid switch ID for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n", ++ ethUnit, ++ phyUnit, ++ MV_SWITCH_ID_DEV_EXPECTATION, ++ switchID)); ++ return; ++ } ++ ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("Found PHY switch for enet %d port %d deviceID 0x%x revision 0x%x\n", ++ ethUnit, ++ phyUnit, ++ (switchID & MV_SWITCH_ID_DEV_MASK) >> MV_SWITCH_ID_DEV_SHIFT, ++ (switchID & MV_SWITCH_ID_REV_MASK) >> MV_SWITCH_ID_REV_SHIFT)) ++ } ++ ++ /*******************************/ ++ /* Verify that switch is ready */ ++ /*******************************/ ++ if (phyBase) { ++ globalStatus = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_SWITCH_GLOBAL_STATUS); ++ ++ if (!(globalStatus & MV_SWITCH_STATUS_READY_MASK)) { ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("PHY switch for ethmac%d NOT ready!\n", ++ ethUnit)); ++ } ++ } else { ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("No ports configured for ethmac%d\n", ethUnit)); ++ } ++} ++ ++/****************************************************************************** ++* ++* mv_phySetup - reset and setup the PHY switch. ++* ++* Resets each PHY port. ++* ++* RETURNS: ++* TRUE --> at least 1 PHY with LINK ++* FALSE --> no LINKs on this ethernet unit ++*/ ++BOOL ++mv_phySetup(int ethUnit, UINT32 phyBase) ++{ ++ int phyUnit; ++ int liveLinks = 0; ++ BOOL foundPhy = FALSE; ++ UINT32 phyAddr; ++ UINT16 atuControl; ++ ++ /* ++ * Allow platform-specific code to determine the default Ethernet MAC ++ * at run-time. If phyEthMacDefault returns a negative value, use the ++ * static mvPhyInfo table "as is". But if phyEthMacDefault returns a ++ * non-negative value, use it as the default ethernet unit. ++ */ ++ { ++ int ethMacDefault = phyEthMacDefault(); ++ ++ if (ethMacDefault >= 0) { ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ MV_ETHUNIT(phyUnit)=ethMacDefault; ++ } ++ } ++ } ++ ++ /* ++ * See if there's any configuration data for this enet, ++ * and set up phyBase in table. ++ */ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (MV_ETHUNIT(phyUnit) != ethUnit) { ++ continue; ++ } ++ ++ MV_PHYBASE(phyUnit) = phyBase; ++ foundPhy = TRUE; ++ } ++ ++ if (!foundPhy) { ++ return FALSE; /* No PHY's configured for this ethUnit */ ++ } ++ ++ /* Verify that the switch is what we think it is, and that it's ready */ ++ mv_verifyReady(ethUnit); ++ ++ /* Initialize global switch settings */ ++ atuControl = MV_ATUCTRL_AGE_TIME_DEFAULT << MV_ATUCTRL_AGE_TIME_SHIFT; ++ atuControl |= MV_ATUCTRL_ATU_SIZE_DEFAULT << MV_ATUCTRL_ATU_SIZE_SHIFT; ++ // atuControl |= MV_ATUCTRL_ATU_LEARNDIS; ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_CONTROL, atuControl); ++ ++ /* Reset PHYs and start autonegoation on each. */ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (MV_ETHUNIT(phyUnit) != ethUnit) { ++ continue; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ phyRegWrite(phyBase, phyAddr, MV_PHY_CONTROL, ++ MV_CTRL_SOFTWARE_RESET | MV_CTRL_AUTONEGOTIATION_ENABLE); ++ } ++ ++ { ++ int timeout; ++ UINT16 phyHwStatus; ++ ++ /* ++ * Wait 5 seconds for ALL associated PHYs to finish autonegotiation. ++ */ ++ timeout=50; ++ for (phyUnit=0; (phyUnit < MV_PHY_MAX) && (timeout > 0); phyUnit++) { ++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { ++ continue; ++ } ++ for (;;) { ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); ++ ++ if (MV_AUTONEG_DONE(phyHwStatus)) { ++ break; ++ } ++ ++ if (--timeout == 0) { ++ break; ++ } ++ ++ sysMsDelay(100); ++ } ++ } ++ } ++ ++ /* ++ * All PHYs have had adequate time to autonegotiate. ++ * Now initialize software status. ++ * ++ * It's possible that some ports may take a bit longer ++ * to autonegotiate; but we can't wait forever. They'll ++ * get noticed by mv_phyCheckStatusChange during regular ++ * polling activities. ++ */ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { ++ continue; ++ } ++ ++ if (mv_phyIsLinkAlive(phyUnit)) { ++ liveLinks++; ++ MV_IS_PHY_ALIVE(phyUnit) = TRUE; ++#ifdef DEBUG ++ mv_phyShow(phyUnit); ++#endif ++ } else { ++ MV_IS_PHY_ALIVE(phyUnit) = FALSE; ++ } ++ ++ MV_PRINT(MV_DEBUG_PHYSETUP, ++ ("ethmac%d: Phy Status=%4.4x\n", ++ ethUnit, ++ phyRegRead(MV_PHYBASE(phyUnit), ++ MV_PHYADDR(phyUnit), ++ MV_PHY_SPECIFIC_STATUS))); ++ ++ } ++ ++#ifdef DEBUG ++ /* PHY 5 is the connection to the CPU */ ++ mv_phyShow(5); ++#endif ++ ++ mv_VLANInit(ethUnit); ++ ++ mv_enableConfiguredPorts(ethUnit); ++ ++ return (liveLinks > 0); ++} ++ ++ ++/****************************************************************************** ++* ++* mv_phyIsDuplexFull - Determines whether the phy ports associated with the ++* specified device are FULL or HALF duplex. ++* ++* RETURNS: ++* TRUE --> at least one associated PHY in FULL DUPLEX ++* FALSE --> all half duplex, or no links ++*/ ++BOOL ++mv_phyIsFullDuplex(int ethUnit) ++{ ++ int phyUnit; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ UINT16 phyHwStatus; ++ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ ++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { ++ continue; ++ } ++ ++ if (mv_phyIsLinkAlive(phyUnit)) { ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); ++ ++ if (phyHwStatus & MV_STATUS_RESOLVED_DUPLEX_FULL) { ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++/****************************************************************************** ++* ++* mv_phyIsSpeed100 - Determines the speed of a phy port ++* ++* RETURNS: ++* TRUE --> PHY operating at 100 Mbit ++* FALSE --> link down, or not operating at 100 Mbit ++*/ ++BOOL ++mv_phyIsSpeed100(int phyUnit) ++{ ++ UINT16 phyHwStatus; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ if (MV_IS_ENET_PORT(phyUnit)) { ++ if (mv_phyIsLinkAlive(phyUnit)) { ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); ++ ++ if (phyHwStatus & MV_STATUS_RESOLVED_SPEED_100) { ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++#ifdef CONFIG_VENETDEV ++/****************************************************************************** ++* ++* mv_phyDetermineSource - Examine a received frame's Egress Trailer ++* to determine whether it came from a LAN or WAN port. ++* ++* RETURNS: ++* Returns 1-->LAN, 0-->WAN, -1-->ERROR ++*/ ++int ++mv_phyDetermineSource(char *data, int len) ++{ ++ unsigned char *phyTrailer; ++ unsigned char incomingPort; ++ ++ phyTrailer = &data[len - MV_PHY_TRAILER_SIZE]; ++ ++ /* ASSERT(phyTrailer[0] == MV_EGRESS_TRAILER_VALID); */ ++ if (phyTrailer[0] != MV_EGRESS_TRAILER_VALID) { ++ printk(KERN_ERR "PHY trailer invalid; got %#02x, expected %#02x\n", ++ phyTrailer[0], MV_EGRESS_TRAILER_VALID); ++ return -1; ++ } ++ ++ incomingPort = phyTrailer[1]; ++ if (MV_IS_LAN_PORT(incomingPort)) { ++ return 1; ++ } else { ++ /* ASSERT(MV_IS_WAN_PORT(incomingPort)); */ ++ if (!MV_IS_WAN_PORT(incomingPort)) { ++ printk(KERN_ERR "incoming port was %d; expected 0-4\n", incomingPort); ++ return -1; ++ } ++ return 0; ++ } ++} ++ ++ ++/****************************************************************************** ++* ++* mv_phySetDestinationPort - Set the Ingress Trailer to force the ++* frame to be sent to LAN or WAN, as specified. ++* ++*/ ++void ++mv_phySetDestinationPort(char *data, int len, int fromLAN) ++{ ++ char *phyTrailer; ++ ++ phyTrailer = &data[len]; ++ if (fromLAN) { ++ /* LAN ports: Use default settings, as per mvPhyInfo */ ++ phyTrailer[0] = 0x00; ++ phyTrailer[1] = 0x00; ++ } else { ++ /* WAN port: Direct to WAN port */ ++ phyTrailer[0] = MV_INGRESS_TRAILER_OVERRIDE; ++ phyTrailer[1] = 1 << MV_WAN_PORT; ++ } ++ phyTrailer[2] = 0x00; ++ phyTrailer[3] = 0x00; ++} ++#endif ++ ++ ++/***************************************************************************** ++* ++* Validate that the specified PHY unit number is a valid PHY ID. ++* Print a message if it is invalid. ++* RETURNS ++* TRUE --> valid ++* FALSE --> invalid ++*/ ++LOCAL BOOL ++mv_validPhyId(int phyUnit) ++{ ++ if ((phyUnit >= MV_ID_MIN) && (phyUnit <= MV_ID_MAX)) { ++ return TRUE; ++ } else { ++ PRINTF("PHY unit number must be in the range [%d..%d]\n", ++ MV_ID_MIN, MV_ID_MAX); ++ return FALSE; ++ } ++} ++ ++ ++/***************************************************************************** ++* ++* mv_waitWhileATUBusy - spins until the ATU completes ++* its previous operation. ++*/ ++LOCAL void ++mv_waitWhileATUBusy(UINT32 phyBase) ++{ ++ BOOL isBusy; ++ UINT16 ATUOperation; ++ ++ do { ++ ++ ATUOperation = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_ATU_OPERATION); ++ ++ isBusy = (ATUOperation & MV_ATU_BUSY_MASK) == MV_ATU_IS_BUSY; ++ ++ } while(isBusy); ++} ++ ++/***************************************************************************** ++* ++* mv_flushATUDB - flushes ALL entries in the Address Translation Unit ++* DataBase associated with phyUnit. [Since we use a single DB for ++* all PHYs, this flushes the entire shared DataBase.] ++* ++* The current implementation flushes even more than absolutely needed -- ++* it flushes all entries for all phyUnits on the same ethernet as the ++* specified phyUnit. ++* ++* It is called only when a link failure is detected on a port that was ++* previously working. In other words, when the cable is unplugged. ++*/ ++void ++mv_flushATUDB(int phyUnit) ++{ ++ UINT32 phyBase; ++ ++ if (!mv_validPhyId(phyUnit)) { ++ PRINTF("Invalid port number: %d\n", phyUnit); ++ return; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ ++ /* Wait for previous operation (if any) to complete */ ++ mv_waitWhileATUBusy(phyBase); ++ ++ /* Tell hardware to flush all entries */ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION, ++ MV_ATU_OP_FLUSH_ALL | MV_ATU_IS_BUSY); ++ ++ mv_waitWhileATUBusy(phyBase); ++} ++ ++/***************************************************************************** ++* ++* mv_phyCheckStatusChange -- checks for significant changes in PHY state. ++* ++* A "significant change" is: ++* dropped link (e.g. ethernet cable unplugged) OR ++* autonegotiation completed + link (e.g. ethernet cable plugged in) ++*/ ++void ++mv_phyCheckStatusChange(int ethUnit) ++{ ++ int phyUnit; ++ UINT16 phyHwStatus; ++ mvPhyInfo_t *lastStatus; ++ int linkCount = 0; ++ int lostLinks = 0; ++ int gainedLinks = 0; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { ++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { ++ continue; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ lastStatus = &mvPhyInfo[phyUnit]; ++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); ++ ++ if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */ ++ /* See if we've lost link */ ++ if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) { ++ linkCount++; ++ } else { ++ lostLinks++; ++ mv_flushATUDB(phyUnit); ++ MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d down\n", ++ ethUnit, phyUnit)); ++ lastStatus->isPhyAlive = FALSE; ++ } ++ } else { /* last known link status was DEAD */ ++ /* Check for AutoNegotiation complete */ ++ if (MV_AUTONEG_DONE(phyHwStatus)) { ++ gainedLinks++; ++ linkCount++; ++ MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d up\n", ++ ethUnit, phyUnit)); ++ lastStatus->isPhyAlive = TRUE; ++ } ++ } ++ } ++ ++ if (linkCount == 0) { ++ if (lostLinks) { ++ /* We just lost the last link for this MAC */ ++ phyLinkLost(ethUnit); ++ } ++ } else { ++ if (gainedLinks == linkCount) { ++ /* We just gained our first link(s) for this MAC */ ++ phyLinkGained(ethUnit); ++ } ++ } ++} ++ ++#if DEBUG ++ ++/* Define the registers of interest for a phyShow command */ ++typedef struct mvRegisterTableEntry_s { ++ UINT32 regNum; ++ char *regIdString; ++} mvRegisterTableEntry_t; ++ ++mvRegisterTableEntry_t mvPhyRegisterTable[] = { ++ {MV_PHY_CONTROL, "PHY Control "}, ++ {MV_PHY_STATUS, "PHY Status "}, ++ {MV_PHY_ID1, "PHY Identifier 1 "}, ++ {MV_PHY_ID2, "PHY Identifier 2 "}, ++ {MV_AUTONEG_ADVERT, "Auto-Negotiation Advertisement "}, ++ {MV_LINK_PARTNER_ABILITY, "Link Partner Ability "}, ++ {MV_AUTONEG_EXPANSION, "Auto-Negotiation Expansion "}, ++ {MV_NEXT_PAGE_TRANSMIT, "Next Page Transmit "}, ++ {MV_LINK_PARTNER_NEXT_PAGE, "Link Partner Next Page "}, ++ {MV_PHY_SPECIFIC_CONTROL_1, "PHY-Specific Control Register 1 "}, ++ {MV_PHY_SPECIFIC_STATUS, "PHY-Specific Status "}, ++ {MV_PHY_INTERRUPT_ENABLE, "PHY Interrupt Enable "}, ++ {MV_PHY_INTERRUPT_STATUS, "PHY Interrupt Status "}, ++ {MV_PHY_INTERRUPT_PORT_SUMMARY, "PHY Interrupt Port Summary "}, ++ {MV_RECEIVE_ERROR_COUNTER, "Receive Error Counter "}, ++ {MV_LED_PARALLEL_SELECT, "LED Parallel Select "}, ++ {MV_LED_STREAM_SELECT_LEDS, "LED Stream Select "}, ++ {MV_PHY_LED_CONTROL, "PHY LED Control "}, ++ {MV_PHY_MANUAL_LED_OVERRIDE, "PHY Manual LED Override "}, ++ {MV_VCT_CONTROL, "VCT Control "}, ++ {MV_VCT_STATUS, "VCT Status "}, ++ {MV_PHY_SPECIFIC_CONTROL_2, "PHY-Specific Control Register 2 "}, ++}; ++int mvPhyNumRegs = sizeof(mvPhyRegisterTable) / sizeof(mvPhyRegisterTable[0]); ++ ++ ++mvRegisterTableEntry_t mvSwitchPortRegisterTable[] = { ++ {MV_PORT_STATUS, "Port Status "}, ++ {MV_SWITCH_ID, "Switch ID "}, ++ {MV_PORT_CONTROL, "Port Control "}, ++ {MV_PORT_BASED_VLAN_MAP, "Port-Based VLAN Map "}, ++ {MV_PORT_ASSOCIATION_VECTOR, "Port Association Vector "}, ++ {MV_RX_COUNTER, "RX Counter "}, ++ {MV_TX_COUNTER, "TX Counter "}, ++}; ++int mvSwitchPortNumRegs = ++ sizeof(mvSwitchPortRegisterTable) / sizeof(mvSwitchPortRegisterTable[0]); ++ ++ ++mvRegisterTableEntry_t mvSwitchGlobalRegisterTable[] = { ++ {MV_SWITCH_GLOBAL_STATUS, "Switch Global Status "}, ++ {MV_SWITCH_MAC_ADDR0, "Switch MAC Addr 0 & 1 "}, ++ {MV_SWITCH_MAC_ADDR2, "Switch MAC Addr 2 & 3 "}, ++ {MV_SWITCH_MAC_ADDR4, "Switch MAC Addr 4 & 5 "}, ++ {MV_SWITCH_GLOBAL_CONTROL, "Switch Global Control "}, ++ {MV_ATU_CONTROL, "ATU Control "}, ++ {MV_ATU_OPERATION, "ATU Operation "}, ++ {MV_ATU_DATA, "ATU Data "}, ++ {MV_ATU_MAC_ADDR0, "ATU MAC Addr 0 & 1 "}, ++ {MV_ATU_MAC_ADDR2, "ATU MAC Addr 2 & 3 "}, ++ {MV_ATU_MAC_ADDR4, "ATU MAC Addr 4 & 5 "}, ++}; ++int mvSwitchGlobalNumRegs = ++ sizeof(mvSwitchGlobalRegisterTable) / sizeof(mvSwitchGlobalRegisterTable[0]); ++ ++ ++/***************************************************************************** ++* ++* mv_phyShow - Dump the state of a PHY. ++* There are two sets of registers for each phy port: ++* "phy registers" and ++* "switch port registers" ++* We dump 'em all, plus the switch global registers. ++*/ ++void ++mv_phyShow(int phyUnit) ++{ ++ int i; ++ UINT16 value; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ UINT32 switchPortAddr; ++ ++ if (!mv_validPhyId(phyUnit)) { ++ return; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); ++ ++ PRINTF("PHY state for PHY%d (ethmac%d, phyBase 0x%8x, phyAddr 0x%x, switchAddr 0x%x)\n", ++ phyUnit, ++ MV_ETHUNIT(phyUnit), ++ MV_PHYBASE(phyUnit), ++ MV_PHYADDR(phyUnit), ++ MV_SWITCH_PORT_ADDR(phyUnit)); ++ ++ PRINTF("PHY Registers:\n"); ++ for (i=0; i < mvPhyNumRegs; i++) { ++ ++ value = phyRegRead(phyBase, phyAddr, mvPhyRegisterTable[i].regNum); ++ ++ PRINTF("Reg %02d (0x%02x) %s = 0x%08x\n", ++ mvPhyRegisterTable[i].regNum, ++ mvPhyRegisterTable[i].regNum, ++ mvPhyRegisterTable[i].regIdString, ++ value); ++ } ++ ++ PRINTF("Switch Port Registers:\n"); ++ for (i=0; i < mvSwitchPortNumRegs; i++) { ++ ++ value = phyRegRead(phyBase, switchPortAddr, ++ mvSwitchPortRegisterTable[i].regNum); ++ ++ PRINTF("Reg %02d (0x%02x) %s = 0x%08x\n", ++ mvSwitchPortRegisterTable[i].regNum, ++ mvSwitchPortRegisterTable[i].regNum, ++ mvSwitchPortRegisterTable[i].regIdString, ++ value); ++ } ++ ++ PRINTF("Switch Global Registers:\n"); ++ for (i=0; i < mvSwitchGlobalNumRegs; i++) { ++ ++ value = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ mvSwitchGlobalRegisterTable[i].regNum); ++ ++ PRINTF("Reg %02d (0x%02x) %s = 0x%08x\n", ++ mvSwitchGlobalRegisterTable[i].regNum, ++ mvSwitchGlobalRegisterTable[i].regNum, ++ mvSwitchGlobalRegisterTable[i].regIdString, ++ value); ++ } ++} ++ ++/***************************************************************************** ++* ++* mv_phySet - Modify the value of a PHY register (debug only). ++*/ ++void ++mv_phySet(int phyUnit, UINT32 regnum, UINT32 value) ++{ ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ if (mv_validPhyId(phyUnit)) { ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ phyAddr = MV_PHYADDR(phyUnit); ++ ++ phyRegWrite(phyBase, phyAddr, regnum, value); ++ } ++} ++ ++ ++/***************************************************************************** ++* ++* mv_switchPortSet - Modify the value of a switch port register (debug only). ++*/ ++void ++mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value) ++{ ++ UINT32 phyBase; ++ UINT32 switchPortAddr; ++ ++ if (mv_validPhyId(phyUnit)) { ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); ++ ++ phyRegWrite(phyBase, switchPortAddr, regnum, value); ++ } ++} ++ ++/***************************************************************************** ++* ++* mv_switchGlobalSet - Modify the value of a switch global register ++* (debug only). ++*/ ++void ++mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value) ++{ ++ UINT32 phyBase; ++ ++ if (mv_validPhyId(phyUnit)) { ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, regnum, value); ++ } ++} ++ ++/***************************************************************************** ++* ++* mv_showATUDB - Dump the contents of the Address Translation Unit DataBase ++* for the PHY switch associated with the specified phy. ++*/ ++void ++mv_showATUDB(int phyUnit) ++{ ++ UINT32 phyBase; ++ UINT16 ATUData; ++ UINT16 ATUMac0; ++ UINT16 ATUMac2; ++ UINT16 ATUMac4; ++ int portVec; ++ int entryState; ++ ++ if (!mv_validPhyId(phyUnit)) { ++ PRINTF("Invalid port number: %d\n", phyUnit); ++ return; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ ++ /* Wait for previous operation (if any) to complete */ ++ mv_waitWhileATUBusy(phyBase); ++ ++ /* Initialize ATU MAC to all 1's */ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0, 0xffff); ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2, 0xffff); ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4, 0xffff); ++ ++ PRINTF(" MAC ADDRESS EntryState PortVector\n"); ++ ++ for(;;) { ++ /* Tell hardware to get next MAC info */ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION, ++ MV_ATU_OP_GET_NEXT | MV_ATU_IS_BUSY); ++ ++ mv_waitWhileATUBusy(phyBase); ++ ++ ATUData = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_DATA); ++ entryState = (ATUData & MV_ENTRYSTATE_MASK) >> MV_ENTRYSTATE_SHIFT; ++ ++ if (entryState == 0) { ++ /* We've hit the end of the list */ ++ break; ++ } ++ ++ ATUMac0 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0); ++ ATUMac2 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2); ++ ATUMac4 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4); ++ ++ portVec = (ATUData & MV_PORTVEC_MASK) >> MV_PORTVEC_SHIFT; ++ ++ PRINTF("%02x:%02x:%02x:%02x:%02x:%02x 0x%02x 0x%02x\n", ++ ATUMac0 >> 8, /* MAC byte 0 */ ++ ATUMac0 & 0xff, /* MAC byte 1 */ ++ ATUMac2 >> 8, /* MAC byte 2 */ ++ ATUMac2 & 0xff, /* MAC byte 3 */ ++ ATUMac4 >> 8, /* MAC byte 4 */ ++ ATUMac4 & 0xff, /* MAC byte 5 */ ++ entryState, ++ portVec); ++ } ++} ++ ++LOCAL BOOL countingGoodFrames; ++ ++/***************************************************************************** ++* ++* mv_countGoodFrames - starts counting GOOD RX/TX frames per port ++*/ ++void ++mv_countGoodFrames(int phyUnit) ++{ ++ UINT32 phyBase; ++ UINT16 globalControl; ++ ++ if (mv_validPhyId(phyUnit)) { ++ /* ++ * Guarantee that counters are cleared by ++ * forcing CtrMode to toggle and end on GOODFRAMES. ++ */ ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ ++ /* Read current Switch Global Control Register */ ++ globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_SWITCH_GLOBAL_CONTROL); ++ ++ /* Set CtrMode to count BAD frames */ ++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) | ++ MV_CTRMODE_BADFRAMES); ++ ++ /* Push new value out to hardware */ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_SWITCH_GLOBAL_CONTROL, globalControl); ++ ++ /* Now toggle CtrMode to count GOOD frames */ ++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) | ++ MV_CTRMODE_GOODFRAMES); ++ ++ /* Push new value out to hardware */ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_SWITCH_GLOBAL_CONTROL, globalControl); ++ ++ countingGoodFrames = TRUE; ++ } ++} ++ ++/***************************************************************************** ++* ++* mv_countBadFrames - starts counting BAD RX/TX frames per port ++*/ ++void ++mv_countBadFrames(int phyUnit) ++{ ++ UINT32 phyBase; ++ UINT16 globalControl; ++ ++ if (mv_validPhyId(phyUnit)) { ++ /* ++ * Guarantee that counters are cleared by ++ * forcing CtrMode to toggle and end on BADFRAMES. ++ */ ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ ++ /* Read current Switch Global Control Register */ ++ globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_SWITCH_GLOBAL_CONTROL); ++ ++ /* Set CtrMode to count GOOD frames */ ++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) | ++ MV_CTRMODE_GOODFRAMES); ++ ++ /* Push new value out to hardware */ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_SWITCH_GLOBAL_CONTROL, globalControl); ++ ++ /* Now toggle CtrMode to count BAD frames */ ++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) | ++ MV_CTRMODE_BADFRAMES); ++ ++ /* Push new value out to hardware */ ++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, ++ MV_SWITCH_GLOBAL_CONTROL, globalControl); ++ ++ countingGoodFrames = FALSE; ++ } ++} ++ ++/***************************************************************************** ++* ++* mv_showFrameCounts - shows current GOOD/BAD Frame counts ++*/ ++void ++mv_showFrameCounts(int phyUnit) ++{ ++ UINT16 rxCounter; ++ UINT16 txCounter; ++ UINT32 phyBase; ++ UINT32 switchPortAddr; ++ ++ if (!mv_validPhyId(phyUnit)) { ++ return; ++ } ++ ++ phyBase = MV_PHYBASE(phyUnit); ++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); ++ ++ rxCounter = phyRegRead(phyBase, switchPortAddr, MV_RX_COUNTER); ++ ++ txCounter = phyRegRead(phyBase, switchPortAddr, MV_TX_COUNTER); ++ ++ PRINTF("port%d %s frames: receive: %05d transmit: %05d\n", ++ phyUnit, ++ (countingGoodFrames ? "good" : "error"), ++ rxCounter, ++ txCounter); ++} ++#endif +diff -urN linux-2.4.32.new/arch/mips/ar531x/mvPhy.h linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.h +--- linux-2.4.32.new/arch/mips/ar531x/mvPhy.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.h 2005-12-25 11:54:39.775382608 +0000 +@@ -0,0 +1,160 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * mvPhy.h - definitions for the ethernet PHY -- Marvell 88E6060 ++ * All definitions in this file are operating system independent! ++ */ ++ ++#ifndef MVPHY_H ++#define MVPHY_H ++ ++/*****************/ ++/* PHY Registers */ ++/*****************/ ++#define MV_PHY_CONTROL 0 ++#define MV_PHY_STATUS 1 ++#define MV_PHY_ID1 2 ++#define MV_PHY_ID2 3 ++#define MV_AUTONEG_ADVERT 4 ++#define MV_LINK_PARTNER_ABILITY 5 ++#define MV_AUTONEG_EXPANSION 6 ++#define MV_NEXT_PAGE_TRANSMIT 7 ++#define MV_LINK_PARTNER_NEXT_PAGE 8 ++#define MV_PHY_SPECIFIC_CONTROL_1 16 ++#define MV_PHY_SPECIFIC_STATUS 17 ++#define MV_PHY_INTERRUPT_ENABLE 18 ++#define MV_PHY_INTERRUPT_STATUS 19 ++#define MV_PHY_INTERRUPT_PORT_SUMMARY 20 ++#define MV_RECEIVE_ERROR_COUNTER 21 ++#define MV_LED_PARALLEL_SELECT 22 ++#define MV_LED_STREAM_SELECT_LEDS 23 ++#define MV_PHY_LED_CONTROL 24 ++#define MV_PHY_MANUAL_LED_OVERRIDE 25 ++#define MV_VCT_CONTROL 26 ++#define MV_VCT_STATUS 27 ++#define MV_PHY_SPECIFIC_CONTROL_2 28 ++ ++/* MV_PHY_CONTROL fields */ ++#define MV_CTRL_SOFTWARE_RESET 0x8000 ++#define MV_CTRL_AUTONEGOTIATION_ENABLE 0x1000 ++ ++/* MV_PHY_ID1 fields */ ++#define MV_PHY_ID1_EXPECTATION 0x0141 /* OUI >> 6 */ ++ ++/* MV_PHY_ID2 fields */ ++#define MV_OUI_LSB_MASK 0xfc00 ++#define MV_OUI_LSB_EXPECTATION 0x0c00 ++#define MV_OUI_LSB_SHIFT 10 ++#define MV_MODEL_NUM_MASK 0x03f0 ++#define MV_MODEL_NUM_SHIFT 4 ++#define MV_REV_NUM_MASK 0x000f ++#define MV_REV_NUM_SHIFT 0 ++ ++/* MV_PHY_SPECIFIC_STATUS fields */ ++#define MV_STATUS_RESOLVED_SPEED_100 0x4000 ++#define MV_STATUS_RESOLVED_DUPLEX_FULL 0x2000 ++#define MV_STATUS_RESOLVED 0x0800 ++#define MV_STATUS_REAL_TIME_LINK_UP 0x0400 ++ ++/* Check if autonegotiation is complete and link is up */ ++#define MV_AUTONEG_DONE(mv_phy_specific_status) \ ++ (((mv_phy_specific_status) & \ ++ (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP)) == \ ++ (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP)) ++ ++ ++/*************************/ ++/* Switch Port Registers */ ++/*************************/ ++#define MV_PORT_STATUS 0 ++#define MV_SWITCH_ID 3 ++#define MV_PORT_CONTROL 4 ++#define MV_PORT_BASED_VLAN_MAP 6 ++#define MV_PORT_ASSOCIATION_VECTOR 11 ++#define MV_RX_COUNTER 16 ++#define MV_TX_COUNTER 17 ++ ++/* MV_SWITCH_ID fields */ ++#define MV_SWITCH_ID_DEV_MASK 0xfff0 ++#define MV_SWITCH_ID_DEV_EXPECTATION 0x0600 ++#define MV_SWITCH_ID_DEV_SHIFT 4 ++#define MV_SWITCH_ID_REV_MASK 0x000f ++#define MV_SWITCH_ID_REV_SHIFT 0 ++ ++/* MV_PORT_CONTROL fields */ ++#define MV_PORT_CONTROL_PORT_STATE_MASK 0x0003 ++#define MV_PORT_CONTROL_PORT_STATE_DISABLED 0x0000 ++#define MV_PORT_CONTROL_PORT_STATE_FORWARDING 0x0003 ++ ++#define MV_PORT_CONTROL_EGRESS_MODE 0x0100 /* Receive */ ++#define MV_PORT_CONTROL_INGRESS_TRAILER 0x4000 /* Transmit */ ++ ++#define MV_EGRESS_TRAILER_VALID 0x80 ++#define MV_INGRESS_TRAILER_OVERRIDE 0x80 ++ ++#define MV_PHY_TRAILER_SIZE 4 ++ ++ ++/***************************/ ++/* Switch Global Registers */ ++/***************************/ ++#define MV_SWITCH_GLOBAL_STATUS 0 ++#define MV_SWITCH_MAC_ADDR0 1 ++#define MV_SWITCH_MAC_ADDR2 2 ++#define MV_SWITCH_MAC_ADDR4 3 ++#define MV_SWITCH_GLOBAL_CONTROL 4 ++#define MV_ATU_CONTROL 10 ++#define MV_ATU_OPERATION 11 ++#define MV_ATU_DATA 12 ++#define MV_ATU_MAC_ADDR0 13 ++#define MV_ATU_MAC_ADDR2 14 ++#define MV_ATU_MAC_ADDR4 15 ++ ++/* MV_SWITCH_GLOBAL_STATUS fields */ ++#define MV_SWITCH_STATUS_READY_MASK 0x0800 ++ ++/* MV_SWITCH_GLOBAL_CONTROL fields */ ++#define MV_CTRMODE_MASK 0x0100 ++#define MV_CTRMODE_GOODFRAMES 0x0000 ++#define MV_CTRMODE_BADFRAMES 0x0100 ++ ++/* MV_ATU_CONTROL fields */ ++#define MV_ATUCTRL_ATU_LEARNDIS 0x4000 ++#define MV_ATUCTRL_ATU_SIZE_MASK 0x3000 ++#define MV_ATUCTRL_ATU_SIZE_SHIFT 12 ++#define MV_ATUCTRL_ATU_SIZE_DEFAULT 2 /* 1024 entry database */ ++#define MV_ATUCTRL_AGE_TIME_MASK 0x0ff0 ++#define MV_ATUCTRL_AGE_TIME_SHIFT 4 ++#define MV_ATUCTRL_AGE_TIME_DEFAULT 19 /* 19 * 16 = 304 seconds */ ++ ++/* MV_ATU_OPERATION fields */ ++#define MV_ATU_BUSY_MASK 0x8000 ++#define MV_ATU_IS_BUSY 0x8000 ++#define MV_ATU_IS_FREE 0x0000 ++#define MV_ATU_OP_MASK 0x7000 ++#define MV_ATU_OP_FLUSH_ALL 0x1000 ++#define MV_ATU_OP_GET_NEXT 0x4000 ++ ++/* MV_ATU_DATA fields */ ++#define MV_ENTRYPRI_MASK 0xc000 ++#define MV_ENTRYPRI_SHIFT 14 ++#define MV_PORTVEC_MASK 0x03f0 ++#define MV_PORTVEC_SHIFT 4 ++#define MV_ENTRYSTATE_MASK 0x000f ++#define MV_ENTRYSTATE_SHIFT 0 ++ ++/* PHY Address for the switch itself */ ++#define MV_SWITCH_GLOBAL_ADDR 0x1f ++ ++BOOL mv_phySetup(int ethUnit, UINT32 phyBase); ++void mv_phyCheckStatusChange(int ethUnit); ++BOOL mv_phyIsSpeed100(int ethUnit); ++BOOL mv_phyIsFullDuplex(int ethUnit); ++ ++#endif /* MVPHY_H */ +diff -urN linux-2.4.32.new/arch/mips/ar531x/rtPhy.c linux-2.4.32.new-eth/arch/mips/ar531x/rtPhy.c +--- linux-2.4.32.new/arch/mips/ar531x/rtPhy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new-eth/arch/mips/ar531x/rtPhy.c 2005-12-25 11:54:46.086423184 +0000 +@@ -0,0 +1,272 @@ ++/* ++ * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. ++ */ ++ ++/* ++ * Manage the ethernet PHY. ++ * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL, ++ * and compatible PHYs, such as the Kendin KS8721B. ++ * All definitions in this file are operating system independent! ++ */ ++ ++#if defined(linux) ++#include ++#include ++#include ++#include ++#include ++ ++#include "ar531xlnx.h" ++#endif ++ ++#if defined(__ECOS) ++#include "ae531xecos.h" ++#endif ++ ++ ++#include "ae531xmac.h" ++#include "ae531xreg.h" ++#include "rtPhy.h" ++ ++#if /* DEBUG */ 1 ++#define RT_DEBUG_ERROR 0x00000001 ++#define RT_DEBUG_PHYSETUP 0x00000002 ++#define RT_DEBUG_PHYCHANGE 0x00000004 ++ ++int rtPhyDebug = RT_DEBUG_ERROR; ++ ++#define RT_PRINT(FLG, X) \ ++{ \ ++ if (rtPhyDebug & (FLG)) { \ ++ DEBUG_PRINTF X; \ ++ } \ ++} ++#else ++#define RT_PRINT(FLG, X) ++#endif ++ ++/* ++ * Track per-PHY port information. ++ */ ++typedef struct { ++ BOOL phyAlive; /* last known state of link */ ++ UINT32 phyBase; ++ UINT32 phyAddr; ++} rtPhyInfo_t; ++ ++#define ETH_PHY_ADDR 1 ++ ++/* ++ * This table defines the mapping from phy units to ++ * per-PHY information. ++ * ++ * This table is somewhat board-dependent. ++ */ ++rtPhyInfo_t rtPhyInfo[] = { ++ {phyAlive: FALSE, /* PHY 0 */ ++ phyBase: 0, /* filled in by rt_phySetup */ ++ phyAddr: ETH_PHY_ADDR}, ++ ++ {phyAlive: FALSE, /* PHY 1 */ ++ phyBase: 0, /* filled in by rt_phySetup */ ++ phyAddr: ETH_PHY_ADDR} ++}; ++ ++/* Convert from phy unit# to (phyBase, phyAddr) pair */ ++#define RT_PHYBASE(phyUnit) (rtPhyInfo[phyUnit].phyBase) ++#define RT_PHYADDR(phyUnit) (rtPhyInfo[phyUnit].phyAddr) ++ ++ ++/****************************************************************************** ++* ++* rt_phySetup - reset and setup the PHY associated with ++* the specified MAC unit number. ++* ++* Resets the associated PHY port. ++* ++* RETURNS: ++* TRUE --> associated PHY is alive ++* FALSE --> no LINKs on this ethernet unit ++*/ ++ ++BOOL ++rt_phySetup(int ethUnit, UINT32 phyBase) ++{ ++ BOOL linkAlive = FALSE; ++ UINT32 phyAddr; ++ ++ RT_PHYBASE(ethUnit) = phyBase; ++ ++ phyAddr = RT_PHYADDR(ethUnit); ++ ++ /* Reset phy */ ++ phyRegWrite(phyBase, phyAddr, GEN_ctl, PHY_SW_RST | AUTONEGENA); ++ ++ sysMsDelay(1500); ++ ++ return linkAlive; ++} ++ ++/****************************************************************************** ++* ++* rt_phyIsDuplexFull - Determines whether the phy ports associated with the ++* specified device are FULL or HALF duplex. ++* ++* RETURNS: ++* TRUE --> FULL ++* FALSE --> HALF ++*/ ++BOOL ++rt_phyIsFullDuplex(int ethUnit) ++{ ++ UINT16 phyCtl; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ phyBase = RT_PHYBASE(ethUnit); ++ phyAddr = RT_PHYADDR(ethUnit); ++ ++ phyCtl = phyRegRead(phyBase, phyAddr, GEN_ctl); ++ ++ if (phyCtl & DUPLEX) { ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++/****************************************************************************** ++* ++* rt_phyIsSpeed100 - Determines the speed of phy ports associated with the ++* specified device. ++* ++* RETURNS: ++* TRUE --> 100Mbit ++* FALSE --> 10Mbit ++*/ ++BOOL ++rt_phyIsSpeed100(int phyUnit) ++{ ++ UINT16 phyLpa; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ phyBase = RT_PHYBASE(phyUnit); ++ phyAddr = RT_PHYADDR(phyUnit); ++ ++ phyLpa = phyRegRead(phyBase, phyAddr, AN_lpa); ++ ++ if (phyLpa & (LPA_TXFD | LPA_TX)) { ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++/***************************************************************************** ++* ++* rt_phyCheckStatusChange -- checks for significant changes in PHY state. ++* ++* A "significant change" is: ++* dropped link (e.g. ethernet cable unplugged) OR ++* autonegotiation completed + link (e.g. ethernet cable plugged in) ++* ++* On AR5311, there is a 1-to-1 mapping of ethernet units to PHYs. ++* When a PHY is plugged in, phyLinkGained is called. ++* When a PHY is unplugged, phyLinkLost is called. ++*/ ++void ++rt_phyCheckStatusChange(int ethUnit) ++{ ++ UINT16 phyHwStatus; ++ rtPhyInfo_t *lastStatus = &rtPhyInfo[ethUnit]; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ phyBase = RT_PHYBASE(ethUnit); ++ phyAddr = RT_PHYADDR(ethUnit); ++ ++ phyHwStatus = phyRegRead(phyBase, phyAddr, GEN_sts); ++ ++ if (lastStatus->phyAlive) { /* last known status was ALIVE */ ++ /* See if we've lost link */ ++ if (!(phyHwStatus & LINK)) { ++ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link down\n", ethUnit)); ++ lastStatus->phyAlive = FALSE; ++ phyLinkLost(ethUnit); ++ } ++ } else { /* last known status was DEAD */ ++ /* Check for AN complete */ ++ if ((phyHwStatus & (AUTOCMPLT | LINK)) == (AUTOCMPLT | LINK)) { ++ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link up\n", ethUnit)); ++ lastStatus->phyAlive = TRUE; ++ phyLinkGained(ethUnit); ++ } ++ } ++} ++ ++#if DEBUG ++ ++/* Define the PHY registers of interest for a phyShow command */ ++struct rtRegisterTable_s { ++ UINT32 regNum; ++ char *regIdString; ++} rtRegisterTable[] = ++{ ++ {GEN_ctl, "Basic Mode Control (GEN_ctl) "}, ++ {GEN_sts, "Basic Mode Status (GEN_sts) "}, ++ {GEN_id_hi, "PHY Identifier 1 (GET_id_hi) "}, ++ {GEN_id_lo, "PHY Identifier 2 (GET_id_lo) "}, ++ {AN_adv, "Auto-Neg Advertisement (AN_adv) "}, ++ {AN_lpa, "Auto-Neg Link Partner Ability "}, ++ {AN_exp, "Auto-Neg Expansion "}, ++}; ++ ++int rtNumRegs = sizeof(rtRegisterTable) / sizeof(rtRegisterTable[0]); ++ ++/* ++ * Dump the state of a PHY. ++ */ ++void ++rt_phyShow(int phyUnit) ++{ ++ int i; ++ UINT16 value; ++ UINT32 phyBase; ++ UINT32 phyAddr; ++ ++ phyBase = RT_PHYBASE(phyUnit); ++ phyAddr = RT_PHYADDR(phyUnit); ++ ++ printf("PHY state for ethphy%d\n", phyUnit); ++ ++ for (i=0; i