X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/9c6b657866cce7276591cd4e7ffd4d41b2e69773..dd511b6d03d74b1ea6996dfe2daaf15165c64c48:/target/linux/aruba-2.6/patches/010-ar2313_enet.patch diff --git a/target/linux/aruba-2.6/patches/010-ar2313_enet.patch b/target/linux/aruba-2.6/patches/010-ar2313_enet.patch index 01fe26fac..0488bd454 100644 --- a/target/linux/aruba-2.6/patches/010-ar2313_enet.patch +++ b/target/linux/aruba-2.6/patches/010-ar2313_enet.patch @@ -1,2160 +1,2175 @@ -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" - +diff -Nur linux-2.6.17/drivers/net/ar2313/ar2313.c linux-2.6.17-owrt/drivers/net/ar2313/ar2313.c +--- linux-2.6.17/drivers/net/ar2313/ar2313.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17-owrt/drivers/net/ar2313/ar2313.c 2006-06-19 12:57:27.000000000 +0200 +@@ -0,0 +1,1649 @@ ++/* ++ * ar2313.c: Linux driver for the Atheros AR2313 Ethernet device. ++ * ++ * Copyright 2004 by Sameer Dekate, . ++ * Copyright (C) 2006 Imre Kaloz ++ * ++ * 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. ++ */ + -+config AR2313 -+ tristate "AR2313 Ethernet support" -+ depends on NET_ETHERNET && MACH_ARUBA -+ help -+ Support for the AR2313 Ethernet part on Aruba AP60/61 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + - 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 ++#include + -+#include ++#include ++#include ++#include ++#include ++#include +#include -+#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) ++extern char *getenv(char *e); + -+/* -+ * 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 */ ++#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 + -+#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 __exit ++#define __exit ++#endif + -+#ifndef K1_TO_PHYS -+// hack -+#define K1_TO_PHYS(x) (((unsigned int)(x)) & 0x1FFFFFFF) /* kseg1 to physical */ ++#ifndef min ++#define min(a,b) (((a)<(b))?(a):(b)) +#endif + -+#ifndef PHYS_TO_K1 -+// hack -+#define PHYS_TO_K1(x) (((unsigned int)(x)) | 0xA0000000) /* physical to kseg1 */ ++#ifndef SMP_CACHE_BYTES ++#define SMP_CACHE_BYTES L1_CACHE_BYTES +#endif + -+#define AR2313_TX_TIMEOUT (HZ/4) ++#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 + -+/* -+ * Rings -+ */ -+#define DSC_RING_ENTRIES_SIZE (AR2313_DESCR_ENTRIES * sizeof(struct desc)) -+#define DSC_NEXT(idx) ((idx + 1) & (AR2313_DESCR_ENTRIES - 1)) ++#define PHYSADDR(a) ((_ACAST32_ (a)) & 0x1fffffff) + -+static inline int tx_space (u32 csm, u32 prd) -+{ -+ return (csm - prd - 1) & (AR2313_DESCR_ENTRIES - 1); -+} ++static char ethaddr[18] = "00:00:00:00:00:00"; ++static char ifname[5] = "bond"; + -+#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) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) ++module_param_string(ethaddr, ethaddr, 18, 0); ++module_param_string(ifname, ifname, 5, 0); +#else -+#define tx_ring_full 0 ++MODULE_PARM(ethaddr, "c18"); ++MODULE_PARM(ifname, "c5"); +#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 ++#define AR2313_MBOX_SET_BIT 0x8 + ++#define BOARD_IDX_STATIC 0 ++#define BOARD_IDX_OVERFLOW -1 + -+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 */ -+}; ++/* margot includes */ ++#include + ++#include "ar2313_msg.h" ++#include "platform.h" ++#include "dma.h" ++#include "ar2313.h" + +/* -+ * Struct private for the Sibyte. ++ * New interrupt handler strategy: + * -+ * 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. ++ * 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: + * -+ * Frequently accessed variables are put at the beginning of the -+ * struct to help the compiler generate better/shorter code. ++ * 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. + */ -+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; ++/* ++ * 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) + -+ struct sk_buff **rx_skb; -+ struct sk_buff **tx_skb; ++#ifdef MODULE ++MODULE_AUTHOR("Sameer Dekate"); ++MODULE_DESCRIPTION("AR2313 Ethernet driver"); ++#endif + -+ /* -+ * RX elements -+ */ -+ u32 rx_skbprd; -+ u32 cur_rx; ++#if DEBUG ++static char version[] __initdata = ++ "ar2313.c: v0.02 2006/06/19 sdekate@arubanetworks.com\n"; ++#endif /* DEBUG */ + -+ /* -+ * TX elements -+ */ -+ u32 tx_prd; -+ u32 tx_csm; ++#define virt_to_phys(x) ((u32)(x) & 0x1fffffff) + -+ /* -+ * 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); ++// 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 -+#if 0 ++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); -+#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) ++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; + -+#define AR2313_DESCR_ENTRIES 64 ++#ifndef ERR ++#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args) ++#endif + -+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; ++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; ++} + -+#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 -+ * -+ * -+ ******************************************************************************/ ++int __init ar2313_probe(void) ++{ ++ struct net_device *dev; ++ struct ar2313_private *sp; ++ int version_disp; ++ char name[64] ; + -+#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 */ ++ if (probed) ++ return -ENODEV; ++ probed++; + -+#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) ++ version_disp = 0; ++ sprintf(name, "%s%%d", ifname) ; ++ dev = alloc_etherdev(sizeof(struct ar2313_private)); + -+#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 */ ++ if (dev == NULL) { ++ printk(KERN_ERR "ar2313: Unable to allocate net_device structure!\n"); ++ return -ENOMEM; ++ } + -+#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 */ ++ SET_MODULE_OWNER(dev); + -+#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */ ++ sp = dev->priv; + -+#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) */ ++ 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; + -+#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 ++ 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; + -+#define FLOW_CONTROL_FCE AR_BIT(1) ++ 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 + -+#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 */ ++ if (mips_machtype == MACH_ARUBA_SAMSUNG) { ++ sp->phy = 0x1f; ++ } else { ++ sp->phy = 1; ++ } ++#else ++ sp->phy = 1; ++#endif ++ dev->irq = 3; ++ break; + -+#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 */ ++ default: ++ printk("%s: unsupported mips_machtype=0x%lx\n", ++ __FUNCTION__, mips_machtype) ; ++ return -ENODEV; ++ } + -+#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 */ ++ spin_lock_init(&sp->lock); + -+#endif // __ARUBA_DMA_H__ ++ /* 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 */ ++ } + -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 $ ++ request_region(PHYSADDR(ETHERNET_BASE), ETHERNET_SIZE*ETHERNET_MACS, ++ "AR2313ENET"); + -+ Author: Dan Steinberg -+ Copyright Integrated Device Technology 2001 ++ 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); ++ } + -+ 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). -+ -+********************************************************************************/ ++ 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); ++ } + -+#ifndef PLATFORM_H -+#define PLATFORM_H ++ 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); ++ } + -+#define BIT(x) (1 << (x)) ++ strncpy(sp->name, "Atheros AR2313", sizeof (sp->name) - 1); ++ sp->name [sizeof (sp->name) - 1] = '\0'; + -+#define RESET_BASE 0xBC003020 -+#define RESET_VALUE 0x00000001 ++ { ++ 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); ++ } ++ } + -+/******************************************************************** -+ * Device controller -+ ********************************************************************/ -+typedef struct { -+ volatile unsigned int flash0; -+} DEVICE; ++ sp->board_idx = BOARD_IDX_STATIC; + -+#define device (*((volatile DEVICE *) DEV_CTL_BASE)) ++ if (ar2313_init(dev)) { ++ /* ++ * ar2313_init() calls ar2313_init_cleanup() on error. ++ */ ++ kfree(dev); ++ return -ENODEV; ++ } + -+// DDRC register -+#define DEV_WP (1<<26) ++ if (register_netdev(dev)){ ++ printk("%s: register_netdev failed\n", __func__); ++ return -1; ++ } + -+/******************************************************************** -+ * DDR controller -+ ********************************************************************/ -+typedef struct { -+ volatile unsigned int ddrc0; -+ volatile unsigned int ddrc1; -+ volatile unsigned int ddrrefresh; -+} DDR; ++ 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); + -+#define ddr (*((volatile DDR *) DDR_BASE)) ++ /* start link poll timer */ ++ ar2313_setup_timer(dev); + -+// DDRC register -+#define DDRC_CS(i) ((i&0x3)<<0) -+#define DDRC_WE (1<<2) ++ /* ++ * Register the device ++ */ ++ root_dev = dev; + -+/******************************************************************** -+ * Ethernet interfaces -+ ********************************************************************/ -+#define ETHERNET_BASE 0xB8200000 ++ return 0; ++} + -+// -+// 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; ++#if 0 ++static void ar2313_dump_regs(struct net_device *dev) ++{ ++ unsigned int *ptr, i; ++ struct ar2313_private *sp = (struct ar2313_private *)dev->priv; + -+/******************************************************************** -+ * Interrupt controller -+ ********************************************************************/ ++ 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); ++ } + -+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; ++ 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); ++ } + -+#define interrupt (*((volatile INTERRUPT *) INTERRUPT_BASE)) ++ 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); ++ } + -+#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) ++ 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 + -+#define INTERRUPT_GLOBAL_ETH BIT(2) -+#define INTERRUPT_GLOBAL_WLAN BIT(3) -+#define INTERRUPT_GLOBAL_MISC BIT(4) -+#define INTERRUPT_GLOBAL_ITIMER BIT(5) ++#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 + -+/******************************************************************** -+ * DMA controller -+ ********************************************************************/ -+#define DMA_BASE 0xB8201000 ++#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;idmi_addrlen;i++) { ++ printk(":%02x", list->dmi_addr[i]); ++ } ++ list = list->next; ++ printk("\n"); ++ } ++} ++#endif + -+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, . -+ * -+ * 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. ++ * 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; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 ++ recognise = sp->eth_regs->mac_control; + -+#ifndef __exit -+#define __exit -+#endif ++ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ ++ recognise |= MAC_CONTROL_PR; ++ } else { ++ recognise &= ~MAC_CONTROL_PR; ++ } + -+#ifndef min -+#define min(a,b) (((a)<(b))?(a):(b)) ++ 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 -+ -+#ifndef SMP_CACHE_BYTES -+#define SMP_CACHE_BYTES L1_CACHE_BYTES ++ 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 -+ -+#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);} ++ 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; ++} + -+#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 ++static void rx_tasklet_cleanup(struct net_device *dev) ++{ ++ struct ar2313_private *sp = dev->priv; + -+#define BOARD_IDX_STATIC 0 -+#define BOARD_IDX_OVERFLOW -1 ++ /* ++ * Tasklet may be scheduled. Need to get it removed from the list ++ * since we're about to free the struct. ++ */ + -+/* margot includes */ -+#include ++ sp->unloading = 1; ++ tasklet_enable(&sp->rx_tasklet); ++ tasklet_kill(&sp->rx_tasklet); ++} + -+#include "ar2313/ar2313_msg.h" -+#include "ar2313/platform.h" -+#include "ar2313/dma.h" -+#include "ar2313/ar2313.h" ++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); ++} + -+/* -+ * 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. ++ * Restart the AR2313 ethernet controller. + */ -+#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 ++static int ar2313_restart(struct net_device *dev) ++{ ++ /* disable interrupts */ ++ disable_irq(dev->irq); + -+#define AR2313_BUFSIZE (AR2313_MTU + ETH_HLEN + CRC_LEN + RX_OFFSET) ++ /* stop mac */ ++ ar2313_halt(dev); ++ ++ /* initialize */ ++ ar2313_init(dev); ++ ++ /* enable interrupts */ ++ enable_irq(dev->irq); ++ ++ return 0; ++} + -+#ifdef MODULE -+MODULE_AUTHOR("Sameer Dekate"); -+MODULE_DESCRIPTION("AR2313 Ethernet driver"); -+#endif ++extern unsigned long mips_machtype; + -+#if DEBUG -+static char version[] __initdata = -+ "ar2313.c: v0.01 2004/01/06 sdekate@arubanetworks.com\n"; -+#endif /* DEBUG */ ++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; ++} + -+#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); ++module_init(ar2313_module_init); ++module_exit(ar2313_module_cleanup); + -+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; -+ } ++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; + } -+ -+ macstr++; -+ dev->dev_addr[i] = result; -+ } -+ -+ return 0; +} + + -+int __init ar2313_probe(void) ++static int ar2313_allocate_descriptors(struct net_device *dev) +{ -+ 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)); ++ struct ar2313_private *sp = dev->priv; ++ int size; ++ int j; ++ ar2313_descr_t *space; + -+ if (dev == NULL) { -+ printk(KERN_ERR "ar2313: Unable to allocate net_device structure!\n"); -+ return -ENOMEM; ++ if(sp->rx_ring != NULL){ ++ printk("%s: already done.\n", __FUNCTION__); ++ return 0; + } + -+ SET_MODULE_OWNER(dev); ++ size = (sizeof(ar2313_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES)); ++ space = kmalloc(size, GFP_KERNEL); ++ if (space == NULL) ++ return 1; + -+ sp = dev->priv; ++ /* invalidate caches */ ++ dma_cache_inv((unsigned int)space, size); + -+ 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; ++ /* now convert pointer to KSEG1 */ ++ space = (ar2313_descr_t *)KSEG1ADDR(space); + -+ 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; ++ memset((void *)space, 0, size); + -+ 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 ++ sp->rx_ring = space; ++ space += AR2313_DESCR_ENTRIES; + -+ if (mips_machtype == MACH_ARUBA_SAMSUNG) { -+ sp->phy = 0x1f; -+ } else { -+ sp->phy = 1; -+ } -+#else -+ sp->phy = 1; -+#endif -+ dev->irq = 3; -+ break; ++ sp->tx_ring = space; ++ space += AR2313_DESCR_ENTRIES; + -+ default: -+ printk("%s: unsupported mips_machtype=0x%lx\n", -+ __FUNCTION__, mips_machtype) ; -+ return -ENODEV; ++ /* 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)]); + } + -+ spin_lock_init(&sp->lock); ++ return 0; ++} + -+ /* 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; ++/* ++ * 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; + -+ // SAMEER: do we need this? -+ dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA; ++ ar2313_free_descriptors(dev); + -+ tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev); -+ tasklet_disable(&sp->rx_tasklet); ++ if (sp->eth_regs) iounmap((void*)sp->eth_regs); ++ if (sp->dma_regs) iounmap((void*)sp->dma_regs); + -+ /* 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 */ ++ 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; + } + -+ 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); ++ 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; + } ++} + -+ 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); -+ } ++static int ar2313_setup_timer(struct net_device *dev) ++{ ++ struct ar2313_private *sp = dev->priv; + -+ 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); -+ } ++ init_timer(&sp->link_timer); + -+ strncpy(sp->name, "Atheros AR2313", sizeof (sp->name) - 1); -+ sp->name [sizeof (sp->name) - 1] = '\0'; ++ sp->link_timer.function = ar2313_link_timer_fn; ++ sp->link_timer.data = (int) dev; ++ sp->link_timer.expires = jiffies + HZ; + -+ { -+ 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); -+ } -+ } ++ add_timer(&sp->link_timer); ++ return 0; + -+ sp->board_idx = BOARD_IDX_STATIC; ++} + -+ if (ar2313_init(dev)) { -+ /* -+ * ar2313_init() calls ar2313_init_cleanup() on error. -+ */ -+ kfree(dev); -+ return -ENODEV; ++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); + } ++} + -+ if (register_netdev(dev)){ -+ printk("%s: register_netdev failed\n", __func__); -+ return -1; -+ } ++static void ar2313_check_link(struct net_device *dev) ++{ ++ struct ar2313_private *sp = dev->priv; ++ u16 phyData; + -+ 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); ++ 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; + -+ /* start link poll timer */ -+ ar2313_setup_timer(dev); ++ 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; ++ } + -+ /* -+ * Register the device -+ */ -+ root_dev = dev; ++ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n", dev->name, ++ (duplex)? "full":"half"); + -+ return 0; ++ 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; ++ } +} -+ -+#if 0 -+static void ar2313_dump_regs(struct net_device *dev) ++ ++static int ++ar2313_reset_reg(struct net_device *dev) +{ -+ unsigned int *ptr, i; + struct ar2313_private *sp = (struct ar2313_private *)dev->priv; ++ unsigned int ethsal, ethsah; ++ unsigned int flags; + -+ 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); -+ } ++ *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); + -+ 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); -+ } ++ 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); + -+ 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 ++ /* 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); + -+#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 ++ /* 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 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;idmi_addrlen;i++) { -+ printk(":%02x", list->dmi_addr[i]); -+ } -+ list = list->next; -+ printk("\n"); ++ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ ++ flags |= MAC_CONTROL_PR; + } -+} -+#endif ++ sp->eth_regs->mac_control = flags; + -+/* -+ * 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; ++ /* 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)); + -+ recognise = sp->eth_regs->mac_control; ++ 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) ); + -+ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ -+ recognise |= MAC_CONTROL_PR; -+ } else { -+ recognise &= ~MAC_CONTROL_PR; -+ } ++ sp->eth_regs->mac_addr[0] = ethsah; ++ sp->eth_regs->mac_addr[1] = ethsal; + -+ 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; ++ mdelay(10); ++ ++ return(0); +} + -+static void rx_tasklet_cleanup(struct net_device *dev) ++ ++static int ar2313_init(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; ++ int ecode=0; + + /* -+ * Tasklet may be scheduled. Need to get it removed from the list -+ * since we're about to free the struct. ++ * Allocate descriptors + */ ++ if (ar2313_allocate_descriptors(dev)) { ++ printk("%s: %s: ar2313_allocate_descriptors failed\n", ++ dev->name, __FUNCTION__); ++ ecode = -EAGAIN; ++ goto init_error; ++ } + -+ sp->unloading = 1; -+ tasklet_enable(&sp->rx_tasklet); -+ tasklet_kill(&sp->rx_tasklet); -+} ++ /* ++ * 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); + -+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); -+} ++ 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; + -+/* -+ * Restart the AR2313 ethernet controller. -+ */ -+static int ar2313_restart(struct net_device *dev) -+{ -+ /* disable interrupts */ -+ disable_irq(dev->irq); ++ /* ++ * Zero the stats before starting the interface ++ */ ++ memset(&sp->stats, 0, sizeof(sp->stats)); + -+ /* stop mac */ -+ ar2313_halt(dev); -+ -+ /* initialize */ -+ ar2313_init(dev); -+ -+ /* enable interrupts */ -+ enable_irq(dev->irq); -+ -+ return 0; -+} ++ /* ++ * 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); + -+extern unsigned long mips_machtype; ++ /* ++ * Init hardware ++ */ ++ ar2313_reset_reg(dev); + -+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; ++ /* ++ * 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; + } -+ return status; -+} + ++#if 0 ++ // commented out, for now + -+module_init(ar2313_module_init); -+module_exit(ar2313_module_cleanup); ++ 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); + -+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; -+ } -+} ++ return 0; + ++ init_error: ++ ar2313_init_cleanup(dev); ++ return ecode; ++} + -+static int ar2313_allocate_descriptors(struct net_device *dev) ++/* ++ * 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 = dev->priv; -+ int size; -+ int j; -+ ar2313_descr_t *space; + -+ if(sp->rx_ring != NULL){ -+ printk("%s: already done.\n", __FUNCTION__); -+ return 0; -+ } ++ struct ar2313_private *sp = ((struct net_device *)dev)->priv; ++ short i, idx; + -+ size = (sizeof(ar2313_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES)); -+ space = kmalloc(size, GFP_KERNEL); -+ if (space == NULL) -+ return 1; ++ idx = sp->rx_skbprd; + -+ /* invalidate caches */ -+ dma_cache_inv((unsigned int)space, size); ++ for (i = 0; i < nr_bufs; i++) { ++ struct sk_buff *skb; ++ ar2313_descr_t *rd; + -+ /* now convert pointer to KSEG1 */ -+ space = (ar2313_descr_t *)KSEG1ADDR(space); ++ if (sp->rx_skb[idx]) { ++#if DEBUG_RX ++ printk(KERN_INFO "ar2313 rx refill full\n"); ++#endif /* DEBUG */ ++ break; ++ } + -+ memset((void *)space, 0, size); ++ // 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); + -+ sp->rx_ring = space; -+ space += AR2313_DESCR_ENTRIES; ++ /* ++ * Make sure IP header starts on a fresh cache line. ++ */ ++ skb->dev = dev; ++ skb_reserve(skb, RX_OFFSET); ++ sp->rx_skb[idx] = skb; + -+ sp->tx_ring = space; -+ space += AR2313_DESCR_ENTRIES; ++ rd = (ar2313_descr_t *) &sp->rx_ring[idx]; + -+ /* 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)]); ++ /* 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); + } + -+ return 0; ++ 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 + -+/* -+ * 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) ++static int ar2313_rx_int(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; -+ struct sk_buff *skb; -+ int j; ++ struct sk_buff *skb, *skb_new; ++ ar2313_descr_t *rxdesc; ++ unsigned int status; ++ u32 idx; ++ int pkts = 0; ++ int rval; + -+ ar2313_free_descriptors(dev); ++ idx = sp->cur_rx; + -+ if (sp->eth_regs) iounmap((void*)sp->eth_regs); -+ if (sp->dma_regs) iounmap((void*)sp->dma_regs); ++ /* process at most the entire ring and then wait for another interrupt */ ++ while(1) { + -+ 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); -+ } ++ 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; + } -+ 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; -+ } -+} ++ if (++pkts > AR2313_MAX_PKTS_PER_CALL) { ++ rval = 1; ++ break; ++ } + -+static int ar2313_setup_timer(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; ++#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 + -+ init_timer(&sp->link_timer); ++ 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++; + -+ sp->link_timer.function = ar2313_link_timer_fn; -+ sp->link_timer.data = (int) dev; -+ sp->link_timer.expires = jiffies + HZ; ++ /* 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++; + -+ add_timer(&sp->link_timer); -+ return 0; ++ } else { ++ /* alloc new buffer. */ ++ skb_new = dev_alloc_skb(AR2313_BUFSIZE + RX_OFFSET + 128); ++ if (skb_new != NULL) { + -+} -+ -+static void ar2313_link_timer_fn(unsigned long data) -+{ -+ struct net_device *dev = (struct net_device *) data; -+ struct ar2313_private *sp = dev->priv; ++ skb = sp->rx_skb[idx]; ++ /* set skb */ ++ skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN); + -+ // 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); -+ } -+} ++#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 */ + -+static void ar2313_check_link(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ u16 phyData; ++#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); + -+ 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->stats.rx_packets++; ++ sp->rx_skb[idx] = skb_new; + -+ 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; -+ } ++ } else { ++ sp->stats.rx_dropped++; ++ } ++ } + -+ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n", dev->name, -+ (duplex)? "full":"half"); ++ rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) | ++ DMA_RX1_CHAINED); ++ rxdesc->status = DMA_RX_OWN; + -+ 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; ++ idx = DSC_NEXT(idx); + } ++ ++ sp->cur_rx = idx; ++ ++ return rval; +} -+ -+static int -+ar2313_reset_reg(struct net_device *dev) ++ ++ ++static void ar2313_tx_int(struct net_device *dev) +{ -+ struct ar2313_private *sp = (struct ar2313_private *)dev->priv; -+ unsigned int ethsal, ethsah; -+ unsigned int flags; ++ struct ar2313_private *sp = dev->priv; ++ u32 idx; ++ struct sk_buff *skb; ++ ar2313_descr_t *txdesc; ++ unsigned int status=0; + -+ *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); ++ idx = sp->tx_csm; + -+ 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); ++ while (idx != sp->tx_prd) { + -+ /* 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); ++ txdesc = &sp->tx_ring[idx]; + -+ /* 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 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 (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ -+ flags |= MAC_CONTROL_PR; ++ 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->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)); ++ sp->tx_csm = idx; + -+ 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) ); ++ return; ++} + -+ sp->eth_regs->mac_addr[0] = ethsah; -+ sp->eth_regs->mac_addr[1] = ethsal; + -+ mdelay(10); ++static void ++rx_tasklet_func(unsigned long data) ++{ ++ struct net_device *dev = (struct net_device *) data; ++ struct ar2313_private *sp = dev->priv; + -+ return(0); ++ 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; + -+static int ar2313_init(struct net_device *dev) ++ tasklet_hi_schedule(&sp->rx_tasklet); ++} ++ ++static irqreturn_t ar2313_interrupt(int irq, void *dev_id) +{ ++ struct net_device *dev = (struct net_device *)dev_id; + struct ar2313_private *sp = dev->priv; -+ int ecode=0; ++ unsigned int status, enabled; + ++ /* clear interrupt */ + /* -+ * Allocate descriptors ++ * Don't clear RI bit if currently disabled. + */ -+ if (ar2313_allocate_descriptors(dev)) { -+ printk("%s: %s: ar2313_allocate_descriptors failed\n", -+ dev->name, __FUNCTION__); -+ ecode = -EAGAIN; -+ goto init_error; -+ } ++ status = sp->dma_regs->status; ++ enabled = sp->dma_regs->intr_ena; ++ sp->dma_regs->status = status & enabled; + -+ /* -+ * 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; ++ 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); + } -+ } -+ 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; ++ if (status & DMA_STATUS_TI) { ++ /* transmit interrupt */ ++ ar2313_tx_int(dev); + } + } -+ 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)); ++ 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_HANDLED; ++} + -+ /* -+ * 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); ++static int ar2313_open(struct net_device *dev) ++{ ++ struct ar2313_private *sp; + -+ /* -+ * 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; -+ } ++ sp = dev->priv; + -+#if 0 -+ // commented out, for now ++ dev->mtu = 1500; ++ netif_start_queue(dev); + -+ 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 ++ sp->eth_regs->mac_control |= MAC_CONTROL_RE; + -+ tasklet_enable(&sp->rx_tasklet); ++ AR2313_MOD_INC_USE_COUNT; + + 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) ++static void ar2313_halt(struct net_device *dev) +{ ++ struct ar2313_private *sp = dev->priv; ++ int j; + -+ struct ar2313_private *sp = ((struct net_device *)dev)->priv; -+ short i, idx; -+ -+ idx = sp->rx_skbprd; ++ tasklet_disable(&sp->rx_tasklet); + -+ for (i = 0; i < nr_bufs; i++) { -+ struct sk_buff *skb; -+ ar2313_descr_t *rd; ++ /* 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; + -+ if (sp->rx_skb[idx]) { -+#if DEBUG_RX -+ printk(KERN_INFO "ar2313 rx refill full\n"); -+#endif /* DEBUG */ -+ break; -+ } ++ /* place phy and MAC in reset */ ++ *sp->int_regs |= (ar_int_mac_mask | ar_int_phy_mask); + -+ // 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); ++ /* free buffers on tx ring */ ++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { ++ struct sk_buff *skb; ++ ar2313_descr_t *txdesc; + -+ /* -+ * Make sure IP header starts on a fresh cache line. -+ */ -+ skb->dev = dev; -+ skb_reserve(skb, RX_OFFSET); -+ sp->rx_skb[idx] = skb; ++ txdesc = &sp->tx_ring[j]; ++ txdesc->descr = 0; + -+ rd = (ar2313_descr_t *) &sp->rx_ring[idx]; ++ skb = sp->tx_skb[j]; ++ if (skb) { ++ dev_kfree_skb(skb); ++ sp->tx_skb[j] = NULL; ++ } ++ } ++} + -+ /* 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; ++/* ++ * 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); + -+ idx = DSC_NEXT(idx); -+ } ++ /* stop the MAC and DMA engines */ ++ ar2313_halt(dev); + -+ if (!i) { -+#if DEBUG_ERR -+ printk(KERN_INFO "Out of memory when allocating standard receive buffers\n"); -+#endif /* DEBUG */ -+ } else { -+ sp->rx_skbprd = idx; -+ } ++ /* release the interrupt */ ++ free_irq(dev->irq, dev); + -+ return; ++#endif ++ AR2313_MOD_DEC_USE_COUNT; ++ return 0; +} + -+#define AR2313_MAX_PKTS_PER_CALL 64 -+ -+static int ar2313_rx_int(struct net_device *dev) ++static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; -+ struct sk_buff *skb, *skb_new; -+ ar2313_descr_t *rxdesc; -+ unsigned int status; ++ ar2313_descr_t *td; + u32 idx; -+ int pkts = 0; -+ int rval; + -+ idx = sp->cur_rx; ++ idx = sp->tx_prd; ++ td = &sp->tx_ring[idx]; + -+ /* process at most the entire ring and then wait for another interrupt */ -+ while(1) { ++ 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); + -+ 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; -+ } ++ /* restart transmitter in case locked */ ++ sp->dma_regs->xmt_poll = 0; ++ return 0; ++ } + -+ if (++pkts > AR2313_MAX_PKTS_PER_CALL) { -+ rval = 1; -+ break; -+ } ++ /* 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; + -+#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 ); ++ /* 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 + -+ 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++; ++ sp->tx_skb[idx] = skb; ++ idx = DSC_NEXT(idx); ++ sp->tx_prd = idx; + -+ /* 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++; ++ //dev->trans_start = jiffies; + -+ } else { -+ /* alloc new buffer. */ -+ skb_new = dev_alloc_skb(AR2313_BUFSIZE + RX_OFFSET + 128); -+ if (skb_new != NULL) { ++ return 0; ++} + -+ skb = sp->rx_skb[idx]; -+ /* set skb */ -+ skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN); ++static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ++{ ++ struct ar2313_private *np = dev->priv; ++ u32 tmp; + -+#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 */ ++ 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; + -+#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); ++ 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; + -+ sp->stats.rx_packets++; -+ sp->rx_skb[idx] = skb_new; ++ tmp = armiiread(np->phy, MII_BMCR); ++ if (tmp & BMCR_ANENABLE) { ++ ecmd->advertising |= ADVERTISED_Autoneg; ++ ecmd->autoneg = AUTONEG_ENABLE; ++ } else { ++ ecmd->autoneg = AUTONEG_DISABLE; ++ } + -+ } else { -+ sp->stats.rx_dropped++; -+ } ++ 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; ++ } + } + -+ rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) | -+ DMA_RX1_CHAINED); -+ rxdesc->status = DMA_RX_OWN; ++ /* ignore maxtxpkt, maxrxpkt for now */ + -+ idx = DSC_NEXT(idx); -+ } ++ return 0; ++} + -+ sp->cur_rx = idx; ++static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ++{ ++ struct ar2313_private *np = dev->priv; ++ u32 tmp; + -+ return rval; ++ 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 void ar2313_tx_int(struct net_device *dev) ++static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ -+ struct ar2313_private *sp = dev->priv; -+ u32 idx; -+ struct sk_buff *skb; -+ ar2313_descr_t *txdesc; -+ unsigned int status=0; ++ struct ar2313_private *np = dev->priv; ++ u32 cmd; ++ ++ if (get_user(cmd, (u32 *)useraddr)) ++ return -EFAULT; + -+ idx = sp->tx_csm; ++ 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; ++} + -+ while (idx != sp->tx_prd) { ++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; + -+ txdesc = &sp->tx_ring[idx]; ++ switch (cmd) { ++ case SIOCDEVPRIVATE: { ++ struct ar2313_cmd scmd; + -+#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); ++ 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 */ + -+ if ((status = txdesc->status) & DMA_TX_OWN) { -+ /* ar2313 dma still owns descr */ ++ 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; -+ } -+ /* 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++; -+ } ++ 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; + -+ 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); ++ 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); + -+ sp->tx_csm = idx; ++ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ ++ data->phy_id = 1; ++ /* Fall Through */ + -+ return; -+} ++ 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; + -+static void -+rx_tasklet_func(unsigned long data) -+{ -+ struct net_device *dev = (struct net_device *) data; -+ struct ar2313_private *sp = dev->priv; ++ case SIOCGIFHWADDR: ++ if (copy_to_user(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr))) ++ return -EFAULT; ++ return 0; + -+ if (sp->unloading) { -+ return; -+ } ++ default: ++ break; ++ } + -+ 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); -+ } ++ return -EOPNOTSUPP; +} + -+static void -+rx_schedule(struct net_device *dev) ++static struct net_device_stats *ar2313_get_stats(struct net_device *dev) +{ -+ struct ar2313_private *sp = dev->priv; -+ -+ sp->dma_regs->intr_ena &= ~DMA_STATUS_RI; -+ -+ tasklet_hi_schedule(&sp->rx_tasklet); ++ struct ar2313_private *sp = dev->priv; ++ return &sp->stats; +} + -+static irqreturn_t ar2313_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) ++static short ++armiiread(short phy, short reg) +{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ struct ar2313_private *sp = dev->priv; -+ unsigned int status, enabled; ++ volatile ETHERNET_STRUCT * ethernet; + -+ /* 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; ++ 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); ++} + -+ 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); -+ } -+ } ++static void ++armiiwrite(short phy, short reg, short data) ++{ ++ volatile ETHERNET_STRUCT * ethernet; + -+ 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); ++ 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); +} + +diff -Nur linux-2.6.17/drivers/net/ar2313/ar2313.h linux-2.6.17-owrt/drivers/net/ar2313/ar2313.h +--- linux-2.6.17/drivers/net/ar2313/ar2313.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17-owrt/drivers/net/ar2313/ar2313.h 2006-06-19 12:05:29.000000000 +0200 +@@ -0,0 +1,190 @@ ++#ifndef _AR2313_H_ ++#define _AR2313_H_ + -+static int ar2313_open(struct net_device *dev) -+{ -+ struct ar2313_private *sp; -+ -+ sp = dev->priv; ++#include ++#include ++#include "platform.h" + -+ dev->mtu = 1500; -+ netif_start_queue(dev); ++extern unsigned long mips_machtype; + -+ sp->eth_regs->mac_control |= MAC_CONTROL_RE; ++#undef ETHERNET_BASE ++#define ETHERNET_BASE ar_eth_base ++#define ETHERNET_SIZE 0x00100000 ++#define ETHERNET_MACS 2 + -+ AR2313_MOD_INC_USE_COUNT; ++#undef DMA_BASE ++#define DMA_BASE ar_dma_base ++#define DMA_SIZE 0x00100000 + -+ return 0; -+} + -+static void ar2313_halt(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ int j; ++/* ++ * probe link timer - 5 secs ++ */ ++#define LINK_TIMER (5*HZ) + -+ tasklet_disable(&sp->rx_tasklet); ++/* ++ * Interrupt register base address ++ */ ++#define INTERRUPT_BASE PHYS_TO_K1(ar_int_base) + -+ /* 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; ++/* ++ * 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 */ + -+ /* place phy and MAC in reset */ -+ *sp->int_regs |= (ar_int_mac_mask | ar_int_phy_mask); ++#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) + -+ /* free buffers on tx ring */ -+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { -+ struct sk_buff *skb; -+ ar2313_descr_t *txdesc; ++#ifndef K1_TO_PHYS ++// hack ++#define K1_TO_PHYS(x) (((unsigned int)(x)) & 0x1FFFFFFF) /* kseg1 to physical */ ++#endif + -+ txdesc = &sp->tx_ring[j]; -+ txdesc->descr = 0; ++#ifndef PHYS_TO_K1 ++// hack ++#define PHYS_TO_K1(x) (((unsigned int)(x)) | 0xA0000000) /* physical to kseg1 */ ++#endif + -+ skb = sp->tx_skb[j]; -+ if (skb) { -+ dev_kfree_skb(skb); -+ sp->tx_skb[j] = NULL; -+ } -+ } -+} ++#define AR2313_TX_TIMEOUT (HZ/4) + +/* -+ * 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. ++ * Rings + */ -+static int ar2313_close(struct net_device *dev) ++#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) +{ -+#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); ++ return (csm - prd - 1) & (AR2313_DESCR_ENTRIES - 1); ++} + -+ /* stop the MAC and DMA engines */ -+ ar2313_halt(dev); ++#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 + -+ /* release the interrupt */ -+ free_irq(dev->irq, dev); ++#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 + -+#endif -+ AR2313_MOD_DEC_USE_COUNT; -+ return 0; -+} + -+static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev) ++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 +{ -+ struct ar2313_private *sp = dev->priv; -+ ar2313_descr_t *td; -+ u32 idx; ++ int version; ++ u32 mb[2]; ++ ++ volatile ETHERNET_STRUCT *eth_regs; ++ volatile DMA *dma_regs; ++ volatile u32 *int_regs; + -+ idx = sp->tx_prd; -+ td = &sp->tx_ring[idx]; ++ spinlock_t lock; /* Serialise access to device */ + -+ 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); ++ /* ++ * RX and TX descriptors, must be adjacent ++ */ ++ ar2313_descr_t *rx_ring; ++ ar2313_descr_t *tx_ring; + -+ /* 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; ++ struct sk_buff **rx_skb; ++ struct sk_buff **tx_skb; + -+ /* kick transmitter last */ -+ sp->dma_regs->xmt_poll = 0; ++ /* ++ * RX elements ++ */ ++ u32 rx_skbprd; ++ u32 cur_rx; + -+#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 ); ++ /* ++ * 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); ++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 -Nur linux-2.6.17/drivers/net/ar2313/ar2313_msg.h linux-2.6.17-owrt/drivers/net/ar2313/ar2313_msg.h +--- linux-2.6.17/drivers/net/ar2313/ar2313_msg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17-owrt/drivers/net/ar2313/ar2313_msg.h 2006-06-19 12:05:29.000000000 +0200 +@@ -0,0 +1,17 @@ ++#ifndef _AR2313_MSG_H_ ++#define _AR2313_MSG_H_ + -+ sp->tx_skb[idx] = skb; -+ idx = DSC_NEXT(idx); -+ sp->tx_prd = idx; ++#define AR2313_MTU 1692 ++#define AR2313_PRIOS 1 ++#define AR2313_QUEUES (2*AR2313_PRIOS) + -+ //dev->trans_start = jiffies; ++#define AR2313_DESCR_ENTRIES 64 + -+ return 0; -+} ++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; + -+static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) -+{ -+ struct ar2313_private *np = dev->priv; -+ u32 tmp; ++#endif /* _AR2313_MSG_H_ */ +diff -Nur linux-2.6.17/drivers/net/ar2313/dma.h linux-2.6.17-owrt/drivers/net/ar2313/dma.h +--- linux-2.6.17/drivers/net/ar2313/dma.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17-owrt/drivers/net/ar2313/dma.h 2006-06-19 12:05:29.000000000 +0200 +@@ -0,0 +1,135 @@ ++#ifndef __ARUBA_DMA_H__ ++#define __ARUBA_DMA_H__ + -+ 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; ++/******************************************************************************* ++ * ++ * 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 ++ * ++ * ++ ******************************************************************************/ + -+ 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; ++#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 */ + -+ tmp = armiiread(np->phy, MII_BMCR); -+ if (tmp & BMCR_ANENABLE) { -+ ecmd->advertising |= ADVERTISED_Autoneg; -+ ecmd->autoneg = AUTONEG_ENABLE; -+ } else { -+ ecmd->autoneg = AUTONEG_DISABLE; -+ } ++#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) + -+ 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; -+ } -+ } ++#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 */ + -+ /* ignore maxtxpkt, maxrxpkt for now */ ++#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 */ + -+ return 0; -+} ++#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */ + -+static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) -+{ -+ struct ar2313_private *np = dev->priv; -+ u32 tmp; ++#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) */ + -+ 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; -+} ++#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 + -+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; ++#define FLOW_CONTROL_FCE AR_BIT(1) + -+ 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; -+} ++#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 */ + -+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; ++#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 */ + -+ switch (cmd) { -+ case SIOCDEVPRIVATE: { -+ struct ar2313_cmd scmd; ++#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 */ + -+ if (copy_from_user(&scmd, ifr->ifr_data, sizeof(scmd))) -+ return -EFAULT; ++#endif // __ARUBA_DMA_H__ + -+#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; -+ } +diff -Nur linux-2.6.17/drivers/net/ar2313/Makefile linux-2.6.17-owrt/drivers/net/ar2313/Makefile +--- linux-2.6.17/drivers/net/ar2313/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17-owrt/drivers/net/ar2313/Makefile 2006-06-19 12:25:58.000000000 +0200 +@@ -0,0 +1,5 @@ ++# ++# Makefile for the AR2313 ethernet driver ++# ++ ++obj-$(CONFIG_AR2313) += ar2313.o +diff -Nur linux-2.6.17/drivers/net/ar2313/platform.h linux-2.6.17-owrt/drivers/net/ar2313/platform.h +--- linux-2.6.17/drivers/net/ar2313/platform.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.17-owrt/drivers/net/ar2313/platform.h 2006-06-19 12:05:29.000000000 +0200 +@@ -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 $ + -+ case SIOCETHTOOL: -+ return netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data); ++ Notes: See Merlot architecture spec for complete details. Note, all ++ addresses are virtual addresses in kseg1 (Uncached, Unmapped). ++ ++********************************************************************************/ + -+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ -+ data->phy_id = 1; -+ /* Fall Through */ ++#ifndef PLATFORM_H ++#define PLATFORM_H + -+ 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; ++#define BIT(x) (1 << (x)) + -+ case SIOCSIFHWADDR: -+ if (copy_from_user(dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr))) -+ return -EFAULT; -+ return 0; ++#define RESET_BASE 0xBC003020 ++#define RESET_VALUE 0x00000001 + -+ case SIOCGIFHWADDR: -+ if (copy_to_user(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr))) -+ return -EFAULT; -+ return 0; ++/******************************************************************** ++ * Device controller ++ ********************************************************************/ ++typedef struct { ++ volatile unsigned int flash0; ++} DEVICE; + -+ default: -+ break; -+ } ++#define device (*((volatile DEVICE *) DEV_CTL_BASE)) + -+ return -EOPNOTSUPP; -+} ++// DDRC register ++#define DEV_WP (1<<26) + -+static struct net_device_stats *ar2313_get_stats(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ return &sp->stats; -+} ++/******************************************************************** ++ * DDR controller ++ ********************************************************************/ ++typedef struct { ++ volatile unsigned int ddrc0; ++ volatile unsigned int ddrc1; ++ volatile unsigned int ddrrefresh; ++} DDR; + -+static short -+armiiread(short phy, short reg) -+{ -+ volatile ETHERNET_STRUCT * ethernet; ++#define ddr (*((volatile DDR *) DDR_BASE)) + -+ 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); -+} ++// DDRC register ++#define DDRC_CS(i) ((i&0x3)<<0) ++#define DDRC_WE (1<<2) + -+static void -+armiiwrite(short phy, short reg, short data) -+{ -+ volatile ETHERNET_STRUCT * ethernet; ++/******************************************************************** ++ * Ethernet interfaces ++ ********************************************************************/ ++#define ETHERNET_BASE 0xB8200000 + -+ 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); -+} ++// ++// 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 -Nur linux-2.6.17/drivers/net/Kconfig linux-2.6.17-owrt/drivers/net/Kconfig +--- linux-2.6.17/drivers/net/Kconfig 2006-06-19 12:05:01.000000000 +0200 ++++ linux-2.6.17-owrt/drivers/net/Kconfig 2006-06-19 12:26:35.000000000 +0200 +@@ -310,6 +310,12 @@ + + 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 -Nur linux-2.6.17/drivers/net/Makefile linux-2.6.17-owrt/drivers/net/Makefile +--- linux-2.6.17/drivers/net/Makefile 2006-06-19 12:05:01.000000000 +0200 ++++ linux-2.6.17-owrt/drivers/net/Makefile 2006-06-19 12:27:02.000000000 +0200 +@@ -12,6 +12,7 @@ + obj-$(CONFIG_CHELSIO_T1) += chelsio/ + obj-$(CONFIG_BONDING) += bonding/ + obj-$(CONFIG_GIANFAR) += gianfar_driver.o ++obj-$(CONFIG_AR2313) += ar2313/ + + gianfar_driver-objs := gianfar.o \ + gianfar_ethtool.o \