diff options
| -rw-r--r-- | target/linux/aruba-2.6/config | 5 | ||||
| -rw-r--r-- | target/linux/aruba-2.6/config-ramdisk | 5 | ||||
| -rw-r--r-- | target/linux/aruba-2.6/patches/010-ar2313_enet.patch | 2160 | 
3 files changed, 2166 insertions, 4 deletions
diff --git a/target/linux/aruba-2.6/config b/target/linux/aruba-2.6/config index e25aa325d..804a26fb2 100644 --- a/target/linux/aruba-2.6/config +++ b/target/linux/aruba-2.6/config @@ -1,7 +1,7 @@  #  # Automatically generated make config: don't edit -# Linux kernel version: 2.6.15 -# Fri Jan 13 15:40:49 2006 +# Linux kernel version: 2.6.15.1 +# Mon Jan 30 02:08:31 2006  #  CONFIG_MIPS=y @@ -734,6 +734,7 @@ CONFIG_TUN=m  #  CONFIG_NET_ETHERNET=y  CONFIG_MII=y +CONFIG_AR2313=y  CONFIG_IDT_RC32434_ETH=y  # CONFIG_HAPPYMEAL is not set  # CONFIG_SUNGEM is not set diff --git a/target/linux/aruba-2.6/config-ramdisk b/target/linux/aruba-2.6/config-ramdisk index a5e81fe13..2d0c1a0a7 100644 --- a/target/linux/aruba-2.6/config-ramdisk +++ b/target/linux/aruba-2.6/config-ramdisk @@ -1,7 +1,7 @@  #  # Automatically generated make config: don't edit -# Linux kernel version: 2.6.15 -# Fri Jan 13 15:40:49 2006 +# Linux kernel version: 2.6.15.1 +# Mon Jan 30 02:08:31 2006  #  CONFIG_MIPS=y @@ -736,6 +736,7 @@ CONFIG_TUN=m  #  CONFIG_NET_ETHERNET=y  CONFIG_MII=y +CONFIG_AR2313=y  CONFIG_IDT_RC32434_ETH=y  # CONFIG_HAPPYMEAL is not set  # CONFIG_SUNGEM is not set diff --git a/target/linux/aruba-2.6/patches/010-ar2313_enet.patch b/target/linux/aruba-2.6/patches/010-ar2313_enet.patch new file mode 100644 index 000000000..01fe26fac --- /dev/null +++ b/target/linux/aruba-2.6/patches/010-ar2313_enet.patch @@ -0,0 +1,2160 @@ +diff -urN linux.old/drivers/net/Kconfig linux.net/drivers/net/Kconfig +--- linux.old/drivers/net/Kconfig	2006-01-21 20:15:08.279272000 +0100 ++++ linux.net/drivers/net/Kconfig	2006-01-30 01:18:34.910315000 +0100 +@@ -176,6 +176,13 @@ +  + source "drivers/net/arm/Kconfig" +  ++ ++config AR2313 ++		tristate "AR2313 Ethernet support" ++		depends on NET_ETHERNET && MACH_ARUBA ++		help ++		Support for the AR2313 Ethernet part on Aruba AP60/61 ++ + config IDT_RC32434_ETH +         tristate "IDT RC32434 Local Ethernet support" +         depends on NET_ETHERNET +diff -urN linux.old/drivers/net/Makefile linux.net/drivers/net/Makefile +--- linux.old/drivers/net/Makefile	2006-01-21 20:15:08.383226000 +0100 ++++ linux.net/drivers/net/Makefile	2006-01-30 01:18:34.914315250 +0100 +@@ -35,6 +35,7 @@ +  + obj-$(CONFIG_OAKNET) += oaknet.o 8390.o +  ++obj-$(CONFIG_AR2313) += ar2313.o + obj-$(CONFIG_IDT_RC32434_ETH) += rc32434_eth.o + obj-$(CONFIG_DGRS) += dgrs.o + obj-$(CONFIG_VORTEX) += 3c59x.o +diff -urN linux.old/drivers/net/ar2313/ar2313.h linux.net/drivers/net/ar2313/ar2313.h +--- linux.old/drivers/net/ar2313/ar2313.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux.net/drivers/net/ar2313/ar2313.h	2006-01-25 00:35:55.000000000 +0100 +@@ -0,0 +1,190 @@ ++#ifndef _AR2313_H_ ++#define _AR2313_H_ ++ ++#include <linux/config.h> ++#include <asm/bootinfo.h> ++#include "platform.h" ++ ++extern unsigned long mips_machtype; ++ ++#undef ETHERNET_BASE ++#define ETHERNET_BASE ar_eth_base ++#define ETHERNET_SIZE 0x00100000 ++#define ETHERNET_MACS 2 ++ ++#undef DMA_BASE ++#define DMA_BASE      ar_dma_base ++#define DMA_SIZE      0x00100000 ++ ++ ++/* ++ * probe link timer - 5 secs ++ */ ++#define LINK_TIMER    (5*HZ)  ++ ++/* ++ * Interrupt register base address ++ */ ++#define INTERRUPT_BASE    PHYS_TO_K1(ar_int_base) ++ ++/* ++ * Reset Register ++ */ ++#define AR531X_RESET    (AR531X_RESETTMR + 0x0020) ++#define RESET_SYSTEM         0x00000001      /* cold reset full system */ ++#define RESET_PROC           0x00000002      /* cold reset MIPS core */ ++#define RESET_WLAN0          0x00000004      /* cold reset WLAN MAC and BB */ ++#define RESET_EPHY0          0x00000008      /* cold reset ENET0 phy */ ++#define RESET_EPHY1          0x00000010      /* cold reset ENET1 phy */ ++#define RESET_ENET0          0x00000020      /* cold reset ENET0 mac */ ++#define RESET_ENET1          0x00000040      /* cold reset ENET1 mac */ ++ ++#define IS_DMA_TX_INT(X)   (((X) & (DMA_STATUS_TI)) != 0) ++#define IS_DMA_RX_INT(X)   (((X) & (DMA_STATUS_RI)) != 0) ++#define IS_DRIVER_OWNED(X) (((X) & (DMA_TX_OWN))    == 0) ++ ++#ifndef K1_TO_PHYS ++// hack ++#define K1_TO_PHYS(x)   (((unsigned int)(x)) & 0x1FFFFFFF)        /* kseg1 to physical */ ++#endif ++ ++#ifndef PHYS_TO_K1 ++// hack ++#define  PHYS_TO_K1(x)   (((unsigned int)(x)) | 0xA0000000)   /* physical to kseg1 */ ++#endif ++ ++#define AR2313_TX_TIMEOUT (HZ/4) ++ ++/* ++ * Rings ++ */ ++#define DSC_RING_ENTRIES_SIZE	(AR2313_DESCR_ENTRIES * sizeof(struct desc)) ++#define DSC_NEXT(idx)	        ((idx + 1) & (AR2313_DESCR_ENTRIES - 1)) ++ ++static inline int tx_space (u32 csm, u32 prd) ++{ ++	return (csm - prd - 1) & (AR2313_DESCR_ENTRIES - 1); ++} ++ ++#if MAX_SKB_FRAGS ++#define TX_RESERVED	(MAX_SKB_FRAGS+1) /* +1 for message header */ ++#define tx_ring_full(csm, prd)	(tx_space(csm, prd) <= TX_RESERVED) ++#else ++#define tx_ring_full		0 ++#endif ++ ++#define AR2313_MBGET		2 ++#define AR2313_MBSET    	3 ++#define AR2313_PCI_RECONFIG	4 ++#define AR2313_PCI_DUMP  	5 ++#define AR2313_TEST_PANIC	6 ++#define AR2313_TEST_NULLPTR	7 ++#define AR2313_READ_DATA	8 ++#define AR2313_WRITE_DATA	9 ++#define AR2313_GET_VERSION	10 ++#define AR2313_TEST_HANG	11 ++#define AR2313_SYNC		12 ++ ++ ++struct ar2313_cmd { ++	u32	cmd; ++        u32     address;      /* virtual address of image */ ++        u32     length;       /* size of image to download */ ++        u32     mailbox;      /* mailbox to get/set */ ++        u32     data[2];      /* contents of mailbox to read/write */ ++}; ++ ++ ++/* ++ * Struct private for the Sibyte. ++ * ++ * Elements are grouped so variables used by the tx handling goes ++ * together, and will go into the same cache lines etc. in order to ++ * avoid cache line contention between the rx and tx handling on SMP. ++ * ++ * Frequently accessed variables are put at the beginning of the ++ * struct to help the compiler generate better/shorter code. ++ */ ++struct ar2313_private ++{ ++        int			version; ++        u32                     mb[2]; ++	 ++	volatile ETHERNET_STRUCT	*eth_regs; ++	volatile DMA			*dma_regs; ++        volatile u32		        *int_regs; ++ ++	spinlock_t lock; 	/* Serialise access to device */ ++ ++        /* ++	 * RX and TX descriptors, must be adjacent ++	 */ ++        ar2313_descr_t	        *rx_ring; ++        ar2313_descr_t	        *tx_ring; ++ ++ ++        struct sk_buff		**rx_skb; ++        struct sk_buff		**tx_skb; ++ ++	/* ++	 * RX elements ++	 */ ++        u32			rx_skbprd; ++	u32			cur_rx; ++ ++	/* ++	 * TX elements ++	 */ ++	u32			tx_prd; ++        u32		        tx_csm; ++ ++        /* ++	 * Misc elements ++	 */ ++	int			board_idx; ++	char			name[48]; ++	struct net_device_stats stats; ++        struct { ++	    u32 address; ++	    u32 length; ++	    char *mapping; ++	} desc; ++ ++ ++	struct timer_list link_timer; ++	unsigned short phy;  /* merlot phy = 1,  samsung phy = 0x1f */ ++        unsigned short mac; ++	unsigned short link; /* 0 - link down,  1 - link up */ ++        u16 phyData; ++ ++	struct tasklet_struct rx_tasklet; ++	int unloading; ++}; ++ ++ ++/* ++ * Prototypes ++ */ ++static int  ar2313_init(struct net_device *dev); ++#ifdef TX_TIMEOUT ++static void ar2313_tx_timeout(struct net_device *dev); ++#endif ++#if 0 ++static void ar2313_multicast_list(struct net_device *dev); ++#endif ++static int ar2313_restart(struct net_device *dev); ++#if DEBUG ++static void  ar2313_dump_regs(struct net_device *dev); ++#endif ++static void ar2313_load_rx_ring(struct net_device *dev, int bufs); ++static irqreturn_t ar2313_interrupt(int irq, void *dev_id, struct pt_regs *regs); ++static int  ar2313_open(struct net_device *dev); ++static int  ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev); ++static int  ar2313_close(struct net_device *dev); ++static int  ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); ++static void ar2313_init_cleanup(struct net_device *dev); ++static int  ar2313_setup_timer(struct net_device *dev); ++static void ar2313_link_timer_fn(unsigned long data); ++static void ar2313_check_link(struct net_device *dev); ++static struct net_device_stats *ar2313_get_stats(struct net_device *dev); ++#endif /* _AR2313_H_ */ +diff -urN linux.old/drivers/net/ar2313/ar2313_msg.h linux.net/drivers/net/ar2313/ar2313_msg.h +--- linux.old/drivers/net/ar2313/ar2313_msg.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux.net/drivers/net/ar2313/ar2313_msg.h	2006-01-24 22:57:25.000000000 +0100 +@@ -0,0 +1,17 @@ ++#ifndef _AR2313_MSG_H_ ++#define _AR2313_MSG_H_ ++ ++#define AR2313_MTU                     1692 ++#define AR2313_PRIOS                   1 ++#define AR2313_QUEUES                  (2*AR2313_PRIOS) ++ ++#define AR2313_DESCR_ENTRIES           64 ++ ++typedef struct { ++    volatile unsigned int	status;		// OWN, Device control and status. ++    volatile unsigned int	devcs;		// pkt Control bits + Length ++    volatile unsigned int	addr;		// Current Address. ++    volatile unsigned int	descr;		// Next descriptor in chain. ++} ar2313_descr_t; ++ ++#endif /* _AR2313_MSG_H_ */ +diff -urN linux.old/drivers/net/ar2313/dma.h linux.net/drivers/net/ar2313/dma.h +--- linux.old/drivers/net/ar2313/dma.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux.net/drivers/net/ar2313/dma.h	2006-01-24 22:58:45.000000000 +0100 +@@ -0,0 +1,135 @@ ++#ifndef __ARUBA_DMA_H__ ++#define __ARUBA_DMA_H__ ++ ++/******************************************************************************* ++ * ++ * Copyright 2002 Integrated Device Technology, Inc. ++ *		All rights reserved. ++ * ++ * DMA register definition. ++ * ++ * File   : $Id: dma.h,v 1.3 2002/06/06 18:34:03 astichte Exp $ ++ * ++ * Author : ryan.holmQVist@idt.com ++ * Date   : 20011005 ++ * Update : ++ *	    $Log: dma.h,v $ ++ *	    Revision 1.3  2002/06/06 18:34:03  astichte ++ *	    Added XXX_PhysicalAddress and XXX_VirtualAddress ++ *	 ++ *	    Revision 1.2  2002/06/05 18:30:46  astichte ++ *	    Removed IDTField ++ *	 ++ *	    Revision 1.1  2002/05/29 17:33:21  sysarch ++ *	    jba File moved from vcode/include/idt/acacia ++ *	 ++ * ++ ******************************************************************************/ ++ ++#define AR_BIT(x)            (1 << (x)) ++#define DMA_RX_ERR_CRC       AR_BIT(1) ++#define DMA_RX_ERR_DRIB      AR_BIT(2) ++#define DMA_RX_ERR_MII       AR_BIT(3) ++#define DMA_RX_EV2           AR_BIT(5) ++#define DMA_RX_ERR_COL       AR_BIT(6) ++#define DMA_RX_LONG          AR_BIT(7) ++#define DMA_RX_LS            AR_BIT(8)  /* last descriptor */ ++#define DMA_RX_FS            AR_BIT(9)  /* first descriptor */ ++#define DMA_RX_MF            AR_BIT(10) /* multicast frame */ ++#define DMA_RX_ERR_RUNT      AR_BIT(11) /* runt frame */ ++#define DMA_RX_ERR_LENGTH    AR_BIT(12) /* length error */ ++#define DMA_RX_ERR_DESC      AR_BIT(14) /* descriptor error */ ++#define DMA_RX_ERROR         AR_BIT(15) /* error summary */ ++#define DMA_RX_LEN_MASK      0x3fff0000 ++#define DMA_RX_LEN_SHIFT     16 ++#define DMA_RX_FILT          AR_BIT(30) ++#define DMA_RX_OWN           AR_BIT(31) /* desc owned by DMA controller */ ++ ++#define DMA_RX1_BSIZE_MASK   0x000007ff ++#define DMA_RX1_BSIZE_SHIFT  0 ++#define DMA_RX1_CHAINED      AR_BIT(24) ++#define DMA_RX1_RER          AR_BIT(25) ++ ++#define DMA_TX_ERR_UNDER     AR_BIT(1)  /* underflow error */ ++#define DMA_TX_ERR_DEFER     AR_BIT(2)  /* excessive deferral */ ++#define DMA_TX_COL_MASK      0x78 ++#define DMA_TX_COL_SHIFT     3 ++#define DMA_TX_ERR_HB        AR_BIT(7)  /* hearbeat failure */ ++#define DMA_TX_ERR_COL       AR_BIT(8)  /* excessive collisions */ ++#define DMA_TX_ERR_LATE      AR_BIT(9)  /* late collision */ ++#define DMA_TX_ERR_LINK      AR_BIT(10) /* no carrier */ ++#define DMA_TX_ERR_LOSS      AR_BIT(11) /* loss of carrier */ ++#define DMA_TX_ERR_JABBER    AR_BIT(14) /* transmit jabber timeout */ ++#define DMA_TX_ERROR         AR_BIT(15) /* frame aborted */ ++#define DMA_TX_OWN           AR_BIT(31) /* descr owned by DMA controller */ ++ ++#define DMA_TX1_BSIZE_MASK   0x000007ff ++#define DMA_TX1_BSIZE_SHIFT  0 ++#define DMA_TX1_CHAINED      AR_BIT(24) /* chained descriptors */ ++#define DMA_TX1_TER          AR_BIT(25) /* transmit end of ring */ ++#define DMA_TX1_FS           AR_BIT(29) /* first segment */ ++#define DMA_TX1_LS           AR_BIT(30) /* last segment */ ++#define DMA_TX1_IC           AR_BIT(31) /* interrupt on completion */ ++ ++#define RCVPKT_LENGTH(X)     (X  >> 16)               /* Received pkt Length  */ ++ ++#define MAC_CONTROL_RE       AR_BIT(2)  /* receive enable */ ++#define MAC_CONTROL_TE       AR_BIT(3)  /* transmit enable */ ++#define MAC_CONTROL_DC       AR_BIT(5)  /* Deferral check*/ ++#define MAC_CONTROL_ASTP     AR_BIT(8)  /* Auto pad strip */ ++#define MAC_CONTROL_DRTY     AR_BIT(10) /* Disable retry */ ++#define MAC_CONTROL_DBF      AR_BIT(11) /* Disable bcast frames */ ++#define MAC_CONTROL_LCC      AR_BIT(12) /* late collision ctrl */ ++#define MAC_CONTROL_HP       AR_BIT(13) /* Hash Perfect filtering */ ++#define MAC_CONTROL_HASH     AR_BIT(14) /* Unicast hash filtering */ ++#define MAC_CONTROL_HO       AR_BIT(15) /* Hash only filtering */ ++#define MAC_CONTROL_PB       AR_BIT(16) /* Pass Bad frames */ ++#define MAC_CONTROL_IF       AR_BIT(17) /* Inverse filtering */ ++#define MAC_CONTROL_PR       AR_BIT(18) /* promiscuous mode (valid frames only) */ ++#define MAC_CONTROL_PM       AR_BIT(19) /* pass multicast */ ++#define MAC_CONTROL_F        AR_BIT(20) /* full-duplex */ ++#define MAC_CONTROL_DRO      AR_BIT(23) /* Disable Receive Own */ ++#define MAC_CONTROL_HBD      AR_BIT(28) /* heart-beat disabled (MUST BE SET) */ ++#define MAC_CONTROL_BLE      AR_BIT(30) /* big endian mode */ ++#define MAC_CONTROL_RA       AR_BIT(31) /* receive all (valid and invalid frames) */ ++ ++#define MII_ADDR_BUSY        AR_BIT(0) ++#define MII_ADDR_WRITE       AR_BIT(1) ++#define MII_ADDR_REG_SHIFT   6 ++#define MII_ADDR_PHY_SHIFT   11 ++#define MII_DATA_SHIFT       0 ++ ++#define FLOW_CONTROL_FCE     AR_BIT(1) ++ ++#define DMA_BUS_MODE_SWR       AR_BIT(0)  /* software reset */ ++#define DMA_BUS_MODE_BLE       AR_BIT(7)  /* big endian mode */ ++#define DMA_BUS_MODE_PBL_SHIFT 8          /* programmable burst length 32 */ ++#define DMA_BUS_MODE_DBO       AR_BIT(20) /* big-endian descriptors */ ++ ++#define DMA_STATUS_TI        AR_BIT(0)  /* transmit interrupt */ ++#define DMA_STATUS_TPS       AR_BIT(1)  /* transmit process stopped */ ++#define DMA_STATUS_TU        AR_BIT(2)  /* transmit buffer unavailable */ ++#define DMA_STATUS_TJT       AR_BIT(3)  /* transmit buffer timeout */ ++#define DMA_STATUS_UNF       AR_BIT(5)  /* transmit underflow */ ++#define DMA_STATUS_RI        AR_BIT(6)  /* receive interrupt */ ++#define DMA_STATUS_RU        AR_BIT(7)  /* receive buffer unavailable */ ++#define DMA_STATUS_RPS       AR_BIT(8)  /* receive process stopped */ ++#define DMA_STATUS_ETI       AR_BIT(10) /* early transmit interrupt */ ++#define DMA_STATUS_FBE       AR_BIT(13) /* fatal bus interrupt */ ++#define DMA_STATUS_ERI       AR_BIT(14) /* early receive interrupt */ ++#define DMA_STATUS_AIS       AR_BIT(15) /* abnormal interrupt summary */ ++#define DMA_STATUS_NIS       AR_BIT(16) /* normal interrupt summary */ ++#define DMA_STATUS_RS_SHIFT  17         /* receive process state */ ++#define DMA_STATUS_TS_SHIFT  20         /* transmit process state */ ++#define DMA_STATUS_EB_SHIFT  23         /* error bits */ ++ ++#define DMA_CONTROL_SR       AR_BIT(1)  /* start receive */ ++#define DMA_CONTROL_ST       AR_BIT(13) /* start transmit */ ++#define DMA_CONTROL_SF       AR_BIT(21) /* store and forward */ ++ ++#endif	// __ARUBA_DMA_H__ ++ ++ ++ ++ ++ +diff -urN linux.old/drivers/net/ar2313/platform.h linux.net/drivers/net/ar2313/platform.h +--- linux.old/drivers/net/ar2313/platform.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux.net/drivers/net/ar2313/platform.h	2006-01-25 00:10:25.000000000 +0100 +@@ -0,0 +1,128 @@ ++/******************************************************************************** ++   Title:   $Source: platform.h,v $ ++ ++   Author:  Dan Steinberg ++            Copyright Integrated Device Technology 2001 ++ ++   Purpose: AR2313 Register/Bit Definitions ++    ++   Update: ++            $Log: platform.h,v $ ++       ++   Notes:   See Merlot architecture spec for complete details.  Note, all ++            addresses are virtual addresses in kseg1 (Uncached, Unmapped). ++  ++********************************************************************************/ ++ ++#ifndef PLATFORM_H ++#define PLATFORM_H ++ ++#define BIT(x) (1 << (x)) ++ ++#define RESET_BASE        0xBC003020 ++#define RESET_VALUE       0x00000001 ++ ++/******************************************************************** ++ * Device controller  ++ ********************************************************************/ ++typedef struct { ++  volatile unsigned int flash0; ++} DEVICE; ++ ++#define device (*((volatile DEVICE *) DEV_CTL_BASE)) ++ ++// DDRC register ++#define DEV_WP        (1<<26) ++ ++/******************************************************************** ++ * DDR controller  ++ ********************************************************************/ ++typedef struct { ++  volatile unsigned int ddrc0; ++  volatile unsigned int ddrc1; ++  volatile unsigned int ddrrefresh; ++} DDR; ++ ++#define ddr (*((volatile DDR *) DDR_BASE)) ++ ++// DDRC register ++#define DDRC_CS(i)     ((i&0x3)<<0) ++#define DDRC_WE        (1<<2) ++ ++/******************************************************************** ++ * Ethernet interfaces ++ ********************************************************************/ ++#define ETHERNET_BASE    0xB8200000 ++ ++// ++// New Combo structure for Both Eth0 AND eth1 ++// ++typedef struct { ++  volatile unsigned int mac_control;    /* 0x00 */ ++  volatile unsigned int mac_addr[2];    /* 0x04 - 0x08*/ ++  volatile unsigned int mcast_table[2]; /* 0x0c - 0x10 */ ++  volatile unsigned int mii_addr;       /* 0x14 */ ++  volatile unsigned int mii_data;       /* 0x18 */ ++  volatile unsigned int flow_control;   /* 0x1c */ ++  volatile unsigned int vlan_tag;       /* 0x20 */ ++  volatile unsigned int pad[7];         /* 0x24 - 0x3c */ ++  volatile unsigned int ucast_table[8]; /* 0x40-0x5c */ ++   ++} ETHERNET_STRUCT; ++ ++/******************************************************************** ++ * Interrupt controller  ++ ********************************************************************/ ++ ++typedef struct { ++  volatile unsigned int wdog_control;		/* 0x08 */ ++  volatile unsigned int wdog_timer;		/* 0x0c */ ++  volatile unsigned int misc_status;		/* 0x10 */ ++  volatile unsigned int misc_mask;		/* 0x14 */ ++  volatile unsigned int global_status;		/* 0x18 */ ++  volatile unsigned int reserved;		/* 0x1c */ ++  volatile unsigned int reset_control;		/* 0x20 */ ++} INTERRUPT; ++ ++#define interrupt (*((volatile INTERRUPT *) INTERRUPT_BASE)) ++ ++#define INTERRUPT_MISC_TIMER    BIT(0) ++#define INTERRUPT_MISC_AHBPROC  BIT(1) ++#define INTERRUPT_MISC_AHBDMA   BIT(2) ++#define INTERRUPT_MISC_GPIO     BIT(3) ++#define INTERRUPT_MISC_UART     BIT(4) ++#define INTERRUPT_MISC_UARTDMA  BIT(5) ++#define INTERRUPT_MISC_WATCHDOG BIT(6) ++#define INTERRUPT_MISC_LOCAL    BIT(7) ++ ++#define INTERRUPT_GLOBAL_ETH    BIT(2) ++#define INTERRUPT_GLOBAL_WLAN   BIT(3) ++#define INTERRUPT_GLOBAL_MISC   BIT(4) ++#define INTERRUPT_GLOBAL_ITIMER BIT(5) ++ ++/******************************************************************** ++ * DMA controller ++ ********************************************************************/ ++#define DMA_BASE          0xB8201000 ++ ++typedef struct { ++  volatile unsigned int bus_mode;        /* 0x00 (CSR0) */ ++  volatile unsigned int xmt_poll;        /* 0x04 (CSR1) */ ++  volatile unsigned int rcv_poll;        /* 0x08 (CSR2) */ ++  volatile unsigned int rcv_base;        /* 0x0c (CSR3) */ ++  volatile unsigned int xmt_base;        /* 0x10 (CSR4) */ ++  volatile unsigned int status;          /* 0x14 (CSR5) */ ++  volatile unsigned int control;         /* 0x18 (CSR6) */ ++  volatile unsigned int intr_ena;        /* 0x1c (CSR7) */ ++  volatile unsigned int rcv_missed;      /* 0x20 (CSR8) */ ++  volatile unsigned int reserved[11];    /* 0x24-0x4c (CSR9-19) */ ++  volatile unsigned int cur_tx_buf_addr; /* 0x50 (CSR20) */ ++  volatile unsigned int cur_rx_buf_addr; /* 0x50 (CSR21) */ ++} DMA; ++ ++#define dma (*((volatile DMA *) DMA_BASE)) ++ ++// macro to convert from virtual to physical address   ++#define phys_addr(x)      (x & 0x1fffffff)  ++ ++#endif /* PLATFORM_H */ +diff -urN linux.old/drivers/net/ar2313.c linux.net/drivers/net/ar2313.c +--- linux.old/drivers/net/ar2313.c	1970-01-01 01:00:00.000000000 +0100 ++++ linux.net/drivers/net/ar2313.c	2006-01-30 01:21:56.822933750 +0100 +@@ -0,0 +1,1642 @@ ++/* ++ * ar2313.c: Linux driver for the Atheros AR2313 Ethernet device. ++ * ++ * Copyright 2004 by Sameer Dekate, <sdekate@arubanetworks.com>. ++ * ++ * Thanks to Atheros for providing hardware and documentation ++ * enabling me to write this driver. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * Additional credits: ++ * 	This code is taken from John Taylor's Sibyte driver and then  ++ * 	modified for the AR2313. ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/ioport.h> ++#include <linux/pci.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/mm.h> ++#include <linux/highmem.h> ++#include <linux/sockios.h> ++#include <linux/pkt_sched.h> ++#include <linux/compile.h> ++#include <linux/mii.h> ++#include <linux/ethtool.h> ++#include <linux/ctype.h> ++ ++#include <net/sock.h> ++#include <net/ip.h> ++ ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/byteorder.h> ++#include <asm/uaccess.h> ++#include <asm/bootinfo.h> ++ ++extern char *getenv(char *e); ++ ++ ++#undef INDEX_DEBUG ++#define DEBUG     0 ++#define DEBUG_TX  0 ++#define DEBUG_RX  0 ++#define DEBUG_INT 0 ++#define DEBUG_MC  0 ++#define DEBUG_ERR 1 ++ ++#ifndef __exit ++#define __exit ++#endif ++ ++#ifndef min ++#define min(a,b)	(((a)<(b))?(a):(b)) ++#endif ++ ++#ifndef SMP_CACHE_BYTES ++#define SMP_CACHE_BYTES	L1_CACHE_BYTES ++#endif ++ ++#ifndef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev)		{do{} while(0);} ++#define AR2313_MOD_INC_USE_COUNT	MOD_INC_USE_COUNT ++#define AR2313_MOD_DEC_USE_COUNT	MOD_DEC_USE_COUNT ++#else ++#define AR2313_MOD_INC_USE_COUNT	{do{} while(0);} ++#define AR2313_MOD_DEC_USE_COUNT	{do{} while(0);} ++#endif ++ ++#define PHYSADDR(a)		((_ACAST32_ (a)) & 0x1fffffff) ++ ++MODULE_PARM(ethaddr, "s"); ++static char *ethaddr = "00:00:00:00:00:00"; ++MODULE_PARM(ifname, "s"); ++static char *ifname = "bond" ; ++ ++#define AR2313_MBOX_SET_BIT  0x8 ++ ++#define BOARD_IDX_STATIC	0 ++#define BOARD_IDX_OVERFLOW	-1 ++ ++/* margot includes */ ++#include <asm/idt-boards/rc32434/rc32434.h> ++ ++#include "ar2313/ar2313_msg.h" ++#include "ar2313/platform.h" ++#include "ar2313/dma.h" ++#include "ar2313/ar2313.h" ++ ++/* ++ * New interrupt handler strategy: ++ * ++ * An old interrupt handler worked using the traditional method of ++ * replacing an skbuff with a new one when a packet arrives. However ++ * the rx rings do not need to contain a static number of buffer ++ * descriptors, thus it makes sense to move the memory allocation out ++ * of the main interrupt handler and do it in a bottom half handler ++ * and only allocate new buffers when the number of buffers in the ++ * ring is below a certain threshold. In order to avoid starving the ++ * NIC under heavy load it is however necessary to force allocation ++ * when hitting a minimum threshold. The strategy for alloction is as ++ * follows: ++ * ++ *     RX_LOW_BUF_THRES    - allocate buffers in the bottom half ++ *     RX_PANIC_LOW_THRES  - we are very low on buffers, allocate ++ *                           the buffers in the interrupt handler ++ *     RX_RING_THRES       - maximum number of buffers in the rx ring ++ * ++ * One advantagous side effect of this allocation approach is that the ++ * entire rx processing can be done without holding any spin lock ++ * since the rx rings and registers are totally independent of the tx ++ * ring and its registers.  This of course includes the kmalloc's of ++ * new skb's. Thus start_xmit can run in parallel with rx processing ++ * and the memory allocation on SMP systems. ++ * ++ * Note that running the skb reallocation in a bottom half opens up ++ * another can of races which needs to be handled properly. In ++ * particular it can happen that the interrupt handler tries to run ++ * the reallocation while the bottom half is either running on another ++ * CPU or was interrupted on the same CPU. To get around this the ++ * driver uses bitops to prevent the reallocation routines from being ++ * reentered. ++ * ++ * TX handling can also be done without holding any spin lock, wheee ++ * this is fun! since tx_csm is only written to by the interrupt ++ * handler. ++ */ ++ ++/* ++ * Threshold values for RX buffer allocation - the low water marks for ++ * when to start refilling the rings are set to 75% of the ring ++ * sizes. It seems to make sense to refill the rings entirely from the ++ * intrrupt handler once it gets below the panic threshold, that way ++ * we don't risk that the refilling is moved to another CPU when the ++ * one running the interrupt handler just got the slab code hot in its ++ * cache. ++ */ ++#define RX_RING_SIZE		AR2313_DESCR_ENTRIES ++#define RX_PANIC_THRES	        (RX_RING_SIZE/4) ++#define RX_LOW_THRES	        ((3*RX_RING_SIZE)/4) ++#define CRC_LEN                 4 ++#define RX_OFFSET               2 ++ ++#define AR2313_BUFSIZE		(AR2313_MTU + ETH_HLEN + CRC_LEN + RX_OFFSET) ++ ++#ifdef MODULE ++MODULE_AUTHOR("Sameer Dekate<sdekate@arubanetworks.com>"); ++MODULE_DESCRIPTION("AR2313 Ethernet driver"); ++#endif ++ ++#if DEBUG ++static char version[] __initdata =  ++  "ar2313.c: v0.01 2004/01/06  sdekate@arubanetworks.com\n"; ++#endif /* DEBUG */ ++ ++#define virt_to_phys(x) ((u32)(x) & 0x1fffffff) ++ ++// prototypes ++static short armiiread(short phy, short reg); ++static void armiiwrite(short phy, short reg, short data); ++#ifdef TX_TIMEOUT ++static void ar2313_tx_timeout(struct net_device *dev); ++#endif ++static void ar2313_halt(struct net_device *dev); ++static void rx_tasklet_func(unsigned long data); ++static void ar2313_multicast_list(struct net_device *dev); ++ ++static struct net_device *root_dev; ++static int probed __initdata = 0; ++static unsigned long ar_eth_base; ++static unsigned long ar_dma_base; ++static unsigned long ar_int_base; ++static unsigned long ar_int_mac_mask; ++static unsigned long ar_int_phy_mask; ++ ++#ifndef ERR ++#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args) ++#endif ++ ++static int parse_mac_addr(struct net_device *dev, char* macstr){ ++  int i, j; ++  unsigned char result, value; ++   ++  for (i=0; i<6; i++) { ++    result = 0; ++    if (i != 5 && *(macstr+2) != ':') { ++      ERR("invalid mac address format: %d %c\n", ++          i, *(macstr+2)); ++      return -EINVAL; ++    } ++    for (j=0; j<2; j++) { ++      if (isxdigit(*macstr) && (value = isdigit(*macstr) ? *macstr-'0' : ++                                toupper(*macstr)-'A'+10) < 16) ++        { ++          result = result*16 + value; ++          macstr++; ++        } ++      else { ++        ERR("invalid mac address " ++            "character: %c\n", *macstr); ++        return -EINVAL; ++      } ++    } ++     ++    macstr++; ++    dev->dev_addr[i] = result; ++  } ++   ++  return 0; ++} ++ ++ ++int __init ar2313_probe(void) ++{ ++    struct net_device *dev; ++    struct ar2313_private *sp; ++    int version_disp; ++    char name[64] ; ++ ++    if (probed) ++        return -ENODEV; ++    probed++; ++ ++    version_disp = 0; ++    sprintf(name, "%s%%d", ifname) ; ++    dev = alloc_etherdev(sizeof(struct ar2313_private)); ++ ++    if (dev == NULL) { ++	printk(KERN_ERR "ar2313: Unable to allocate net_device structure!\n"); ++	return -ENOMEM; ++    } ++ ++    SET_MODULE_OWNER(dev); ++ ++    sp = dev->priv; ++ ++    sp->link = 0; ++    switch (mips_machtype) { ++    case MACH_ARUBA_AP60: ++        ar_eth_base = 0xb8100000; ++        ar_dma_base = ar_eth_base + 0x1000; ++        ar_int_base = 0x1C003020; ++        ar_int_mac_mask = RESET_ENET0|RESET_ENET1; ++        ar_int_phy_mask = RESET_EPHY0|RESET_EPHY1; ++        sp->mac = 1; ++    	sp->phy = 1; ++        dev->irq = 4; ++        break; ++ ++    case MACH_ARUBA_AP40: ++        ar_eth_base = 0xb0500000; ++        ar_dma_base = ar_eth_base + 0x1000; ++        ar_int_base = 0x11000004; ++        ar_int_mac_mask = 0x800; ++        ar_int_phy_mask = 0x400; ++        sp->mac = 0; ++    	sp->phy = 1; ++        dev->irq = 4; ++        break; ++ ++    case MACH_ARUBA_AP65: ++        ar_eth_base = 0xb8100000; ++        ar_dma_base = ar_eth_base + 0x1000; ++        ar_int_base = 0x1C003020; ++        ar_int_mac_mask = RESET_ENET0|RESET_ENET1; ++        ar_int_phy_mask = RESET_EPHY0|RESET_EPHY1; ++        sp->mac = 0; ++#if 0 ++        // commented out, for now ++ ++        if (mips_machtype == MACH_ARUBA_SAMSUNG) { ++            sp->phy = 0x1f; ++        } else { ++            sp->phy = 1; ++        } ++#else ++        sp->phy = 1; ++#endif ++        dev->irq = 3; ++        break; ++ ++    default: ++        printk("%s: unsupported mips_machtype=0x%lx\n", ++               __FUNCTION__, mips_machtype) ; ++        return -ENODEV; ++    } ++ ++    spin_lock_init(&sp->lock); ++ ++    /* initialize func pointers */ ++    dev->open = &ar2313_open; ++    dev->stop = &ar2313_close; ++    dev->hard_start_xmit = &ar2313_start_xmit; ++ ++    dev->get_stats = &ar2313_get_stats; ++    dev->set_multicast_list = &ar2313_multicast_list; ++#ifdef TX_TIMEOUT ++    dev->tx_timeout = ar2313_tx_timeout; ++    dev->watchdog_timeo = AR2313_TX_TIMEOUT; ++#endif ++    dev->do_ioctl = &ar2313_ioctl; ++ ++    // SAMEER: do we need this? ++    dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA; ++ ++    tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev); ++    tasklet_disable(&sp->rx_tasklet); ++ ++    /* display version info if adapter is found */ ++    if (!version_disp) { ++        /* set display flag to TRUE so that */ ++        /* we only display this string ONCE */ ++	version_disp = 1; ++#if DEBUG ++	printk(version); ++#endif /* DEBUG */ ++    } ++ ++    request_region(PHYSADDR(ETHERNET_BASE), ETHERNET_SIZE*ETHERNET_MACS, ++                   "AR2313ENET"); ++ ++    sp->eth_regs = ioremap_nocache(PHYSADDR(ETHERNET_BASE + ETHERNET_SIZE*sp->mac), ++                                   sizeof(*sp->eth_regs)); ++    if (!sp->eth_regs) { ++	printk("Can't remap eth registers\n"); ++	return(-ENXIO); ++    } ++ ++    sp->dma_regs = ioremap_nocache(PHYSADDR(DMA_BASE + DMA_SIZE*sp->mac), ++                                   sizeof(*sp->dma_regs)); ++    dev->base_addr = (unsigned int) sp->dma_regs; ++    if (!sp->dma_regs) { ++	printk("Can't remap DMA registers\n"); ++	return(-ENXIO); ++    } ++ ++    sp->int_regs = ioremap_nocache(PHYSADDR(INTERRUPT_BASE), ++                                   sizeof(*sp->int_regs)); ++    if (!sp->int_regs) { ++	printk("Can't remap INTERRUPT registers\n"); ++	return(-ENXIO); ++    } ++ ++    strncpy(sp->name, "Atheros AR2313", sizeof (sp->name) - 1); ++    sp->name [sizeof (sp->name) - 1] = '\0'; ++ ++    { ++      char mac[32]; ++      extern char *getenv(char *e); ++      unsigned char def_mac[6] = {0, 0x0b, 0x86, 0xba, 0xdb, 0xad}; ++      memset(mac, 0, 32); ++      memcpy(mac, getenv("ethaddr"), 17); ++      if (parse_mac_addr(dev, mac)){ ++        printk("%s: MAC address not found, using default\n", __func__); ++        memcpy(dev->dev_addr, def_mac, 6); ++      } ++    } ++ ++    sp->board_idx = BOARD_IDX_STATIC; ++ ++    if (ar2313_init(dev)) { ++        /* ++         * ar2313_init() calls ar2313_init_cleanup() on error. ++         */ ++        kfree(dev); ++        return -ENODEV; ++    } ++ ++    if (register_netdev(dev)){ ++      printk("%s: register_netdev failed\n", __func__); ++      return -1; ++    } ++ ++    printk("%s: %s: %02x:%02x:%02x:%02x:%02x:%02x, irq %d\n", ++           dev->name, sp->name,  ++           dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], ++           dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], ++           dev->irq); ++ ++    /* start link poll timer */ ++    ar2313_setup_timer(dev); ++ ++    /* ++     * Register the device ++     */ ++    root_dev = dev; ++ ++    return 0; ++} ++ ++#if 0 ++static void ar2313_dump_regs(struct net_device *dev) ++{ ++    unsigned int *ptr, i; ++    struct ar2313_private *sp = (struct ar2313_private *)dev->priv; ++ ++    ptr = (unsigned int *)sp->eth_regs; ++    for(i=0; i< (sizeof(ETHERNET_STRUCT)/ sizeof(unsigned int)); i++, ptr++) { ++	    printk("ENET: %08x = %08x\n", (int)ptr, *ptr); ++    } ++ ++    ptr = (unsigned int *)sp->dma_regs; ++    for(i=0; i< (sizeof(DMA)/ sizeof(unsigned int)); i++, ptr++) { ++	    printk("DMA: %08x = %08x\n", (int)ptr, *ptr); ++    } ++ ++    ptr = (unsigned int *)sp->int_regs; ++    for(i=0; i< (sizeof(INTERRUPT)/ sizeof(unsigned int)); i++, ptr++){ ++	    printk("INT: %08x = %08x\n", (int)ptr, *ptr); ++    } ++ ++    for (i = 0; i < AR2313_DESCR_ENTRIES; i++) { ++	ar2313_descr_t *td = &sp->tx_ring[i]; ++        printk("Tx desc %2d: %08x %08x %08x %08x\n", i, ++               td->status, td->devcs, td->addr, td->descr); ++    } ++} ++#endif ++ ++#ifdef TX_TIMEOUT ++static void ++ar2313_tx_timeout(struct net_device *dev) ++{ ++    struct ar2313_private *sp = (struct ar2313_private *)dev->priv; ++    unsigned long flags; ++	 ++#if DEBUG_TX ++    printk("Tx timeout\n"); ++#endif ++    spin_lock_irqsave(&sp->lock, flags); ++    ar2313_restart(dev); ++    spin_unlock_irqrestore(&sp->lock, flags); ++} ++#endif ++ ++#if DEBUG_MC ++static void ++printMcList(struct net_device *dev) ++{ ++    struct dev_mc_list *list = dev->mc_list; ++    int num=0, i; ++    while(list){ ++    	printk("%d MC ADDR ", num); ++    	for(i=0;i<list->dmi_addrlen;i++) { ++    	    printk(":%02x", list->dmi_addr[i]); ++    	} ++	list = list->next; ++    	printk("\n"); ++    } ++} ++#endif ++ ++/* ++ * Set or clear the multicast filter for this adaptor. ++ * THIS IS ABSOLUTE CRAP, disabled ++ */ ++static void ++ar2313_multicast_list(struct net_device *dev) ++{    ++    /*  ++     * Always listen to broadcasts and  ++     * treat IFF bits independently  ++     */ ++    struct ar2313_private *sp = (struct ar2313_private *)dev->priv; ++    unsigned int recognise; ++ ++    recognise = sp->eth_regs->mac_control; ++ ++    if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ ++    	recognise |= MAC_CONTROL_PR; ++    } else { ++    	recognise &= ~MAC_CONTROL_PR; ++    } ++ ++    if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) { ++#if DEBUG_MC ++	printMcList(dev); ++    	printk("%s: all MULTICAST mc_count %d\n", __FUNCTION__, dev->mc_count); ++#endif ++    	recognise |= MAC_CONTROL_PM;/* all multicast */ ++    } else if (dev->mc_count > 0) { ++#if DEBUG_MC ++	printMcList(dev); ++    	printk("%s: mc_count %d\n", __FUNCTION__, dev->mc_count); ++#endif ++    	recognise |= MAC_CONTROL_PM; /* for the time being */ ++    } ++#if DEBUG_MC ++    printk("%s: setting %08x to %08x\n", __FUNCTION__, (int)sp->eth_regs, recognise); ++#endif ++	 ++    sp->eth_regs->mac_control = recognise; ++} ++ ++static void rx_tasklet_cleanup(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++ ++    /* ++     * Tasklet may be scheduled. Need to get it removed from the list ++     * since we're about to free the struct. ++     */ ++ ++    sp->unloading = 1; ++    tasklet_enable(&sp->rx_tasklet); ++    tasklet_kill(&sp->rx_tasklet); ++} ++ ++static void __exit ar2313_module_cleanup(void) ++{ ++    rx_tasklet_cleanup(root_dev); ++    ar2313_init_cleanup(root_dev); ++    unregister_netdev(root_dev); ++    kfree(root_dev); ++    release_region(PHYSADDR(ETHERNET_BASE), ETHERNET_SIZE*ETHERNET_MACS); ++} ++ ++ ++/* ++ * Restart the AR2313 ethernet controller.  ++ */ ++static int ar2313_restart(struct net_device *dev) ++{ ++    /* disable interrupts */ ++    disable_irq(dev->irq); ++ ++    /* stop mac */ ++    ar2313_halt(dev); ++     ++    /* initialize */ ++    ar2313_init(dev); ++     ++    /* enable interrupts */ ++    enable_irq(dev->irq); ++     ++    return 0; ++} ++ ++extern unsigned long mips_machtype; ++ ++int __init ar2313_module_init(void) ++{ ++    int status=-1; ++    switch (mips_machtype){ ++    case MACH_ARUBA_AP60: ++    case MACH_ARUBA_AP65: ++    case MACH_ARUBA_AP40: ++    	root_dev = NULL; ++    	status = ar2313_probe(); ++        break; ++    } ++    return status; ++} ++ ++ ++module_init(ar2313_module_init); ++module_exit(ar2313_module_cleanup); ++ ++ ++static void ar2313_free_descriptors(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    if (sp->rx_ring != NULL) { ++	kfree((void*)KSEG0ADDR(sp->rx_ring)); ++	sp->rx_ring = NULL; ++	sp->tx_ring = NULL; ++    } ++} ++ ++ ++static int ar2313_allocate_descriptors(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    int size; ++    int j; ++    ar2313_descr_t *space; ++ ++    if(sp->rx_ring != NULL){ ++	printk("%s: already done.\n", __FUNCTION__); ++	return 0; ++    } ++ ++    size = (sizeof(ar2313_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES)); ++    space = kmalloc(size, GFP_KERNEL); ++    if (space == NULL) ++        return 1; ++ ++    /* invalidate caches */ ++    dma_cache_inv((unsigned int)space, size); ++ ++    /* now convert pointer to KSEG1 */ ++    space = (ar2313_descr_t *)KSEG1ADDR(space); ++ ++    memset((void *)space, 0, size); ++ ++    sp->rx_ring = space; ++    space += AR2313_DESCR_ENTRIES; ++ ++    sp->tx_ring = space; ++    space += AR2313_DESCR_ENTRIES; ++ ++    /* Initialize the transmit Descriptors */ ++    for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { ++	ar2313_descr_t *td = &sp->tx_ring[j]; ++	td->status = 0; ++	td->devcs  = DMA_TX1_CHAINED; ++	td->addr   = 0; ++	td->descr  = K1_TO_PHYS(&sp->tx_ring[(j+1) & (AR2313_DESCR_ENTRIES-1)]); ++    } ++ ++    return 0; ++} ++ ++ ++/* ++ * Generic cleanup handling data allocated during init. Used when the ++ * module is unloaded or if an error occurs during initialization ++ */ ++static void ar2313_init_cleanup(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    struct sk_buff *skb; ++    int j; ++ ++    ar2313_free_descriptors(dev); ++ ++    if (sp->eth_regs) iounmap((void*)sp->eth_regs); ++    if (sp->dma_regs) iounmap((void*)sp->dma_regs); ++ ++    if (sp->rx_skb) { ++	for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { ++	    skb = sp->rx_skb[j]; ++	    if (skb) { ++		sp->rx_skb[j] = NULL; ++		dev_kfree_skb(skb); ++	    } ++	} ++	kfree(sp->rx_skb); ++	sp->rx_skb = NULL; ++    } ++ ++    if (sp->tx_skb) { ++	for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { ++	    skb = sp->tx_skb[j]; ++	    if (skb) { ++		sp->tx_skb[j] = NULL; ++		dev_kfree_skb(skb); ++	    } ++	} ++	kfree(sp->tx_skb); ++	sp->tx_skb = NULL; ++    } ++} ++ ++static int ar2313_setup_timer(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv;  ++ ++    init_timer(&sp->link_timer); ++ ++    sp->link_timer.function = ar2313_link_timer_fn; ++    sp->link_timer.data = (int) dev; ++    sp->link_timer.expires = jiffies + HZ; ++ ++    add_timer(&sp->link_timer); ++    return 0; ++ ++} ++ ++static void ar2313_link_timer_fn(unsigned long data) ++{ ++    struct net_device *dev = (struct net_device *) data; ++    struct ar2313_private *sp = dev->priv;  ++ ++    // see if the link status changed ++    // This was needed to make sure we set the PHY to the ++    // autonegotiated value of half or full duplex. ++    ar2313_check_link(dev); ++     ++    // Loop faster when we don't have link.  ++    // This was needed to speed up the AP bootstrap time. ++    if(sp->link == 0) { ++    	mod_timer(&sp->link_timer, jiffies + HZ/2); ++    } else { ++    	mod_timer(&sp->link_timer, jiffies + LINK_TIMER); ++    } ++} ++ ++static void ar2313_check_link(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    u16 phyData; ++ ++    phyData = armiiread(sp->phy, MII_BMSR); ++    if (sp->phyData != phyData) { ++	if (phyData & BMSR_LSTATUS) { ++            /* link is present, ready link partner ability to deterine duplexity */ ++            int duplex = 0; ++            u16 reg; ++ ++            sp->link = 1; ++            reg = armiiread(sp->phy, MII_BMCR); ++            if (reg & BMCR_ANENABLE) { ++                /* auto neg enabled */ ++                reg = armiiread(sp->phy, MII_LPA); ++                duplex = (reg & (LPA_100FULL|LPA_10FULL))? 1:0; ++            } else { ++                /* no auto neg, just read duplex config */ ++                duplex = (reg & BMCR_FULLDPLX)? 1:0; ++            } ++ ++            printk(KERN_INFO "%s: Configuring MAC for %s duplex\n", dev->name, ++                   (duplex)? "full":"half"); ++ ++            if (duplex) { ++                /* full duplex */ ++                sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_F) & ++                                             ~MAC_CONTROL_DRO); ++            } else { ++                /* half duplex */ ++                sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_DRO) & ++                                             ~MAC_CONTROL_F); ++            } ++    	} else { ++            /* no link */ ++            sp->link = 0; ++    	} ++        sp->phyData = phyData; ++    } ++} ++   ++static int ++ar2313_reset_reg(struct net_device *dev) ++{ ++    struct ar2313_private *sp = (struct ar2313_private *)dev->priv; ++    unsigned int ethsal, ethsah; ++    unsigned int flags; ++ ++    *sp->int_regs |= ar_int_mac_mask; ++    mdelay(10); ++    *sp->int_regs &= ~ar_int_mac_mask; ++    mdelay(10); ++    *sp->int_regs |= ar_int_phy_mask; ++    mdelay(10); ++    *sp->int_regs &= ~ar_int_phy_mask; ++    mdelay(10); ++ ++    sp->dma_regs->bus_mode = (DMA_BUS_MODE_SWR); ++    mdelay(10); ++    sp->dma_regs->bus_mode = ((32 << DMA_BUS_MODE_PBL_SHIFT) | DMA_BUS_MODE_BLE); ++ ++    /* enable interrupts */ ++    sp->dma_regs->intr_ena = (DMA_STATUS_AIS | ++			      DMA_STATUS_NIS | ++			      DMA_STATUS_RI  | ++			      DMA_STATUS_TI  | ++			      DMA_STATUS_FBE); ++    sp->dma_regs->xmt_base = K1_TO_PHYS(sp->tx_ring); ++    sp->dma_regs->rcv_base = K1_TO_PHYS(sp->rx_ring); ++    sp->dma_regs->control = (DMA_CONTROL_SR | DMA_CONTROL_ST | DMA_CONTROL_SF); ++     ++    sp->eth_regs->flow_control = (FLOW_CONTROL_FCE); ++    sp->eth_regs->vlan_tag = (0x8100); ++ ++    /* Enable Ethernet Interface */ ++    flags = (MAC_CONTROL_TE  | /* transmit enable */ ++	     MAC_CONTROL_PM  | /* pass mcast */ ++	     MAC_CONTROL_F   | /* full duplex */ ++	     MAC_CONTROL_HBD); /* heart beat disabled */ ++ ++    if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ ++	flags |= MAC_CONTROL_PR; ++    } ++    sp->eth_regs->mac_control = flags; ++ ++    /* Set all Ethernet station address registers to their initial values */ ++    ethsah = ((((u_int)(dev->dev_addr[5]) << 8) & (u_int)0x0000FF00) | ++	      (((u_int)(dev->dev_addr[4]) << 0) & (u_int)0x000000FF)); ++ ++    ethsal = ((((u_int)(dev->dev_addr[3]) << 24) & (u_int)0xFF000000) | ++              (((u_int)(dev->dev_addr[2]) << 16) & (u_int)0x00FF0000) | ++              (((u_int)(dev->dev_addr[1]) <<  8) & (u_int)0x0000FF00) | ++              (((u_int)(dev->dev_addr[0]) <<  0) & (u_int)0x000000FF) ); ++ ++    sp->eth_regs->mac_addr[0] = ethsah; ++    sp->eth_regs->mac_addr[1] = ethsal; ++ ++    mdelay(10); ++ ++    return(0); ++} ++ ++ ++static int ar2313_init(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    int ecode=0; ++ ++    /* ++     * Allocate descriptors ++     */ ++    if (ar2313_allocate_descriptors(dev)) { ++	printk("%s: %s: ar2313_allocate_descriptors failed\n",  ++			dev->name, __FUNCTION__); ++	ecode = -EAGAIN; ++        goto init_error; ++    } ++ ++    /* ++     * Get the memory for the skb rings. ++     */ ++    if(sp->rx_skb == NULL) { ++	sp->rx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL); ++	if (!(sp->rx_skb)) { ++	    printk("%s: %s: rx_skb kmalloc failed\n",  ++			    dev->name, __FUNCTION__); ++	    ecode = -EAGAIN; ++	    goto init_error; ++	} ++    } ++    memset(sp->rx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES); ++ ++    if(sp->tx_skb == NULL) { ++	sp->tx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL); ++	if (!(sp->tx_skb)) { ++	    printk("%s: %s: tx_skb kmalloc failed\n",  ++			    dev->name, __FUNCTION__); ++	    ecode = -EAGAIN; ++	    goto init_error; ++	} ++    } ++    memset(sp->tx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES); ++ ++    /* ++     * Set tx_csm before we start receiving interrupts, otherwise ++     * the interrupt handler might think it is supposed to process ++     * tx ints before we are up and running, which may cause a null ++     * pointer access in the int handler. ++     */ ++    sp->rx_skbprd = 0; ++    sp->cur_rx = 0; ++    sp->tx_prd = 0; ++    sp->tx_csm = 0; ++ ++    /* ++     * Zero the stats before starting the interface ++     */ ++    memset(&sp->stats, 0, sizeof(sp->stats)); ++ ++    /* ++     * We load the ring here as there seem to be no way to tell the ++     * firmware to wipe the ring without re-initializing it. ++     */ ++    ar2313_load_rx_ring(dev, RX_RING_SIZE); ++ ++    /*  ++     * Init hardware ++     */ ++    ar2313_reset_reg(dev); ++ ++    /* ++     * Get the IRQ ++     */ ++    ecode = request_irq(dev->irq, &ar2313_interrupt, SA_SHIRQ | SA_INTERRUPT, dev->name, dev); ++    if (ecode) { ++        printk(KERN_WARNING "%s: %s: Requested IRQ %d is busy\n", ++	       dev->name, __FUNCTION__, dev->irq); ++	goto init_error; ++    } ++ ++#if 0 ++    // commented out, for now ++ ++    if(mips_machtype == MACH_ARUBA_SAMSUNG) { ++      int i; ++        /* configure Marvell 88E6060 */ ++        /* reset chip */ ++        armiiwrite(0x1f, 0xa, 0xa130); ++        do { ++            udelay(1000); ++            i = armiiread(sp->phy, 0xa); ++        } while (i & 0x8000); ++       ++        /* configure MAC address */ ++        armiiwrite(sp->phy, 0x1, dev->dev_addr[0] << 8 | dev->dev_addr[1]); ++        armiiwrite(sp->phy, 0x2, dev->dev_addr[2] << 8 | dev->dev_addr[3]); ++        armiiwrite(sp->phy, 0x3, dev->dev_addr[4] << 8 | dev->dev_addr[5]); ++       ++        /* set ports to forwarding */ ++        armiiwrite(0x18, 0x4, 0x3); ++        armiiwrite(0x1c, 0x4, 0x3); ++        armiiwrite(0x1d, 0x4, 0x3); ++    } ++#endif ++ ++    tasklet_enable(&sp->rx_tasklet); ++ ++    return 0; ++ ++ init_error: ++    ar2313_init_cleanup(dev); ++    return ecode; ++} ++ ++/* ++ * Load the rx ring. ++ * ++ * Loading rings is safe without holding the spin lock since this is ++ * done only before the device is enabled, thus no interrupts are ++ * generated and by the interrupt handler/tasklet handler. ++ */ ++static void ar2313_load_rx_ring(struct net_device *dev, int nr_bufs) ++{ ++ ++    struct ar2313_private *sp = ((struct net_device *)dev)->priv; ++    short i, idx; ++ ++    idx = sp->rx_skbprd; ++ ++    for (i = 0; i < nr_bufs; i++) { ++        struct sk_buff *skb; ++	ar2313_descr_t *rd; ++ ++	if (sp->rx_skb[idx]) { ++#if DEBUG_RX ++	    printk(KERN_INFO "ar2313 rx refill full\n"); ++#endif /* DEBUG */ ++	    break; ++	} ++ ++        // partha: create additional room for the second GRE fragment ++	skb = alloc_skb(AR2313_BUFSIZE+128, GFP_ATOMIC); ++	if (!skb) { ++	    printk("\n\n\n\n %s: No memory in system\n\n\n\n", __FUNCTION__); ++	    break; ++	} ++        // partha: create additional room in the front for tx pkt capture ++        skb_reserve(skb, 32); ++ ++	/* ++	 * Make sure IP header starts on a fresh cache line. ++	 */ ++	skb->dev = dev; ++	skb_reserve(skb, RX_OFFSET); ++	sp->rx_skb[idx] = skb; ++ ++	rd = (ar2313_descr_t *) &sp->rx_ring[idx]; ++ ++	/* initialize dma descriptor */ ++	rd->devcs  = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) | ++                      DMA_RX1_CHAINED); ++	rd->addr   = virt_to_phys(skb->data); ++	rd->descr  = virt_to_phys(&sp->rx_ring[(idx+1) & (AR2313_DESCR_ENTRIES-1)]); ++	rd->status = DMA_RX_OWN; ++ ++	idx = DSC_NEXT(idx); ++    } ++ ++    if (!i) { ++#if DEBUG_ERR ++        printk(KERN_INFO "Out of memory when allocating standard receive buffers\n"); ++#endif /* DEBUG */ ++    } else { ++	sp->rx_skbprd = idx; ++    } ++ ++    return; ++} ++ ++#define AR2313_MAX_PKTS_PER_CALL        64 ++ ++static int ar2313_rx_int(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    struct sk_buff *skb, *skb_new; ++    ar2313_descr_t *rxdesc; ++    unsigned int status; ++    u32 idx; ++    int pkts = 0; ++    int rval; ++ ++    idx = sp->cur_rx; ++ ++    /* process at most the entire ring and then wait for another interrupt */ ++    while(1) { ++ ++	rxdesc = &sp->rx_ring[idx]; ++	status = rxdesc->status; ++	if (status & DMA_RX_OWN) { ++	    /* SiByte owns descriptor or descr not yet filled in */ ++            rval = 0; ++	    break; ++	} ++ ++        if (++pkts > AR2313_MAX_PKTS_PER_CALL) { ++            rval = 1; ++            break; ++        } ++ ++#if DEBUG_RX ++	printk("index %d\n", idx); ++	printk("RX status %08x\n", rxdesc->status); ++	printk("RX devcs  %08x\n", rxdesc->devcs ); ++	printk("RX addr   %08x\n", rxdesc->addr  ); ++	printk("RX descr  %08x\n", rxdesc->descr ); ++#endif ++ ++        if ((status & (DMA_RX_ERROR|DMA_RX_ERR_LENGTH)) && ++	    (!(status & DMA_RX_LONG))){ ++#if DEBUG_RX ++	    printk("%s: rx ERROR %08x\n", __FUNCTION__, status); ++#endif ++	    sp->stats.rx_errors++; ++	    sp->stats.rx_dropped++; ++ ++	    /* add statistics counters */ ++	    if (status & DMA_RX_ERR_CRC)    sp->stats.rx_crc_errors++; ++	    if (status & DMA_RX_ERR_COL)    sp->stats.rx_over_errors++; ++	    if (status & DMA_RX_ERR_LENGTH) ++		    sp->stats.rx_length_errors++; ++	    if (status & DMA_RX_ERR_RUNT)   sp->stats.rx_over_errors++; ++	    if (status & DMA_RX_ERR_DESC)   sp->stats.rx_over_errors++; ++ ++	} else { ++	    /* alloc new buffer. */ ++	    skb_new = dev_alloc_skb(AR2313_BUFSIZE + RX_OFFSET + 128); ++	    if (skb_new != NULL) { ++ ++                skb = sp->rx_skb[idx]; ++		/* set skb */ ++                skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN); ++ ++#ifdef CONFIG_MERLOT ++		if ((dev->am_pkt_handler == NULL) ||  ++                    (dev->am_pkt_handler(skb, dev) == 0)) { ++#endif ++                  sp->stats.rx_bytes += skb->len; ++                  skb->protocol = eth_type_trans(skb, dev); ++                  /* pass the packet to upper layers */ ++ ++#ifdef CONFIG_MERLOT ++                  if (dev->asap_netif_rx) ++                      dev->asap_netif_rx(skb); ++                  else ++#endif ++                  netif_rx(skb); ++#ifdef CONFIG_MERLOT ++		} ++#endif ++		skb_new->dev = dev; ++		/* 16 bit align */ ++		skb_reserve(skb_new, RX_OFFSET+32); ++		/* reset descriptor's curr_addr */ ++		rxdesc->addr = virt_to_phys(skb_new->data);  ++ ++		sp->stats.rx_packets++; ++		sp->rx_skb[idx] = skb_new; ++ ++	    } else { ++		sp->stats.rx_dropped++; ++	    } ++	} ++ ++	rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |  ++                         DMA_RX1_CHAINED); ++	rxdesc->status = DMA_RX_OWN; ++ ++	idx = DSC_NEXT(idx); ++    } ++ ++    sp->cur_rx = idx; ++ ++    return rval; ++} ++ ++ ++static void ar2313_tx_int(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    u32 idx; ++    struct sk_buff *skb; ++    ar2313_descr_t *txdesc; ++    unsigned int status=0; ++ ++    idx = sp->tx_csm; ++ ++    while (idx != sp->tx_prd) { ++ ++	txdesc = &sp->tx_ring[idx]; ++ ++#if DEBUG_TX ++	printk("%s: TXINT: csm=%d idx=%d prd=%d status=%x devcs=%x addr=%08x descr=%x\n",  ++		dev->name, sp->tx_csm, idx, sp->tx_prd, ++	       	txdesc->status, txdesc->devcs, txdesc->addr, txdesc->descr); ++#endif /* DEBUG */ ++ ++	if ((status = txdesc->status) & DMA_TX_OWN) { ++	    /* ar2313 dma still owns descr */ ++	    break; ++	} ++	/* done with this descriptor */ ++	txdesc->status = 0; ++ ++	if (status & DMA_TX_ERROR){ ++		sp->stats.tx_errors++; ++		sp->stats.tx_dropped++; ++		if(status & DMA_TX_ERR_UNDER) ++                    sp->stats.tx_fifo_errors++; ++		if(status & DMA_TX_ERR_HB) ++                    sp->stats.tx_heartbeat_errors++; ++		if(status & (DMA_TX_ERR_LOSS | ++                             DMA_TX_ERR_LINK)) ++                    sp->stats.tx_carrier_errors++; ++                if (status & (DMA_TX_ERR_LATE| ++                              DMA_TX_ERR_COL | ++                              DMA_TX_ERR_JABBER | ++                              DMA_TX_ERR_DEFER)) ++                    sp->stats.tx_aborted_errors++; ++	} else { ++		/* transmit OK */ ++		sp->stats.tx_packets++; ++	} ++ ++	skb = sp->tx_skb[idx]; ++	sp->tx_skb[idx] = NULL; ++	idx = DSC_NEXT(idx); ++	sp->stats.tx_bytes += skb->len; ++	dev_kfree_skb_irq(skb); ++    } ++ ++    sp->tx_csm = idx; ++ ++    return; ++} ++ ++ ++static void ++rx_tasklet_func(unsigned long data) ++{ ++	struct net_device *dev = (struct net_device *) data; ++	struct ar2313_private *sp = dev->priv; ++ ++	if (sp->unloading) { ++	    return; ++	} ++ ++        if (ar2313_rx_int(dev)) { ++            tasklet_hi_schedule(&sp->rx_tasklet); ++        } ++        else { ++            unsigned long flags; ++            spin_lock_irqsave(&sp->lock, flags); ++            sp->dma_regs->intr_ena |= DMA_STATUS_RI; ++            spin_unlock_irqrestore(&sp->lock, flags); ++        } ++} ++ ++static void ++rx_schedule(struct net_device *dev) ++{ ++	struct ar2313_private *sp = dev->priv; ++ ++	sp->dma_regs->intr_ena &= ~DMA_STATUS_RI; ++ ++	tasklet_hi_schedule(&sp->rx_tasklet); ++} ++ ++static irqreturn_t ar2313_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) ++{ ++    struct net_device *dev = (struct net_device *)dev_id; ++    struct ar2313_private *sp = dev->priv; ++    unsigned int status, enabled; ++ ++    /* clear interrupt */ ++    /* ++     * Don't clear RI bit if currently disabled. ++     */ ++    status = sp->dma_regs->status; ++    enabled = sp->dma_regs->intr_ena; ++    sp->dma_regs->status = status & enabled; ++ ++    if (status & DMA_STATUS_NIS) { ++	/* normal status */ ++        /* ++         * Don't schedule rx processing if interrupt ++         * is already disabled. ++         */ ++	if (status & enabled & DMA_STATUS_RI) { ++	    /* receive interrupt */ ++	    rx_schedule(dev); ++	} ++	if (status & DMA_STATUS_TI) { ++	   /* transmit interrupt */ ++	    ar2313_tx_int(dev); ++	} ++    } ++ ++    if (status & DMA_STATUS_AIS) { ++#if DEBUG_INT ++        printk("%s: AIS set %08x & %x\n", __FUNCTION__, ++               status, (DMA_STATUS_FBE | DMA_STATUS_TPS)); ++#endif ++	/* abnormal status */ ++	if (status & (DMA_STATUS_FBE | DMA_STATUS_TPS)) { ++	    ar2313_restart(dev); ++	} ++    } ++    return IRQ_RETVAL(0); ++} ++ ++ ++static int ar2313_open(struct net_device *dev) ++{ ++    struct ar2313_private *sp; ++ ++    sp = dev->priv; ++ ++    dev->mtu = 1500; ++    netif_start_queue(dev); ++ ++    sp->eth_regs->mac_control |= MAC_CONTROL_RE; ++ ++    AR2313_MOD_INC_USE_COUNT; ++ ++    return 0; ++} ++ ++static void ar2313_halt(struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    int j; ++ ++    tasklet_disable(&sp->rx_tasklet); ++ ++    /* kill the MAC */ ++    sp->eth_regs->mac_control &= ~(MAC_CONTROL_RE | /* disable Receives */ ++                                   MAC_CONTROL_TE); /* disable Transmits */ ++    /* stop dma */ ++    sp->dma_regs->control = 0; ++    sp->dma_regs->bus_mode = DMA_BUS_MODE_SWR; ++ ++    /* place phy and MAC in reset */ ++    *sp->int_regs |= (ar_int_mac_mask | ar_int_phy_mask); ++ ++    /* free buffers on tx ring */ ++    for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { ++	struct sk_buff *skb; ++	ar2313_descr_t *txdesc; ++ ++	txdesc = &sp->tx_ring[j]; ++	txdesc->descr = 0; ++ ++	skb = sp->tx_skb[j]; ++	if (skb) { ++	    dev_kfree_skb(skb); ++	    sp->tx_skb[j] = NULL; ++	} ++    } ++} ++ ++/* ++ * close should do nothing. Here's why. It's called when ++ * 'ifconfig bond0 down' is run. If it calls free_irq then ++ * the irq is gone forever ! When bond0 is made 'up' again, ++ * the ar2313_open () does not call request_irq (). Worse, ++ * the call to ar2313_halt() generates a WDOG reset due to ++ * the write to 'sp->int_regs' and the box reboots. ++ * Commenting this out is good since it allows the ++ * system to resume when bond0 is made up again. ++ */ ++static int ar2313_close(struct net_device *dev) ++{ ++#if 0 ++    /* ++     * Disable interrupts ++     */ ++    disable_irq(dev->irq); ++    	 ++    /* ++     * Without (or before) releasing irq and stopping hardware, this ++     * is an absolute non-sense, by the way. It will be reset instantly ++     * by the first irq. ++     */ ++    netif_stop_queue(dev); ++ ++    /* stop the MAC and DMA engines */ ++    ar2313_halt(dev); ++ ++    /* release the interrupt */ ++    free_irq(dev->irq, dev); ++ ++#endif ++    AR2313_MOD_DEC_USE_COUNT; ++    return 0; ++} ++ ++static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++    struct ar2313_private *sp = dev->priv; ++    ar2313_descr_t *td; ++    u32 idx; ++ ++    idx = sp->tx_prd; ++    td = &sp->tx_ring[idx]; ++ ++    if (td->status & DMA_TX_OWN) { ++#if DEBUG_TX ++	printk("%s: No space left to Tx\n", __FUNCTION__); ++#endif ++        /* free skbuf and lie to the caller that we sent it out */ ++        sp->stats.tx_dropped++; ++	dev_kfree_skb(skb); ++ ++        /* restart transmitter in case locked */ ++        sp->dma_regs->xmt_poll = 0; ++	return 0; ++    } ++ ++    /* Setup the transmit descriptor. */ ++    td->devcs = ((skb->len << DMA_TX1_BSIZE_SHIFT) |  ++                 (DMA_TX1_LS|DMA_TX1_IC|DMA_TX1_CHAINED)); ++    td->addr = virt_to_phys(skb->data); ++    td->status = DMA_TX_OWN; ++ ++    /* kick transmitter last */ ++    sp->dma_regs->xmt_poll = 0; ++ ++#if DEBUG_TX ++    printk("index %d\n", idx); ++    printk("TX status %08x\n", td->status); ++    printk("TX devcs  %08x\n", td->devcs ); ++    printk("TX addr   %08x\n", td->addr  ); ++    printk("TX descr  %08x\n", td->descr ); ++#endif ++ ++    sp->tx_skb[idx] = skb; ++    idx = DSC_NEXT(idx); ++    sp->tx_prd = idx; ++ ++    //dev->trans_start = jiffies; ++ ++    return 0; ++} ++ ++static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ++{ ++	struct ar2313_private *np = dev->priv; ++	u32 tmp; ++ ++	ecmd->supported =  ++		(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | ++		SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | ++		SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); ++	 ++        ecmd->port = PORT_TP; ++	/* only supports internal transceiver */ ++	ecmd->transceiver = XCVR_INTERNAL; ++	/* not sure what this is for */ ++	ecmd->phy_address = 1; ++ ++	ecmd->advertising = ADVERTISED_MII; ++	tmp = armiiread(np->phy, MII_ADVERTISE); ++	if (tmp & ADVERTISE_10HALF) ++		ecmd->advertising |= ADVERTISED_10baseT_Half; ++	if (tmp & ADVERTISE_10FULL) ++		ecmd->advertising |= ADVERTISED_10baseT_Full; ++	if (tmp & ADVERTISE_100HALF) ++		ecmd->advertising |= ADVERTISED_100baseT_Half; ++	if (tmp & ADVERTISE_100FULL) ++		ecmd->advertising |= ADVERTISED_100baseT_Full; ++ ++	tmp = armiiread(np->phy, MII_BMCR); ++	if (tmp & BMCR_ANENABLE) { ++		ecmd->advertising |= ADVERTISED_Autoneg; ++		ecmd->autoneg = AUTONEG_ENABLE; ++	} else { ++		ecmd->autoneg = AUTONEG_DISABLE; ++	} ++ ++        if (ecmd->autoneg == AUTONEG_ENABLE) { ++            tmp = armiiread(np->phy, MII_LPA); ++            if (tmp & (LPA_100FULL|LPA_10FULL)) { ++                ecmd->duplex = DUPLEX_FULL; ++            } else { ++                ecmd->duplex = DUPLEX_HALF; ++            } ++            if (tmp & (LPA_100FULL|LPA_100HALF)) { ++		ecmd->speed = SPEED_100; ++            } else { ++		ecmd->speed = SPEED_10; ++            } ++        } else { ++            if (tmp & BMCR_FULLDPLX) { ++                ecmd->duplex = DUPLEX_FULL; ++            } else { ++                ecmd->duplex = DUPLEX_HALF; ++            } ++            if (tmp & BMCR_SPEED100) { ++		ecmd->speed = SPEED_100; ++            } else { ++		ecmd->speed = SPEED_10; ++            } ++	} ++ ++	/* ignore maxtxpkt, maxrxpkt for now */ ++ ++	return 0; ++} ++ ++static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ++{ ++	struct ar2313_private *np = dev->priv; ++	u32 tmp; ++ ++	if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) ++		return -EINVAL; ++	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) ++		return -EINVAL; ++	if (ecmd->port != PORT_TP) ++		return -EINVAL; ++	if (ecmd->transceiver != XCVR_INTERNAL) ++		return -EINVAL; ++	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) ++		return -EINVAL; ++	/* ignore phy_address, maxtxpkt, maxrxpkt for now */ ++	 ++	/* WHEW! now lets bang some bits */ ++	 ++	tmp = armiiread(np->phy, MII_BMCR); ++	if (ecmd->autoneg == AUTONEG_ENABLE) { ++		/* turn on autonegotiation */ ++		tmp |= BMCR_ANENABLE; ++                printk("%s: Enabling auto-neg\n", dev->name); ++	} else { ++		/* turn off auto negotiation, set speed and duplexity */ ++		tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); ++		if (ecmd->speed == SPEED_100) ++			tmp |= BMCR_SPEED100; ++		if (ecmd->duplex == DUPLEX_FULL) ++			tmp |= BMCR_FULLDPLX; ++                printk("%s: Hard coding %d/%s\n", dev->name,  ++                       (ecmd->speed == SPEED_100)? 100:10, ++                       (ecmd->duplex == DUPLEX_FULL)? "full":"half"); ++	} ++	armiiwrite(np->phy, MII_BMCR, tmp); ++        np->phyData = 0; ++	return 0; ++} ++ ++static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ++{ ++	struct ar2313_private *np = dev->priv; ++	u32 cmd; ++	 ++	if (get_user(cmd, (u32 *)useraddr)) ++		return -EFAULT; ++ ++        switch (cmd) { ++	/* get settings */ ++	case ETHTOOL_GSET: { ++		struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++		spin_lock_irq(&np->lock); ++		netdev_get_ecmd(dev, &ecmd); ++		spin_unlock_irq(&np->lock); ++		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) ++			return -EFAULT; ++		return 0; ++	} ++	/* set settings */ ++	case ETHTOOL_SSET: { ++		struct ethtool_cmd ecmd; ++		int r; ++		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) ++			return -EFAULT; ++		spin_lock_irq(&np->lock); ++		r = netdev_set_ecmd(dev, &ecmd); ++		spin_unlock_irq(&np->lock); ++		return r; ++	} ++	/* restart autonegotiation */ ++	case ETHTOOL_NWAY_RST: { ++		int tmp; ++		int r = -EINVAL; ++		/* if autoneg is off, it's an error */ ++		tmp = armiiread(np->phy, MII_BMCR); ++		if (tmp & BMCR_ANENABLE) { ++			tmp |= (BMCR_ANRESTART); ++			armiiwrite(np->phy, MII_BMCR, tmp); ++			r = 0; ++		} ++		return r; ++	} ++	/* get link status */ ++	case ETHTOOL_GLINK: { ++		struct ethtool_value edata = {ETHTOOL_GLINK}; ++		edata.data = (armiiread(np->phy, MII_BMSR)&BMSR_LSTATUS) ? 1:0; ++		if (copy_to_user(useraddr, &edata, sizeof(edata))) ++			return -EFAULT; ++		return 0; ++	} ++        } ++	 ++	return -EOPNOTSUPP; ++} ++ ++static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++    struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; ++ ++    switch (cmd) { ++    case SIOCDEVPRIVATE: { ++        struct ar2313_cmd scmd; ++ ++        if (copy_from_user(&scmd, ifr->ifr_data, sizeof(scmd))) ++	    return -EFAULT; ++ ++#if DEBUG ++	printk("%s: ioctl devprivate c=%d a=%x l=%d m=%d d=%x,%x\n", ++	       dev->name, scmd.cmd, ++	       scmd.address, scmd.length, ++	       scmd.mailbox, scmd.data[0], scmd.data[1]); ++#endif /* DEBUG */ ++ ++	switch (scmd.cmd) { ++	case AR2313_READ_DATA: ++	    if(scmd.length==4){ ++		scmd.data[0] = *((u32*)scmd.address); ++	    } else if(scmd.length==2) { ++		scmd.data[0] = *((u16*)scmd.address); ++	    } else if (scmd.length==1) { ++		scmd.data[0] = *((u8*)scmd.address); ++	    } else { ++		return -EOPNOTSUPP; ++	    } ++	    if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd))) ++	        return -EFAULT; ++	    break; ++ ++	case AR2313_WRITE_DATA: ++	    if(scmd.length==4){ ++		*((u32*)scmd.address) = scmd.data[0]; ++	    } else if(scmd.length==2) { ++		*((u16*)scmd.address) = scmd.data[0]; ++	    } else if (scmd.length==1) { ++		*((u8*)scmd.address) = scmd.data[0]; ++	    } else { ++		return -EOPNOTSUPP; ++	    } ++	    break; ++ ++	case AR2313_GET_VERSION: ++	    // SAMEER: sprintf((char*) &scmd, "%s", ARUBA_VERSION); ++	    if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd))) ++	        return -EFAULT; ++	    break; ++ ++	default: ++	    return -EOPNOTSUPP; ++	} ++	return 0; ++    } ++       ++    case SIOCETHTOOL: ++        return netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data); ++ ++    case SIOCGMIIPHY:		/* Get address of MII PHY in use. */ ++        data->phy_id = 1; ++        /* Fall Through */ ++ ++    case SIOCGMIIREG:		/* Read MII PHY register. */ ++    case SIOCDEVPRIVATE+1:	/* for binary compat, remove in 2.5 */ ++        data->val_out = armiiread(data->phy_id & 0x1f,  ++                                  data->reg_num & 0x1f); ++        return 0; ++    case SIOCSMIIREG:		/* Write MII PHY register. */ ++    case SIOCDEVPRIVATE+2:	/* for binary compat, remove in 2.5 */ ++        if (!capable(CAP_NET_ADMIN)) ++            return -EPERM; ++        armiiwrite(data->phy_id & 0x1f,  ++                   data->reg_num & 0x1f, data->val_in); ++        return 0; ++ ++    case SIOCSIFHWADDR: ++        if (copy_from_user(dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr))) ++            return -EFAULT; ++        return 0; ++ ++    case SIOCGIFHWADDR: ++        if (copy_to_user(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr))) ++            return -EFAULT; ++        return 0; ++ ++    default: ++        break; ++    } ++ ++    return -EOPNOTSUPP; ++} ++ ++static struct net_device_stats *ar2313_get_stats(struct net_device *dev) ++{ ++  struct ar2313_private *sp = dev->priv; ++    return &sp->stats; ++} ++ ++static short ++armiiread(short phy, short reg) ++{ ++  volatile ETHERNET_STRUCT * ethernet; ++ ++  ethernet = (volatile ETHERNET_STRUCT *)ETHERNET_BASE; /* always MAC 0 */ ++  ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) | ++                        (phy << MII_ADDR_PHY_SHIFT)); ++  while (ethernet->mii_addr & MII_ADDR_BUSY); ++  return (ethernet->mii_data >> MII_DATA_SHIFT); ++} ++ ++static void ++armiiwrite(short phy, short reg, short data) ++{ ++  volatile ETHERNET_STRUCT * ethernet; ++ ++  ethernet = (volatile ETHERNET_STRUCT *)ETHERNET_BASE; /* always MAC 0 */ ++  while (ethernet->mii_addr & MII_ADDR_BUSY); ++  ethernet->mii_data = data << MII_DATA_SHIFT; ++  ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) | ++                        (phy << MII_ADDR_PHY_SHIFT) | ++                        MII_ADDR_WRITE); ++} ++  | 
