All of lore.kernel.org
 help / color / mirror / Atom feed
* [4/7] LEON SPARC V8 processor support for linux-2.6.10
@ 2005-01-04 19:04 ` Jiri Gaisler
  0 siblings, 0 replies; 4+ messages in thread
From: Jiri Gaisler @ 2005-01-04 19:04 UTC (permalink / raw)
  To: sparclinux; +Cc: linux-kernel, wli

[-- Attachment #1: Type: text/plain, Size: 95 bytes --]

Leon3 serial+ethermac driver:

[4/7] diff2.6.10_driver_amba.diff         diff for drivers/amba

[-- Attachment #2: diff2.6.10_driver_amba.diff --]
[-- Type: text/plain, Size: 73408 bytes --]

diff -Naur ../linux-2.6.10/drivers/Makefile linux-2.6.10/drivers/Makefile
--- ../linux-2.6.10/drivers/Makefile	2004-12-24 22:36:00.000000000 +0100
+++ linux-2.6.10/drivers/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -60,3 +60,4 @@
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-y				+= firmware/
+obj-$(CONFIG_LEON_3)            += amba/
diff -Naur ../linux-2.6.10/drivers/amba/Kconfig linux-2.6.10/drivers/amba/Kconfig
--- ../linux-2.6.10/drivers/amba/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Kconfig	2005-01-03 17:10:41.000000000 +0100
@@ -0,0 +1,12 @@
+
+#------------------------------------------------------------------------------
+# Amba device driver configuration
+#------------------------------------------------------------------------------
+
+menu "Grlib: Amba device driver configuration"
+
+source "drivers/amba/gaisler/Kconfig"
+source "drivers/amba/opencores/Kconfig"
+
+endmenu
+
diff -Naur ../linux-2.6.10/drivers/amba/Makefile linux-2.6.10/drivers/amba/Makefile
--- ../linux-2.6.10/drivers/amba/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,7 @@
+#
+# Makefile for the PCI bus specific drivers.
+#
+
+obj-y		+= amba.o amba_driver.o
+
+obj-y           += gaisler/ opencores/
diff -Naur ../linux-2.6.10/drivers/amba/amba.c linux-2.6.10/drivers/amba/amba.c
--- ../linux-2.6.10/drivers/amba/amba.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,181 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+amba_confarea_type amba_conf;
+
+/* Pointers to Interrupt Controller configuration registers */
+volatile LEON3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs = 0;
+volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs = 0;
+unsigned long LEON3_GpTimer_Irq = 0;
+
+static void vendor_dev_string(unsigned long conf, char *vendorbuf,char *devbuf) {
+  int vendor = amba_vendor(conf); int dev = amba_device(conf);
+  char *devstr; char *vendorstr; 
+  sprintf(vendorbuf, "Unknown vendor %2x",vendor);
+  sprintf(devbuf, "Unknown device %2x",dev);
+  vendorstr = vendor_id2str(vendor);
+  if (vendorstr) {
+    sprintf(vendorbuf, "%s",vendorstr);
+  } 
+  devstr = device_id2str(vendor,dev);
+  if (devstr) {
+    sprintf(devbuf, "%s",devstr);
+  }
+}
+
+void amba_prinf_config(void)  
+{
+  char devbuf[128]; char vendorbuf[128]; unsigned int conf;
+  int i = 0; int j = 0; 
+  unsigned int addr; unsigned int m;
+  printk("             Vendors         Slaves\n");
+  printk("Ahb masters:\n");
+  i = 0;
+  while (i < amba_conf.ahbmst.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbmst, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbmst,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+        printk(" +%i: 0x%x \n", j, addr);
+      }
+    }
+    i++;
+  }
+  printk("Ahb slaves:\n");
+  i = 0;
+  while (i < amba_conf.ahbslv.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbslv,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+	if (amba_membar_type(m) == AMBA_TYPE_AHBIO) {
+	  addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	} else if (amba_membar_type(m) == AMBA_TYPE_APBIO) {
+	  printk("Warning: apbio membar\n");
+	}
+	printk(" +%i: 0x%x (raw:0x%x)\n", j, addr, m);
+      }
+    }
+    i++;
+  }
+  printk("Apb slaves:\n");
+  i = 0;
+  while (i < amba_conf.apbslv.devnr) 
+  {
+    
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    
+    m = amba_apb_get_membar(amba_conf.apbslv, i);
+    addr = amba_iobar_start(amba_conf.apbmst, m);
+    printk(" +%2i: 0x%x (raw:0x%x) \n", 0, addr, m);
+    
+    i++;
+    
+  }
+  
+}
+
+#define amba_insert_device(tab, address) \
+{ \
+  if (LEON3_BYPASS_LOAD_PA(address)) \
+  { \
+    (tab)->addr[(tab)->devnr] = (address); \
+    (tab)->devnr ++; \
+  } \
+} while(0)
+
+/*
+ *  Used to scan system bus. Probes for AHB masters, AHB slaves and 
+ *  APB slaves. Addresses to configuration areas of the AHB masters,
+ *  AHB slaves, APB slaves and APB master are storeds in 
+ *  amba_ahb_masters, amba_ahb_slaves and amba.
+ */
+
+void amba_init(void) 
+{
+  unsigned int *cfg_area;  /* address to configuration area */
+  unsigned int mbar, conf;
+  int i, j;
+  
+#ifdef DEBUG_CONFIG
+  printk("Reading AMBA Plug&Play configuration area\n");
+#endif
+
+  memset(&amba_conf,0,sizeof(amba_conf));
+  //amba_conf.ahbmst.devnr = 0; amba_conf.ahbslv.devnr = 0; amba_conf.apbslv.devnr = 0;
+  
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA);
+
+  for (i = 0; i < LEON3_AHB_MASTERS; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbmst, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }
+
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA | LEON3_AHB_SLAVE_CONF_AREA);
+  for (i = 0; i < LEON3_AHB_SLAVES; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbslv, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }  
+
+  for (i = 0; i < amba_conf.ahbslv.devnr; i ++) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    mbar = amba_ahb_get_membar(amba_conf.ahbslv, i, 0);
+    if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_APBMST))
+    {
+      amba_conf.apbmst = amba_membar_start(mbar);
+      cfg_area = (unsigned int *) (amba_conf.apbmst | LEON3_CONF_AREA);
+      
+      printk("Found apbmst, cfg: 0x%x\n",(unsigned int)cfg_area);
+      
+      for (j = amba_conf.apbslv.devnr; j < LEON3_APB_SLAVES; j++)
+      {
+	amba_insert_device(&amba_conf.apbslv, cfg_area);
+	cfg_area += LEON3_APB_CONF_WORDS;
+      }
+    }
+  }    
+ 
+  /* Find LEON3 Interrupt controler */
+  LEON3_IrqCtrl_Regs = (volatile LEON3_IrqCtrl_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_IRQMP, 0);
+  LEON3_GpTimer_Regs = (volatile LEON3_GpTimer_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_GPTIMER, &LEON3_GpTimer_Irq);
+  if (LEON3_IrqCtrl_Regs) {
+    LEON3_BYPASS_STORE_PA(&(LEON3_IrqCtrl_Regs ->mask[0]),0);
+  }
+}
+
+unsigned long amba_find_apbslv_addr(unsigned long vendor, unsigned long device, unsigned long *irq) {
+  unsigned int i,conf,iobar;
+  for (i = 0; i < amba_conf.apbslv.devnr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device))
+    {
+      if (irq) {
+        *irq = amba_irq(conf);
+      }
+      iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+      return amba_iobar_start(amba_conf.apbmst, iobar);
+    }
+  }
+  return 0;
+}
diff -Naur ../linux-2.6.10/drivers/amba/amba_driver.c linux-2.6.10/drivers/amba/amba_driver.c
--- ../linux-2.6.10/drivers/amba/amba_driver.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba_driver.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,78 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+extern amba_confarea_type amba_conf;
+ 
+//collect apb slaves
+int amba_get_free_apbslv_devices (int vendor, int device, amba_apb_device *dev,int nr) {
+  unsigned int i,conf,iobar,j = 0;
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: search for apdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.apbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.apbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Apbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.apbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+        iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+        dev[j].start = amba_iobar_start(amba_conf.apbmst, iobar);
+#ifdef DEBUG_CONFIG
+	printk(" +bar: 0x%x \n", k, dev[j].start);
+#endif
+        j++;
+      }
+    }
+  }
+  return j;
+}
+
+//collect ahb slaves
+int amba_get_free_ahbslv_devices (int vendor, int device, amba_ahb_device *dev,int nr) {
+  unsigned int addr, i,conf,iobar,j = 0,k;
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: search for ahdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.ahbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.ahbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Ahbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.ahbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+	for (k = 0; k < 4; k ++) {
+	  iobar = amba_ahb_get_membar(amba_conf.ahbslv, i, k);
+	  addr = amba_membar_start(iobar);
+	  if (amba_membar_type(iobar) == AMBA_TYPE_AHBIO) {
+	    addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	  }
+	  dev[j].start[k] = addr;
+#ifdef DEBUG_CONFIG
+	  printk(" +%i: 0x%x \n", k, dev[j].start[k]);
+#endif
+	}
+        j++;
+      }
+    }
+  }
+  return j;
+}
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Kconfig linux-2.6.10/drivers/amba/gaisler/Kconfig
--- ../linux-2.6.10/drivers/amba/gaisler/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,12 @@
+
+menu "Vendor Gaisler"
+
+config GRLIB_GAISLER_APBUART
+	bool "Grlib apbuart driver" 
+	default y
+	---help---
+	  Add the driver for the grlib apbuart serial core.
+
+endmenu
+
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Makefile linux-2.6.10/drivers/amba/gaisler/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_GAISLER_APBUART)		+= apbuart/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= apbuart.o
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,729 @@
+/*
+ *  linux/drivers/serial/leon.c
+ *
+ *  Driver for Leon serial ports
+ *
+ *  Based on linux/drivers/serial/amba.c , Documentation/serial/driver
+ * 
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ * 
+ *  Modified for Leon by Konrad Eisele <eiselekd@web.de>, 2003
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+
+#if defined(CONFIG_SERIAL_LEON_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <asm/leon.h>
+
+#define UART_NR		8
+int leon_ports_nr = 0;
+
+#define SERIAL_LEON_MAJOR	TTY_MAJOR
+#define SERIAL_LEON_MINOR	64
+#define SERIAL_LEON_NR		UART_NR
+
+#define AMBA_ISR_PASS_LIMIT	256
+
+#define APBBASE(port) ((LEON3_APBUART_Regs_Map *)((port)->membase))
+
+#define APBBASE_DATA_P(port) (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port)	(LEON_BYPASS_LOAD_PA(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v)	(LEON_BYPASS_STORE_PA(APBBASE_DATA_P(port),v))
+#define UART_GET_STATUS(port)	(LEON_BYPASS_LOAD_PA(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port,v)	(LEON_BYPASS_STORE_PA(APBBASE_STATUS_P(port),v))
+#define UART_GET_CTRL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_CTRL_P(port),v))
+#define UART_GET_SCAL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_SCALAR_P(port),v))
+#define UART_RX_DATA(s)       (((s) & LEON_REG_UART_STATUS_DR) != 0)
+#define UART_TX_READY(s)	(((s) & LEON_REG_UART_STATUS_THE) != 0)
+
+#define UART_DUMMY_RSR_RX	0x8000 /* for ignore all read */
+
+/* We wrap our port structure around the generic uart_port */
+struct uart_leon_port {
+	struct uart_port	port;
+	unsigned int		old_status;
+};
+
+static void leonuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port);
+static void leonuart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr |= LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+	
+	if (UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars (port);
+	}
+}
+
+static void leonuart_stop_rx(struct uart_port *port)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~(LEON_REG_UART_CTRL_RI);
+	UART_PUT_CTRL(port, cr);
+}
+
+static void leonuart_enable_ms(struct uart_port *port)
+{
+	/* no modem status for leon */
+}
+
+//static 
+void
+#ifdef SUPPORT_SYSRQ
+leonuart_rx_chars(struct uart_port *port, struct pt_regs *regs)
+#else
+leonuart_rx_chars(struct uart_port *port)
+#endif
+{
+	struct tty_struct *tty = port->info->tty;
+	unsigned int status, ch, rsr;
+
+	status = UART_GET_STATUS(port); 
+	if (UART_RX_DATA(status)) {
+      
+            if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.work.func((void *)tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+				return;
+			}
+		}
+
+		ch = UART_GET_CHAR(port); 
+
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = TTY_NORMAL;
+		port->icount.rx++;
+
+		/*
+		 * Note that the error handling code is
+		 * out of the main execution path
+		 */
+		rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX; 
+		UART_PUT_STATUS(port,0);
+		if (rsr & LEON_REG_UART_STATUS_ERR) { 
+
+		  if (rsr & LEON_REG_UART_STATUS_BR) {
+		    rsr &= ~(LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE);
+		    port->icount.brk++;
+		    if (uart_handle_break(port))
+		      goto ignore_char;
+		  } else if (rsr & LEON_REG_UART_STATUS_PE) {
+		    port->icount.parity++;
+		  } else if (rsr & LEON_REG_UART_STATUS_FE) {
+		    port->icount.frame++;
+		  }
+		  if (rsr & LEON_REG_UART_STATUS_OE)
+		    port->icount.overrun++;
+                  
+		  rsr &= port->read_status_mask;
+		  
+		  if (rsr & LEON_REG_UART_STATUS_PE)
+		    *tty->flip.flag_buf_ptr = TTY_PARITY;
+                  else if (rsr & LEON_REG_UART_STATUS_FE)
+		    *tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+            
+		if (uart_handle_sysrq_char(port, ch, regs))
+		    goto ignore_char;
+		
+		if ((rsr & port->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((rsr & LEON_REG_UART_STATUS_OE) &&
+		    tty->flip.count < TTY_FLIPBUF_SIZE) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.char_buf_ptr++ = 0;
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+			tty->flip.count++;
+		}
+	}
+ignore_char:
+	tty_flip_buffer_push(tty);
+	return;
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	int count;
+
+	if (port->x_char) {
+		UART_PUT_CHAR(port, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		leonuart_stop_tx(port, 0);
+		return;
+	}
+
+	count = port->fifosize >> 1; //amba: fill FIFO
+	do {
+		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		leonuart_stop_tx(port, 0);
+}
+
+//static 
+irqreturn_t leonuart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	unsigned int status;
+
+	spin_lock(port ->lock);
+
+	status = UART_GET_STATUS(port);
+	if (status & LEON_REG_UART_STATUS_DR) {
+#ifdef SUPPORT_SYSRQ
+	  leonuart_rx_chars(port,regs);
+#else
+	  leonuart_rx_chars(port);
+#endif          
+	}
+	if (status & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars(port);
+	}
+	spin_unlock(port ->lock);
+	return IRQ_HANDLED;
+}
+
+static unsigned int leonuart_tx_empty(struct uart_port *port)
+{
+	return UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int leonuart_get_mctrl(struct uart_port *port)
+{
+	unsigned int result = 0;
+
+	/*
+	  no modem status for leon
+	*/
+
+	return result;
+}
+
+static void leonuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* no modem status for leon */
+}
+
+static void leonuart_break_ctl(struct uart_port *port, int break_state)
+{
+	/* no break for leon */
+}
+
+static int leonuart_startup(struct uart_port *port)
+{
+	struct uart_leon_port *uap = (struct uart_leon_port *)port;
+	int retval;
+	unsigned int cr;
+
+	/*
+	 * Allocate the IRQ
+	 */
+	retval = request_irq(port->irq, leonuart_int, 0, "leon", port);
+	if (retval)
+		return retval;
+
+	/*
+	 * initialise the old status of the modem signals
+	 */
+	uap->old_status = 0;
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr | LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI );	
+      
+	return 0;
+}
+
+static void leonuart_shutdown(struct uart_port *port)
+{
+	unsigned int cr;
+
+	/*
+	 * Free the interrupt
+	 */
+	free_irq(port->irq, port);
+
+	/*
+	 * disable all interrupts, disable the port
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr & ~( LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI ));	
+      
+}
+
+static void
+leonuart_set_termios(struct uart_port *port, struct termios *termios,
+		     struct termios *old)
+{
+	unsigned int cr;
+	unsigned long flags;
+	unsigned int baud, quot;
+
+	/*
+	 * Ask the core to calculate the divisor for us.
+	 */
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	if (baud == 0) {
+	  panic("invalid baudrate %i\n", port->uartclk/16);
+	}
+	quot = (uart_get_divisor(port, baud)) * 2; //uart_get_divisor calc a *16 uart freq, leon is *8
+	cr = UART_GET_CTRL(port);
+	cr &= ~( LEON_REG_UART_CTRL_PE | LEON_REG_UART_CTRL_PS );
+	  
+	if (termios->c_cflag & PARENB) { 
+		cr |= LEON_REG_UART_CTRL_PE; 
+		if ((termios->c_cflag & PARODD))
+			cr |= LEON_REG_UART_CTRL_PS;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/*
+	 * Update the per-port timeout.
+	 */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	port->read_status_mask = LEON_REG_UART_STATUS_OE;
+	if (termios->c_iflag & INPCK) 
+		port->read_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE ;
+
+	/*
+	 * Characters to ignore
+	 */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_OE | LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/* Set baud rate */
+	quot -= 1;
+	UART_PUT_SCAL(port, quot);
+	UART_PUT_CTRL(port, cr);
+      
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *leonuart_type(struct uart_port *port)
+{
+	return port->type == PORT_LEON ? "Leon" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void leonuart_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int leonuart_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void leonuart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_LEON;
+		leonuart_request_port(port);
+	}
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int leonuart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_LEON)
+		ret = -EINVAL;
+	if (ser->irq < 0 || ser->irq >= NR_IRQS)
+		ret = -EINVAL;
+	if (ser->baud_base < 9600)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops leon_pops = {
+	.tx_empty	= leonuart_tx_empty,
+	.set_mctrl	= leonuart_set_mctrl,
+	.get_mctrl	= leonuart_get_mctrl,
+	.stop_tx	= leonuart_stop_tx,
+	.start_tx	= leonuart_start_tx,
+	.stop_rx	= leonuart_stop_rx,
+	.enable_ms	= leonuart_enable_ms,
+	.break_ctl	= leonuart_break_ctl,
+	.startup	= leonuart_startup,
+	.shutdown	= leonuart_shutdown,
+	.set_termios	= leonuart_set_termios,
+	.type		= leonuart_type,
+	.release_port	= leonuart_release_port,
+	.request_port	= leonuart_request_port,
+	.config_port	= leonuart_config_port,
+	.verify_port	= leonuart_verify_port,
+};
+
+static struct uart_leon_port leon_ports[UART_NR];
+/* = {
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART0),
+			.mapbase	= (LEON_PREGS+LEON_UART0),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_0_RX_TX,
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+	},
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART1),
+			.mapbase	= (LEON_PREGS+LEON_UART1),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_1_RX_TX, 
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+	}
+};*/
+
+extern volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs;
+
+/* rs_init inits the driver */
+static int _apbuart_init_bases_done = 0;
+static void __init 
+_apbuart_init_bases(void)
+{
+  int  i; 
+  amba_apb_device dev[8];
+  if (!_apbuart_init_bases_done ) {
+    unsigned long clk = ((unsigned long)(((LEON3_BYPASS_LOAD_PA(&LEON3_GpTimer_Regs->scalar_reload)) + 1))); 
+    printk("Attaching grlib apbuart serial drivers (clk:%ihz):\n",(int)clk);
+    leon_ports_nr = amba_get_free_apbslv_devices (VENDOR_GAISLER, GAISLER_APBUART, dev, 8);
+
+    for (i = 0;i < leon_ports_nr;i++) {
+      leon_ports[i].port.membase = (void *)dev[i].start;
+      leon_ports[i].port.mapbase = dev[i].start;
+      leon_ports[i].port.irq = dev[i].irq;
+      leon_ports[i].port.iotype = SERIAL_IO_MEM;
+      leon_ports[i].port.uartclk = clk * 1000 * 1000;
+      leon_ports[i].port.fifosize = 1;
+      leon_ports[i].port.ops	= &leon_pops;
+      leon_ports[i].port.flags = ASYNC_BOOT_AUTOCONF;
+      leon_ports[i].port.line =i;
+    }
+    _apbuart_init_bases_done = 1;
+  }
+}
+
+
+#ifdef CONFIG_SERIAL_LEON_CONSOLE
+
+static void
+leonuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_port *port = &leon_ports[co->index].port;
+	unsigned int status, old_cr;
+	int i;
+
+	/*
+	 *	First save the CR then disable the interrupts
+	 */
+	old_cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, (old_cr & ~(LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI)) | (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE) ); 
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++) {
+		do {
+			status = UART_GET_STATUS(port);
+		} while (!UART_TX_READY(status));
+		UART_PUT_CHAR(port, s[i]);
+		if (s[i] == '\n') {
+			do {
+				status = UART_GET_STATUS(port);
+			} while (!UART_TX_READY(status));
+			UART_PUT_CHAR(port, '\r');
+		}
+	}
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore the TCR
+	 */
+	do {
+		status = UART_GET_STATUS(port);
+	} while (!UART_TX_READY(status));
+	UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+leonuart_console_get_options(struct uart_port *port, int *baud,
+			     int *parity, int *bits)
+{
+      if (UART_GET_CTRL(port) & (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE)) {
+	
+		unsigned int quot, status;
+		status = UART_GET_STATUS(port);
+
+		*parity = 'n';
+		if (status & LEON_REG_UART_CTRL_PE) {
+			if ((status & LEON_REG_UART_CTRL_PS) == 0 )
+				*parity = 'e';
+			else
+				*parity = 'o';
+		}
+            
+		*bits = 8;
+            quot = UART_GET_SCAL(port) / 8;
+		*baud = port->uartclk / (16 * (quot + 1));
+	}
+}
+
+static int __init leonuart_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 38400;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	/*
+	 * Check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	if (co->index >= leon_ports_nr)
+		co->index = 0;
+	port = &leon_ports[co->index].port;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		leonuart_console_get_options(port, &baud, &parity, &bits);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+static struct uart_driver leon_reg;
+static struct console leon_console = {
+	.name		= "ttyS",
+	.write		= leonuart_console_write,
+	.device		= uart_console_device,
+	.setup		= leonuart_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &leon_reg,
+};
+
+//static int leonuart_init(void);
+static int __init leonuart_console_init(void)
+{
+	_apbuart_init_bases();
+	register_console(&leon_console);
+	return 0;
+}
+console_initcall(leonuart_console_init);
+
+#define LEON_CONSOLE	&leon_console
+#else
+#define LEON_CONSOLE	NULL
+#endif
+
+static struct uart_driver leon_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "serial",
+	.devfs_name	= "tts/",
+	.dev_name	= "ttyS",
+	.major		= SERIAL_LEON_MAJOR,
+	.minor		= SERIAL_LEON_MINOR,
+	.nr		= UART_NR,
+	.cons		= LEON_CONSOLE,
+};
+
+
+static int __init gaisler_apbuart_init(void)
+{
+	int ret;
+	int i;
+	int node;
+	int freq_khz;
+	int baud_rates[UART_NR];
+
+	_apbuart_init_bases();
+	node = prom_getchild(prom_root_node);
+	freq_khz = prom_getint(node, "frequency");
+	
+	printk(KERN_INFO "grlib apbuart: %i serial driver(s) at [",leon_ports_nr);
+	for (i = 0; i < leon_ports_nr; i++) {
+	  baud_rates[i] = prom_getintdefault(node, "uart1_baud", 9600);
+	  if (i != 0) {printk(",");}
+	  printk("0x%x",(unsigned int) leon_ports[i].port.mapbase);
+	  printk("(irq %i)",leon_ports[i].port.irq);
+	}
+	printk("]\n");
+
+	baud_rates[0] = prom_getintdefault(node, "uart1_baud", 9600);
+	baud_rates[1] = prom_getintdefault(node, "uart2_baud", 9600);
+
+	printk(KERN_INFO "grlib apbuart: system frequency: %i khz, baud rates: %i %i\n", freq_khz, baud_rates[0], baud_rates[1]);
+
+	ret = uart_register_driver(&leon_reg);
+	leon_reg.tty_driver->init_termios.c_cflag = 
+		(leon_reg.tty_driver->init_termios.c_cflag & ~CBAUD) | B38400;
+	
+	if (ret) return ret;
+
+	for (i = 0; i < leon_ports_nr; i++) {
+		struct console co;
+		leon_ports[i].port.uartclk = freq_khz * 1000;
+		uart_add_one_port(&leon_reg, &leon_ports[i].port);
+		uart_set_options(&leon_ports[i].port, &co,
+				 baud_rates[i], 'n', 8, 'n');
+	}
+
+	return ret;
+}
+
+static void __exit gaisler_apbuart_exit(void)
+{
+	int i;
+
+	for (i = 0; i < leon_ports_nr; i++)
+		uart_remove_one_port(&leon_reg, &leon_ports[i].port);
+
+	uart_unregister_driver(&leon_reg);
+}
+
+module_init(gaisler_apbuart_init);
+module_exit(gaisler_apbuart_exit);
+
+MODULE_AUTHOR("Konrad Eisele<eiselekd@web.de>, based on AMBA serial");
+MODULE_DESCRIPTION("grlib apbuart serial driver");
+MODULE_LICENSE("GPL");
+
+
+
+
+
+void leon3_rs_put_char_base(LEON3_APBUART_Regs_Map *uart_regs,char ch)
+{
+        int flags, loops;
+
+        save_flags(flags); cli();
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_THE) && (loops < 100000))
+        	loops++;
+
+	LEON3_BYPASS_STORE_PA(&(uart_regs->data),ch);
+
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_TSE) && (loops < 100000))
+        	loops++;
+        restore_flags(flags);
+}
+
+void leon3_rs_put_char(char ch)
+{
+  LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+  if (b) {
+    leon3_rs_put_char_base(b,ch);
+  }
+}
+
+void console_print_LEON(const char *p)
+{
+	char c;
+
+        LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+        
+	while((c=*(p++)) != 0) {
+          if(c == '\n')
+            leon3_rs_put_char_base(b,'\r');
+          leon3_rs_put_char_base(b,c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	/* rs_fair_output(); */
+
+	return;
+}
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Kconfig linux-2.6.10/drivers/amba/opencores/Kconfig
--- ../linux-2.6.10/drivers/amba/opencores/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,36 @@
+
+menu "Vendor Opencores"
+
+config GRLIB_OPENCORES_ETHERMAC
+	bool "Grlib's opencores ethermac driver" 
+	default y
+	depends on NETDEVICES
+	---help---
+	  Add the driver for the grlib opencore ethermac.
+
+
+config GRLIB_OPENCORES_ETHERMAC_MACMSB
+	hex "MSB 24 bits of ethern number (hex)" 
+	default 00007A
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Most significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is 00007A.
+
+config GRLIB_OPENCORES_ETHERMAC_MACLSB
+	hex "LSB 24 bits of ethern number (hex)" 
+	default CC0012
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Least significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is CC0012.
+
+
+
+
+endmenu
+
+
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Makefile linux-2.6.10/drivers/amba/opencores/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_OPENCORES_ETHERMAC)		+= ethermac/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile linux-2.6.10/drivers/amba/opencores/ethermac/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= open_eth.o
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,1181 @@
+/*
+ * Ethernet driver for Open Ethernet Controller (www.opencores.org).
+ *      Copyright (c) 2002 Simon Srot (simons@opencores.org)
+ *
+ * Based on:
+ *
+ * Ethernet driver for Motorola MPC8xx.
+ *      Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * mcen302.c: A Linux network driver for Mototrola 68EN302 MCU
+ *
+ *      Copyright (C) 1999 Aplio S.A. Written by Vadim Lebedev
+ *
+ * Right now XXBUFF_PREALLOC must be used, because MAC does not 
+ * handle unaligned buffers yet.  Also the cache inhibit calls
+ * should be used some day.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/cacheflush.h>
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/rtnetlink.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <asm/processor.h>	/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+ 
+#ifdef CONFIG_LEON
+#include <asm/leon.h>
+//#define OETH_INTERRUPT LEON_INTERRUPT_OPEN_ETH
+#define DEBUG 1
+#endif
+
+/*
+#define MACADDR1 0
+#define MACADDR2 0
+#define MACADDR3 0
+#define MACADDR4 0
+#define MACADDR5 0
+*/
+ 
+#define MACADDR0 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 16) & 0xff)
+#define MACADDR1 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 8) & 0xff)
+#define MACADDR2 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 0) & 0xff)
+#define MACADDR3 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 16) & 0xff)
+#define MACADDR4 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 8) & 0xff)
+#define MACADDR5 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 0) & 0xff)
+
+#include "open_eth.h"
+
+//#define net_device device
+//#define __pa(x) (x)
+//#define __va(x) (x)
+#define __clear_user(add,len) memset((add),0,(len))
+
+
+#define RXBUFF_PREALLOC	1
+#define TXBUFF_PREALLOC	1
+
+//#define SRAM_BUFF	1
+//#define SRAM_BUFF_BASE	(FBMEM_BASE_ADD + 0x80000)
+
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT	(2*HZ)
+
+/* Buffer number (must be 2^n) 
+ */
+#define OETH_RXBD_NUM		8
+#define OETH_TXBD_NUM		8
+#define OETH_RXBD_NUM_MASK	(OETH_RXBD_NUM-1)
+#define OETH_TXBD_NUM_MASK	(OETH_TXBD_NUM-1)
+
+/* Buffer size 
+ */
+#define OETH_RX_BUFF_SIZE	2048
+#define OETH_TX_BUFF_SIZE	2048
+
+/* How many buffers per page 
+ */
+#define OETH_RX_BUFF_PPGAE	(PAGE_SIZE/OETH_RX_BUFF_SIZE)
+#define OETH_TX_BUFF_PPGAE	(PAGE_SIZE/OETH_TX_BUFF_SIZE)
+
+/* How many pages is needed for buffers 
+ */
+#define OETH_RX_BUFF_PAGE_NUM	(OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE)
+#define OETH_TX_BUFF_PAGE_NUM	(OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE)
+
+/* Buffer size  (if not XXBUF_PREALLOC 
+ */
+#define MAX_FRAME_SIZE		1518
+
+/* The buffer descriptors track the ring buffers.   
+ */
+struct oeth_private {
+	struct	sk_buff* rx_skbuff[OETH_RXBD_NUM];
+	struct	sk_buff* tx_skbuff[OETH_TXBD_NUM];
+
+	ushort	tx_next;			/* Next buffer to be sent */
+	ushort	tx_last;			/* Next buffer to be checked if packet sent */
+	ushort	tx_full;			/* Buffer ring fuul indicator */
+	ushort	rx_cur;				/* Next buffer to be checked if packet received */
+
+	oeth_regs	*regs;			/* Address of controller registers. */
+	oeth_bd		*rx_bd_base;		/* Address of Rx BDs. */
+	oeth_bd		*tx_bd_base;		/* Address of Tx BDs. */
+        ushort          irq;
+
+	struct net_device_stats stats;
+};
+
+static int oeth_open(struct net_device *dev);
+static int oeth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void oeth_rx(struct net_device *dev);
+static void oeth_tx(struct net_device *dev);
+static irqreturn_t oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int oeth_close(struct net_device *dev);
+static struct net_device_stats *oeth_get_stats(struct net_device *dev);
+static void oeth_set_multicast_list(struct net_device *dev);
+static int oeth_set_mac_address(struct net_device *dev,void *p);
+static int calc_crc(char *mac_addr);
+
+#define OETH_REGLOAD(a)	(LEON3_BYPASS_LOAD_PA(&(a)))
+#define OETH_REGSAVE(a,v) (LEON3_BYPASS_STORE_PA(&(a),v))
+#define OETH_REGORIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) | (v))))
+#define OETH_REGANDIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) & (v))))
+
+
+#if DEBUG
+static void
+oeth_print_packet(unsigned long add, int len)
+{
+  //	int i;
+
+	printk("ipacket: add = %x len = %d\n", (unsigned int)add, len);
+/*
+	for(i = 0; i < len; i++) {
+  		if(!(i % 16))
+    			printk("\n");
+  		printk(" %.2x", *(((unsigned char *)add) + i));
+	}
+*/
+      printk("\n");
+	printk("                             \n");
+}
+#endif
+
+static int
+oeth_open(struct net_device *dev)
+{
+
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	
+#if DEBUG
+	printk("oeth_open\n");
+#endif
+#ifndef RXBUFF_PREALLOC
+	struct  sk_buff *skb;
+	volatile oeth_bd *rx_bd;
+	int i;
+
+	rx_bd = cep->rx_bd_base;
+
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+		skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+		if (skb == NULL)
+      		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+		else
+		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = skb;
+
+		OETH_REGSAVE(rx_bd[i].addr,(unsigned long)skb->tail);
+		//rx_bd[i].addr = (unsigned long)skb->tail;
+	}
+        OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+#endif
+
+	/* Install our interrupt handler.
+	 */
+	request_irq(cep->irq, oeth_interrupt, 0, "eth", (void *)dev);
+
+	/* Enable receiver and transmiter 
+	 */
+        OETH_REGORIN(regs->moder , OETH_MODER_RXEN | OETH_MODER_TXEN);
+	//regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
+
+	return 0;
+}
+
+static int
+oeth_close(struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	volatile oeth_bd *bdp;
+	int i;
+
+#if DEBUG
+	printk("oeth_close\n");
+#endif
+	/* Free interrupt hadler 
+	 */
+	free_irq(cep->irq, (void *)dev);
+
+	/* Disable receiver and transmitesr 
+	 */
+        OETH_REGANDIN(regs->moder , ~(OETH_MODER_RXEN | OETH_MODER_TXEN));
+	//regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);	
+
+	bdp = cep->rx_bd_base;
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status, ~(OETH_TX_BD_STATS | OETH_TX_BD_READY));
+		//bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
+		bdp++;
+	}
+
+	bdp = cep->tx_bd_base;
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status , ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY));
+		//bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
+		bdp++;
+	}
+
+#ifndef RXBUFF_PREALLOC
+
+	/* Free all alocated rx buffers 
+	 */
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	
+		if (cep->rx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->rx_skbuff[i]); //, FREE_READ);
+		
+	}
+#endif
+#ifndef TXBUFF_PREALLOC
+
+	/* Free all alocated tx buffers 
+	 */
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	
+		if (cep->tx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->tx_skbuff[i]);//, FREE_WRITE);
+	}
+#endif
+
+	return 0;
+}
+
+static int
+oeth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	volatile oeth_bd *bdp;
+	unsigned long flags;
+
+	/* Fill in a Tx ring entry 
+	 */
+	bdp = cep->tx_bd_base + cep->tx_next;
+
+	if (cep->tx_full) {
+
+		/* All transmit buffers are full.  Bail out.
+		 */
+		printk("%s: tx queue full!.\n", dev->name);
+		return 1;
+	}
+
+	/* Clear all of the status flags.
+	 */
+	OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_STATS);
+	//bdp->len_status &= ~OETH_TX_BD_STATS;
+
+	/* If the frame is short, tell CPM to pad it.
+	 */
+	if (skb->len <= ETH_ZLEN)
+	        OETH_REGORIN(bdp->len_status , OETH_TX_BD_PAD);
+	        //bdp->len_status |= OETH_TX_BD_PAD;
+	else
+	        OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_PAD);
+	        //bdp->len_status &= ~OETH_TX_BD_PAD;
+
+#if DEBUG
+	printk("TX\n");
+	oeth_print_packet((unsigned long)skb->data, skb->len);
+#endif
+
+#ifdef TXBUFF_PREALLOC
+
+	/* Copy data in preallocated buffer */
+	if (skb->len > OETH_TX_BUFF_SIZE) {
+		printk("%s: tx frame too long!.\n", dev->name);
+		return 1;
+	}
+	else {
+	  
+	  memcpy(__va((unsigned char *)OETH_REGLOAD(bdp->addr)), skb->data, skb->len); 
+            __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+	    //memcpy(__va((unsigned char *)bdp->addr), skb->data, skb->len); 
+            //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+      }
+
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16));
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+
+	dev_kfree_skb(skb); // 	dev_kfree_skb(skb, FREE_WRITE);
+#else
+	/* Set buffer length and buffer pointer.
+	 */
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16))
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+	OETH_REGSAVE(bdp->addr , (uint)__pa(skb->data));
+	//bdp->addr = (uint)__pa(skb->data);
+
+	/* Save skb pointer.
+	 */
+	cep->tx_skbuff[cep->tx_next] = skb;
+#endif
+
+	cep->tx_next = (cep->tx_next + 1) & OETH_TXBD_NUM_MASK;
+	
+	save_flags(flags); cli();
+
+	if (cep->tx_next == cep->tx_last)
+		cep->tx_full = 1;
+
+	/* Send it on its way.  Tell controller its ready, interrupt when done,
+	 * and to put the CRC on the end.
+	 */
+        OETH_REGORIN(bdp->len_status , (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC));
+	//bdp->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
+
+	dev->trans_start = jiffies;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The interrupt handler.
+ */
+static irqreturn_t
+oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct	net_device *dev = dev_id;
+	volatile struct	oeth_private *cep;
+	uint	int_events;
+      
+#if DEBUG
+      printk ("oeth_interrupt()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get the interrupt events that caused us to be here.
+	 */
+        int_events = OETH_REGLOAD( cep->regs->int_src);
+	//int_events = cep->regs->int_src;
+        OETH_REGSAVE(cep->regs->int_src , int_events);
+	//cep->regs->int_src = int_events;
+
+	/* Handle receive event in its own function.
+	 */
+	if (int_events & (OETH_INT_RXF | OETH_INT_RXE))
+		oeth_rx(dev_id);
+
+	/* Handle transmit event in its own function.
+	 */
+	if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
+		oeth_tx(dev_id);
+            netif_wake_queue(dev); //mark_bh(NET_BH);
+	}
+
+	/* Check for receive busy, i.e. packets coming but no place to
+	 * put them. 
+	 */
+	if (int_events & OETH_INT_BUSY) {
+		if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE)))
+			oeth_rx(dev_id);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static void
+oeth_tx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+
+#ifndef TXBUFF_PREALLOC
+	struct	sk_buff *skb;
+#endif
+
+#if DEBUG
+      printk ("oeth_tx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) {
+
+		bdp = cep->tx_bd_base + cep->tx_last;
+
+		if ((OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_READY) || 
+		//if ((bdp->len_status & OETH_TX_BD_READY) || 
+			((cep->tx_last == cep->tx_next) && !cep->tx_full))
+			break;
+
+		/* Check status for errors
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+
+		/* Check status for errors
+		 */
+                /*
+		if (bdp->len_status & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (bdp->len_status & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (bdp->len_status & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (bdp->len_status & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (bdp->len_status & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+		*/
+
+		cep->stats.tx_packets++;
+		cep->stats.collisions += (OETH_REGLOAD(bdp->len_status) >> 4) & 0x000f;
+		//cep->stats.collisions += (bdp->len_status >> 4) & 0x000f;
+
+#ifndef TXBUFF_PREALLOC
+		skb = cep->tx_skbuff[cep->tx_last];
+
+		/* Free the sk buffer associated with this last transmit.
+		*/
+		dev_kfree_skb(skb);//, FREE_WRITE);
+#endif
+
+		if (cep->tx_full)
+			cep->tx_full = 0;
+	}
+}
+
+static void
+oeth_rx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+	struct	sk_buff *skb;
+	int	pkt_len;
+	int	bad = 0;
+#ifndef RXBUFF_PREALLOC
+	struct	sk_buff *small_skb;
+#endif
+      
+#if DEBUG
+      printk ("oeth_rx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* First, grab all of the stats for the incoming packet.
+	 * These get messed up if we get called due to a busy condition.
+	 */
+	for (;;cep->rx_cur = (cep->rx_cur + 1) & OETH_RXBD_NUM_MASK) {
+
+		bdp = cep->rx_bd_base + cep->rx_cur;
+
+#ifndef RXBUFF_PREALLOC
+		skb = cep->rx_skbuff[cep->rx_cur];
+
+		if (skb == NULL) {
+
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			if (skb != NULL)
+			{
+				OETH_REGSAVE(bdp->addr , (unsigned long) skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long) skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+
+			continue;
+		}
+#endif
+			
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_EMPTY)
+		//if (bdp->len_status & OETH_RX_BD_EMPTY)
+			break;
+			
+		/* Check status for errors.
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+		//if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+                  printk ("oeth: length error\n");
+			cep->stats.rx_length_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_DRIBBLE) {
+		//if (bdp->len_status & OETH_RX_BD_DRIBBLE) {
+                  printk ("oeth: dribble error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_CRCERR) {
+		//if (bdp->len_status & OETH_RX_BD_CRCERR) {
+                  printk ("oeth: crc error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_OVERRUN) {
+		//if (bdp->len_status & OETH_RX_BD_OVERRUN) {
+                  printk ("oeth: overrun error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_MISS) {
+		//if (bdp->len_status & OETH_RX_BD_MISS) {
+                  printk ("oeth: miss error\n");
+
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_LATECOL) {
+		//if (bdp->len_status & OETH_RX_BD_LATECOL) {
+                  printk ("oeth: latecol error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		
+		
+		if (bad) {
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+      //bdp->len_status &= ~OETH_RX_BD_STATS;
+      //bdp->len_status |= OETH_RX_BD_EMPTY;
+
+			continue;
+		}
+
+		/* Process the incoming frame.
+		 */
+		pkt_len = OETH_REGLOAD(bdp->len_status) >> 16;
+		//pkt_len = bdp->len_status >> 16;
+        
+#ifdef RXBUFF_PREALLOC
+		//skb = dev_alloc_skb(pkt_len);
+                skb = alloc_skb(pkt_len + 4, GFP_ATOMIC); //added from michael wurm's patches
+
+		if (skb == NULL) {
+			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+			cep->stats.rx_dropped++;
+		}
+		else {
+			skb_reserve(skb, 2); //added from michael wurm's patches
+			skb->dev = dev;
+
+                  __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+                  //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+#if DEBUG
+			printk("RX\n");
+                  oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), pkt_len);
+                  //oeth_print_packet((unsigned long)(__va(bdp->addr)), pkt_len);
+#endif
+			memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+			//memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+		}
+
+		OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+		OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+		//bdp->len_status &= ~OETH_RX_BD_STATS;
+		//bdp->len_status |= OETH_RX_BD_EMPTY;
+#else //RXBUFF_PREALLOC
+
+		if (pkt_len < 128) {
+
+			small_skb = dev_alloc_skb(pkt_len);
+
+			if (small_skb) {
+				small_skb->dev = dev;
+
+                        __flush_page_to_ram(__va(OETH_REGLOAD(bdp->addr)));
+                        //__flush_page_to_ram(__va(bdp->addr));
+#if DEBUG
+				printk("RX short\n");
+                        oeth_print_packet((unsigned long)(__va(bdp->addr)), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+                        memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+                        //memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+
+                        small_skb->protocol = eth_type_trans(small_skb,dev);
+                        netif_rx(small_skb);
+				cep->stats.rx_packets++;
+			}
+			else {
+				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+	                        cep->stats.rx_dropped++;
+			}
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+			//bdp->len_status |= OETH_RX_BD_EMPTY;
+		}
+		else {
+        		skb->dev = dev;
+			skb_put(skb, OETH_REGLOAD(bdp->len_status) >> 16);
+			//skb_put(skb, bdp->len_status >> 16);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+#if DEBUG
+			printk("RX long\n");
+                        oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+		
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+        
+			if (skb) {
+				cep->rx_skbuff[cep->rx_cur] = skb;
+
+				OETH_REGSAVE(bdp->addr , (unsigned long)skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long)skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+			else {
+				cep->rx_skbuff[cep->rx_cur] = NULL;	
+			}
+		}
+#endif //!RXBUFF_PREALLOC
+	}
+
+#if DEBUG
+      printk ("oeth_rx sent()\n");
+#endif
+}
+
+static int calc_crc(char *mac_addr)
+{
+	int result = 0;
+	return (result & 0x3f);
+}
+
+static struct net_device_stats *oeth_get_stats(struct net_device *dev)
+{
+        struct oeth_private *cep = (struct oeth_private *)dev->priv;
+ 
+        return &cep->stats;
+}
+
+static void oeth_set_multicast_list(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	struct	dev_mc_list *dmi;
+	volatile oeth_regs *regs;
+	int	i;
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get pointer of controller registers.
+	 */
+	regs = (oeth_regs *)dev->base_addr;
+
+	if (dev->flags & IFF_PROMISC) {
+	  
+		/* Log any net taps. 
+		 */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		OETH_REGORIN(regs->moder , OETH_MODER_PRO);
+		//regs->moder |= OETH_MODER_PRO;
+	} else {
+
+		OETH_REGANDIN(regs->moder , ~OETH_MODER_PRO);
+		//regs->moder &= ~OETH_MODER_PRO;
+
+		if (dev->flags & IFF_ALLMULTI) {
+
+			/* Catch all multicast addresses, so set the
+			 * filter to all 1's.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0xffffffff);
+			OETH_REGSAVE(regs->hash_addr1 , 0xffffffff);
+			//regs->hash_addr0 = 0xffffffff;
+			//regs->hash_addr1 = 0xffffffff;
+		}
+		else if (dev->mc_count) {
+
+                        OETH_REGORIN(regs->moder , OETH_MODER_IAM);
+                        //regs->moder |= OETH_MODER_IAM;
+                        
+			/* Clear filter and add the addresses in the list.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			//regs->hash_addr0 = 0x00000000;
+			//regs->hash_addr0 = 0x00000000;
+
+			dmi = dev->mc_list;
+
+			for (i = 0; i < dev->mc_count; i++) {
+				
+				int hash_b;
+
+				/* Only support group multicast for now.
+				 */
+				if (!(dmi->dmi_addr[0] & 1))
+					continue;
+
+				hash_b = calc_crc(dmi->dmi_addr); 
+				if(hash_b >= 32)
+					OETH_REGORIN(regs->hash_addr1 , 1 << (hash_b - 32));
+				        //regs->hash_addr1 |= 1 << (hash_b - 32);
+				else
+					OETH_REGORIN(regs->hash_addr0 , 1 << hash_b);
+				        //regs->hash_addr0 |= 1 << hash_b;
+			}
+		}
+	}
+}
+
+static int oeth_set_mac_address(struct net_device *dev,void *p)
+{
+	struct sockaddr *addr=p;
+	volatile oeth_regs *regs;
+      
+	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+      
+	regs = (oeth_regs *)dev->base_addr;
+      
+    
+	    
+// old version: sa_data is of type char, will be expanded to int when ored
+// so negative values e.g 0xB5 will be expanded to 0xffffffB5 and ored
+/*
+	regs->mac_addr1 = 	addr->sa_data[0] << 8 	|
+            			addr->sa_data[1];
+        regs->mac_addr0 = 	addr->sa_data[2] << 24 	|
+            			addr->sa_data[3] << 16 	|
+            			addr->sa_data[4] << 8 	|
+            			addr->sa_data[5];
+
+*/
+
+// dev_addr is of type unsigned char and will be expanded to unsigned int which is ok
+	OETH_REGSAVE(regs->mac_addr1 , 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1]);
+        OETH_REGSAVE(regs->mac_addr0 , 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5]);
+
+	/*	    
+	regs->mac_addr1 = 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1];
+        regs->mac_addr0 = 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5];
+	*/  
+	    
+	    
+	return 0;
+}
+
+/* Initialize the Open Ethernet MAC.
+ */
+int do_oeth_probe(struct net_device *dev)
+{
+	struct oeth_private *cep;
+	volatile oeth_regs *regs;
+	volatile oeth_bd *tx_bd, *rx_bd;
+	int i, j, k, l;
+#ifdef SRAM_BUFF
+	unsigned long mem_addr = SRAM_BUFF_BASE;
+#else
+	unsigned long mem_addr;
+#endif
+	unsigned long base;
+
+	amba_ahb_device adev[1];
+	l = amba_get_free_ahbslv_devices (VENDOR_GAISLER, GAISLER_ETHAHB, adev, 1);
+	if (l == 0) {
+	  return 1;
+	}
+	
+	base = adev[0].start[0];
+
+	//printk("Probing Open Ethernet Core at 0x%x (irq:%i,n:%s)\n",adev[0].start[0], adev[0].irq, dev ->name);
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Allocate a new 'dev' if needed. 
+	 */
+	if (dev == NULL) {
+		/*
+		 * Don't allocate the private data here, it is done later
+		 * This makes it easier to free the memory when this driver
+		 * is used as a module.
+		 */
+//		dev = init_etherdev(0, 0);
+                dev=alloc_etherdev(0);		
+//		dev = alloc_netdev(0, "eth0", setup_ether);
+		if (dev == NULL)
+			return -ENOMEM;
+	}
+
+
+
+
+	/* Initialize the device structure. 
+	 */
+	if (dev->priv == NULL) {
+		cep = (struct oeth_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+		dev->priv = cep;
+		if (dev->priv == NULL)
+			return -ENOMEM;
+	}
+	
+	__clear_user(cep,sizeof(*cep));
+
+	/* Get pointer ethernet controller configuration registers.
+	 */
+	cep->regs = (oeth_regs *)(OETH_REG_BASE(base));
+	regs = (oeth_regs *)(OETH_REG_BASE(base));
+	cep->irq = adev[0].irq;
+
+	/* Reset the controller.
+	 */
+	OETH_REGSAVE(regs->moder , OETH_MODER_RST);	/* Reset ON */
+	OETH_REGANDIN(regs->moder , ~OETH_MODER_RST);	/* Reset OFF */
+	//regs->moder = OETH_MODER_RST;	/* Reset ON */
+	//regs->moder &= ~OETH_MODER_RST;	/* Reset OFF */
+
+	/* Setting TXBD base to OETH_TXBD_NUM.
+	 */
+	OETH_REGSAVE(regs->tx_bd_num , OETH_TXBD_NUM);
+	//regs->tx_bd_num = OETH_TXBD_NUM;
+	
+	/* Initialize TXBD pointer
+	 */
+	cep->tx_bd_base = (oeth_bd *)OETH_BD_BASE(base);
+	tx_bd = (volatile oeth_bd *)OETH_BD_BASE(base);
+
+	/* Initialize RXBD pointer
+	 */
+	cep->rx_bd_base = ((oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+	rx_bd = ((volatile oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+
+	/* Initialize transmit pointers.
+	 */
+	cep->rx_cur = 0;
+	cep->tx_next = 0;
+	cep->tx_last = 0;
+	cep->tx_full = 0;
+
+	/* Set min/max packet length 
+	 */
+	OETH_REGSAVE(regs->packet_len , 0x00400600);
+	//regs->packet_len = 0x00400600;
+
+	/* Set IPGT register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgt , 0x00000012);
+	//regs->ipgt = 0x00000012;
+
+	/* Set IPGR1 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr1 , 0x0000000c);
+	//regs->ipgr1 = 0x0000000c;
+
+	/* Set IPGR2 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr2 , 0x00000012);
+	//regs->ipgr2 = 0x00000012;
+
+	/* Set COLLCONF register to recomended value 
+	 */
+	OETH_REGSAVE(regs->collconf , 0x000f003f);
+	//regs->collconf = 0x000f003f;
+
+	/* Set control module mode 
+	 */
+#if 0
+	OETH_REGSAVE(regs->ctrlmoder , OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW);
+	//regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW;
+#else
+	OETH_REGSAVE(regs->ctrlmoder , 0);
+	//regs->ctrlmoder = 0;
+#endif
+
+  /* Set PHY to show Tx status, Rx status and Link status */
+  /*regs->miiaddress = 20<<8;
+  regs->miitx_data = 0x1422;
+  regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;*/
+ 
+  // switch to 10 mbit ethernet
+  OETH_REGSAVE(regs->miiaddress , 0);
+  OETH_REGSAVE(regs->miitx_data , 0);
+  OETH_REGSAVE(regs->miicommand , OETH_MIICOMMAND_WCTRLDATA);
+  //regs->miiaddress = 0;
+  //regs->miitx_data = 0;
+  //regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
+  
+#ifdef TXBUFF_PREALLOC
+
+	/* Initialize TXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(tx_bd[k].len_status , OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(tx_bd[k].addr , __pa(mem_addr));
+			//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+			//tx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_TX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#else
+
+ 	/* Initialize TXBDs.
+	 */
+	for(i = 0; i < OETH_TXBD_NUM; i++) {
+
+		cep->tx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(tx_bd[i].len_status , (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+		OETH_REGSAVE(tx_bd[i].addr , 0);
+		//tx_bd[i].len_status = (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+		//tx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#endif
+
+#ifdef RXBUFF_PREALLOC
+
+	/* Initialize RXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(rx_bd[k].len_status , OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(rx_bd[k].addr , __pa(mem_addr));
+			//rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+			//rx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_RX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#else
+	/* Initialize RXBDs.
+	 */
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+
+		OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		//rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(rx_bd[i].addr , 0);
+		//rx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#endif
+	
+	/* Set default ethernet station address.
+	 */
+	dev->dev_addr[0] = MACADDR0;
+	dev->dev_addr[1] = MACADDR1;
+	dev->dev_addr[2] = MACADDR2;
+	dev->dev_addr[3] = MACADDR3;
+	dev->dev_addr[4] = MACADDR4;
+	dev->dev_addr[5] = MACADDR5;
+
+	OETH_REGSAVE(regs->mac_addr1 , MACADDR0 << 8 | MACADDR1);
+	OETH_REGSAVE(regs->mac_addr0 , MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5);
+	//regs->mac_addr1 = MACADDR0 << 8 | MACADDR1;
+	//regs->mac_addr0 = MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5;
+	
+	/* Clear all pending interrupts 
+	 */
+	OETH_REGSAVE(regs->int_src , 0xffffffff);
+	//regs->int_src = 0xffffffff;
+
+	/* Promisc, IFG, CRCEn
+	 */
+	OETH_REGORIN(regs->moder , OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN);
+	//regs->moder |= OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN;
+
+	/* Enable interrupt sources.
+	 */
+	OETH_REGSAVE(regs->int_mask , OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC);
+	/*	regs->int_mask = OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC;
+	*/
+	/* Fill in the fields of the device structure with ethernet values. 
+	 */
+	ether_setup(dev);
+
+	dev->base_addr = (unsigned long)OETH_REG_BASE(base);
+
+	/* The Open Ethernet specific entries in the device structure. 
+	 */
+	dev->open = oeth_open;
+	dev->hard_start_xmit = oeth_start_xmit;
+	dev->stop = oeth_close;
+	dev->get_stats = oeth_get_stats;
+	dev->set_multicast_list = oeth_set_multicast_list;
+	dev->set_mac_address = oeth_set_mac_address;
+
+	if (register_netdev(dev)) {
+	  kfree(dev->priv);
+	  printk(KERN_ERR "open_eth: netdevice registration failed.\n");
+	  return -ENOMEM;
+        }
+
+	printk("%s: Open Ethernet Core Version 1.0 at [0x%x] irq %i\n", dev->name,(unsigned int)(cep->regs),(unsigned int)(cep->irq));
+
+	return 0;
+}
+	
+struct net_device *grlib_oeth_probe(int unit) {
+  
+  struct net_device *dev = alloc_etherdev(0);
+  int err;
+  
+  if (!dev)
+    return ERR_PTR(-ENOMEM);
+  if (unit >= 0)
+    sprintf(dev->name, "eth%d", unit);
+  SET_MODULE_OWNER(dev);
+  err = do_oeth_probe(dev);
+  if (err) {
+    free_netdev(dev);
+    return ERR_PTR(err);
+  }
+  return dev;
+
+  //      printk("Init: Open Ethernet probe\n");
+  //    oeth_dev=alloc_etherdev(sizeof(struct oeth_private));
+  //    return do_oeth_probe(oeth_dev);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef MODULE
+static struct net_device		*oeth_dev;		/* netdevice struct */
+
+int
+init_module(void)
+{
+  oeth_dev = grlib_oeth_probe(-1);
+  if (IS_ERR(oeth_dev)) {
+    printk(KERN_WARNING "Grlib Oeth: No core found\n");
+    return PTR_ERR(oeth_dev);
+  }
+  return 0;
+}
+
+void cleanup_module(void) {
+	
+  printk("Open Ethernet Core cleanup\n");
+  if (oeth_dev) {
+    unregister_netdev(oeth_dev);
+    kfree(oeth_dev);
+  }
+}
+
+//module_init(grlib_oeth_probe);
+//module_exit(oeth_cleanup);
+MODULE_LICENSE("GPL");
+
+#endif
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,143 @@
+/* Ethernet configuration registers */
+typedef struct _oeth_regs {
+        uint    moder;          /* Mode Register */
+        uint    int_src;        /* Interrupt Source Register */
+        uint    int_mask;       /* Interrupt Mask Register */
+        uint    ipgt;           /* Back to Bak Inter Packet Gap Register */
+        uint    ipgr1;          /* Non Back to Back Inter Packet Gap Register 1 */
+        uint    ipgr2;          /* Non Back to Back Inter Packet Gap Register 2 */
+        uint    packet_len;     /* Packet Length Register (min. and max.) */
+        uint    collconf;       /* Collision and Retry Configuration Register */
+        uint    tx_bd_num;      /* Transmit Buffer Descriptor Number Register */
+        uint    ctrlmoder;      /* Control Module Mode Register */
+        uint    miimoder;       /* MII Mode Register */
+        uint    miicommand;     /* MII Command Register */
+        uint    miiaddress;     /* MII Address Register */
+        uint    miitx_data;     /* MII Transmit Data Register */
+        uint    miirx_data;     /* MII Receive Data Register */
+        uint    miistatus;      /* MII Status Register */
+        uint    mac_addr0;      /* MAC Individual Address Register 0 */
+        uint    mac_addr1;      /* MAC Individual Address Register 1 */
+        uint    hash_addr0;     /* Hash Register 0 */
+        uint    hash_addr1;     /* Hash Register 1 */                           
+} oeth_regs;
+
+/* Ethernet buffer descriptor */
+typedef struct _oeth_bd {
+#if 0
+        ushort  len;            /* Buffer length */
+        ushort  status;         /* Buffer status */
+#else
+        uint    len_status;
+#endif
+        uint    addr;           /* Buffer address */
+} oeth_bd;
+
+#define OETH_REG_BASE(b)        (b)
+#define OETH_BD_BASE(b)         ((b) + 0x400)
+#define OETH_TOTAL_BD           128
+#define OETH_MAXBUF_LEN         0x600
+                                
+/* Tx BD */                     
+#define OETH_TX_BD_READY        0x8000 /* Tx BD Ready */
+#define OETH_TX_BD_IRQ          0x4000 /* Tx BD IRQ Enable */
+#define OETH_TX_BD_WRAP         0x2000 /* Tx BD Wrap (last BD) */
+#define OETH_TX_BD_PAD          0x1000 /* Tx BD Pad Enable */
+#define OETH_TX_BD_CRC          0x0800 /* Tx BD CRC Enable */
+                                
+#define OETH_TX_BD_UNDERRUN     0x0100 /* Tx BD Underrun Status */
+#define OETH_TX_BD_RETRY        0x00F0 /* Tx BD Retry Status */
+#define OETH_TX_BD_RETLIM       0x0008 /* Tx BD Retransmission Limit Status */
+#define OETH_TX_BD_LATECOL      0x0004 /* Tx BD Late Collision Status */
+#define OETH_TX_BD_DEFER        0x0002 /* Tx BD Defer Status */
+#define OETH_TX_BD_CARRIER      0x0001 /* Tx BD Carrier Sense Lost Status */
+#define OETH_TX_BD_STATS        (OETH_TX_BD_UNDERRUN            | \
+                                OETH_TX_BD_RETRY                | \
+                                OETH_TX_BD_RETLIM               | \
+                                OETH_TX_BD_LATECOL              | \
+                                OETH_TX_BD_DEFER                | \
+                                OETH_TX_BD_CARRIER)
+                                
+/* Rx BD */                     
+#define OETH_RX_BD_EMPTY        0x8000 /* Rx BD Empty */
+#define OETH_RX_BD_IRQ          0x4000 /* Rx BD IRQ Enable */
+#define OETH_RX_BD_WRAP         0x2000 /* Rx BD Wrap (last BD) */
+                                
+#define OETH_RX_BD_MISS         0x0080 /* Rx BD Miss Status */
+#define OETH_RX_BD_OVERRUN      0x0040 /* Rx BD Overrun Status */
+#define OETH_RX_BD_INVSIMB      0x0020 /* Rx BD Invalid Symbol Status */
+#define OETH_RX_BD_DRIBBLE      0x0010 /* Rx BD Dribble Nibble Status */
+#define OETH_RX_BD_TOOLONG      0x0008 /* Rx BD Too Long Status */
+#define OETH_RX_BD_SHORT        0x0004 /* Rx BD Too Short Frame Status */
+#define OETH_RX_BD_CRCERR       0x0002 /* Rx BD CRC Error Status */
+#define OETH_RX_BD_LATECOL      0x0001 /* Rx BD Late Collision Status */
+#define OETH_RX_BD_STATS        (OETH_RX_BD_MISS                | \
+                                OETH_RX_BD_OVERRUN              | \
+                                OETH_RX_BD_INVSIMB              | \
+                                OETH_RX_BD_DRIBBLE              | \
+                                OETH_RX_BD_TOOLONG              | \
+                                OETH_RX_BD_SHORT                | \
+                                OETH_RX_BD_CRCERR               | \
+                                OETH_RX_BD_LATECOL)
+
+/* MODER Register */
+#define OETH_MODER_RXEN         0x00000001 /* Receive Enable  */
+#define OETH_MODER_TXEN         0x00000002 /* Transmit Enable */
+#define OETH_MODER_NOPRE        0x00000004 /* No Preamble  */
+#define OETH_MODER_BRO          0x00000008 /* Reject Broadcast */
+#define OETH_MODER_IAM          0x00000010 /* Use Individual Hash */
+#define OETH_MODER_PRO          0x00000020 /* Promiscuous (receive all) */
+#define OETH_MODER_IFG          0x00000040 /* Min. IFG not required */
+#define OETH_MODER_LOOPBCK      0x00000080 /* Loop Back */
+#define OETH_MODER_NOBCKOF      0x00000100 /* No Backoff */
+#define OETH_MODER_EXDFREN      0x00000200 /* Excess Defer */
+#define OETH_MODER_FULLD        0x00000400 /* Full Duplex */
+#define OETH_MODER_RST          0x00000800 /* Reset MAC */
+#define OETH_MODER_DLYCRCEN     0x00001000 /* Delayed CRC Enable */
+#define OETH_MODER_CRCEN        0x00002000 /* CRC Enable */
+#define OETH_MODER_HUGEN        0x00004000 /* Huge Enable */
+#define OETH_MODER_PAD          0x00008000 /* Pad Enable */
+#define OETH_MODER_RECSMALL     0x00010000 /* Receive Small */
+ 
+/* Interrupt Source Register */
+#define OETH_INT_TXB            0x00000001 /* Transmit Buffer IRQ */
+#define OETH_INT_TXE            0x00000002 /* Transmit Error IRQ */
+#define OETH_INT_RXF            0x00000004 /* Receive Frame IRQ */
+#define OETH_INT_RXE            0x00000008 /* Receive Error IRQ */
+#define OETH_INT_BUSY           0x00000010 /* Busy IRQ */
+#define OETH_INT_TXC            0x00000020 /* Transmit Control Frame IRQ */
+#define OETH_INT_RXC            0x00000040 /* Received Control Frame IRQ */
+
+/* Interrupt Mask Register */
+#define OETH_INT_MASK_TXB       0x00000001 /* Transmit Buffer IRQ Mask */
+#define OETH_INT_MASK_TXE       0x00000002 /* Transmit Error IRQ Mask */
+#define OETH_INT_MASK_RXF       0x00000004 /* Receive Frame IRQ Mask */
+#define OETH_INT_MASK_RXE       0x00000008 /* Receive Error IRQ Mask */
+#define OETH_INT_MASK_BUSY      0x00000010 /* Busy IRQ Mask */
+#define OETH_INT_MASK_TXC       0x00000020 /* Transmit Control Frame IRQ Mask */
+#define OETH_INT_MASK_RXC       0x00000040 /* Received Control Frame IRQ Mask */
+ 
+/* Control Module Mode Register */
+#define OETH_CTRLMODER_PASSALL  0x00000001 /* Pass Control Frames */
+#define OETH_CTRLMODER_RXFLOW   0x00000002 /* Receive Control Flow Enable */
+#define OETH_CTRLMODER_TXFLOW   0x00000004 /* Transmit Control Flow Enable */
+                               
+/* MII Mode Register */        
+#define OETH_MIIMODER_CLKDIV    0x000000FF /* Clock Divider */
+#define OETH_MIIMODER_NOPRE     0x00000100 /* No Preamble */
+#define OETH_MIIMODER_RST       0x00000200 /* MIIM Reset */
+ 
+/* MII Command Register */
+#define OETH_MIICOMMAND_SCANSTAT  0x00000001 /* Scan Status */
+#define OETH_MIICOMMAND_RSTAT     0x00000002 /* Read Status */
+#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */
+ 
+/* MII Address Register */
+#define OETH_MIIADDRESS_FIAD    0x0000001F /* PHY Address */
+#define OETH_MIIADDRESS_RGAD    0x00001F00 /* RGAD Address */
+ 
+/* MII Status Register */
+#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */
+#define OETH_MIISTATUS_BUSY     0x00000002 /* MII Busy */
+#define OETH_MIISTATUS_NVALID   0x00000004 /* Data in MII Status Register is invalid */
+

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [4/7] LEON SPARC V8 processor support for linux-2.6.10
@ 2005-01-04 19:04 ` Jiri Gaisler
  0 siblings, 0 replies; 4+ messages in thread
From: Jiri Gaisler @ 2005-01-04 19:04 UTC (permalink / raw)
  To: sparclinux; +Cc: linux-kernel, wli

[-- Attachment #1: Type: text/plain, Size: 95 bytes --]

Leon3 serial+ethermac driver:

[4/7] diff2.6.10_driver_amba.diff         diff for drivers/amba

[-- Attachment #2: diff2.6.10_driver_amba.diff --]
[-- Type: text/plain, Size: 73408 bytes --]

diff -Naur ../linux-2.6.10/drivers/Makefile linux-2.6.10/drivers/Makefile
--- ../linux-2.6.10/drivers/Makefile	2004-12-24 22:36:00.000000000 +0100
+++ linux-2.6.10/drivers/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -60,3 +60,4 @@
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-y				+= firmware/
+obj-$(CONFIG_LEON_3)            += amba/
diff -Naur ../linux-2.6.10/drivers/amba/Kconfig linux-2.6.10/drivers/amba/Kconfig
--- ../linux-2.6.10/drivers/amba/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Kconfig	2005-01-03 17:10:41.000000000 +0100
@@ -0,0 +1,12 @@
+
+#------------------------------------------------------------------------------
+# Amba device driver configuration
+#------------------------------------------------------------------------------
+
+menu "Grlib: Amba device driver configuration"
+
+source "drivers/amba/gaisler/Kconfig"
+source "drivers/amba/opencores/Kconfig"
+
+endmenu
+
diff -Naur ../linux-2.6.10/drivers/amba/Makefile linux-2.6.10/drivers/amba/Makefile
--- ../linux-2.6.10/drivers/amba/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,7 @@
+#
+# Makefile for the PCI bus specific drivers.
+#
+
+obj-y		+= amba.o amba_driver.o
+
+obj-y           += gaisler/ opencores/
diff -Naur ../linux-2.6.10/drivers/amba/amba.c linux-2.6.10/drivers/amba/amba.c
--- ../linux-2.6.10/drivers/amba/amba.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,181 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+amba_confarea_type amba_conf;
+
+/* Pointers to Interrupt Controller configuration registers */
+volatile LEON3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs = 0;
+volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs = 0;
+unsigned long LEON3_GpTimer_Irq = 0;
+
+static void vendor_dev_string(unsigned long conf, char *vendorbuf,char *devbuf) {
+  int vendor = amba_vendor(conf); int dev = amba_device(conf);
+  char *devstr; char *vendorstr; 
+  sprintf(vendorbuf, "Unknown vendor %2x",vendor);
+  sprintf(devbuf, "Unknown device %2x",dev);
+  vendorstr = vendor_id2str(vendor);
+  if (vendorstr) {
+    sprintf(vendorbuf, "%s",vendorstr);
+  } 
+  devstr = device_id2str(vendor,dev);
+  if (devstr) {
+    sprintf(devbuf, "%s",devstr);
+  }
+}
+
+void amba_prinf_config(void)  
+{
+  char devbuf[128]; char vendorbuf[128]; unsigned int conf;
+  int i = 0; int j = 0; 
+  unsigned int addr; unsigned int m;
+  printk("             Vendors         Slaves\n");
+  printk("Ahb masters:\n");
+  i = 0;
+  while (i < amba_conf.ahbmst.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbmst, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbmst,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+        printk(" +%i: 0x%x \n", j, addr);
+      }
+    }
+    i++;
+  }
+  printk("Ahb slaves:\n");
+  i = 0;
+  while (i < amba_conf.ahbslv.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbslv,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+	if (amba_membar_type(m) == AMBA_TYPE_AHBIO) {
+	  addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	} else if (amba_membar_type(m) == AMBA_TYPE_APBIO) {
+	  printk("Warning: apbio membar\n");
+	}
+	printk(" +%i: 0x%x (raw:0x%x)\n", j, addr, m);
+      }
+    }
+    i++;
+  }
+  printk("Apb slaves:\n");
+  i = 0;
+  while (i < amba_conf.apbslv.devnr) 
+  {
+    
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    
+    m = amba_apb_get_membar(amba_conf.apbslv, i);
+    addr = amba_iobar_start(amba_conf.apbmst, m);
+    printk(" +%2i: 0x%x (raw:0x%x) \n", 0, addr, m);
+    
+    i++;
+    
+  }
+  
+}
+
+#define amba_insert_device(tab, address) \
+{ \
+  if (LEON3_BYPASS_LOAD_PA(address)) \
+  { \
+    (tab)->addr[(tab)->devnr] = (address); \
+    (tab)->devnr ++; \
+  } \
+} while(0)
+
+/*
+ *  Used to scan system bus. Probes for AHB masters, AHB slaves and 
+ *  APB slaves. Addresses to configuration areas of the AHB masters,
+ *  AHB slaves, APB slaves and APB master are storeds in 
+ *  amba_ahb_masters, amba_ahb_slaves and amba.
+ */
+
+void amba_init(void) 
+{
+  unsigned int *cfg_area;  /* address to configuration area */
+  unsigned int mbar, conf;
+  int i, j;
+  
+#ifdef DEBUG_CONFIG
+  printk("Reading AMBA Plug&Play configuration area\n");
+#endif
+
+  memset(&amba_conf,0,sizeof(amba_conf));
+  //amba_conf.ahbmst.devnr = 0; amba_conf.ahbslv.devnr = 0; amba_conf.apbslv.devnr = 0;
+  
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA);
+
+  for (i = 0; i < LEON3_AHB_MASTERS; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbmst, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }
+
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA | LEON3_AHB_SLAVE_CONF_AREA);
+  for (i = 0; i < LEON3_AHB_SLAVES; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbslv, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }  
+
+  for (i = 0; i < amba_conf.ahbslv.devnr; i ++) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    mbar = amba_ahb_get_membar(amba_conf.ahbslv, i, 0);
+    if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_APBMST))
+    {
+      amba_conf.apbmst = amba_membar_start(mbar);
+      cfg_area = (unsigned int *) (amba_conf.apbmst | LEON3_CONF_AREA);
+      
+      printk("Found apbmst, cfg: 0x%x\n",(unsigned int)cfg_area);
+      
+      for (j = amba_conf.apbslv.devnr; j < LEON3_APB_SLAVES; j++)
+      {
+	amba_insert_device(&amba_conf.apbslv, cfg_area);
+	cfg_area += LEON3_APB_CONF_WORDS;
+      }
+    }
+  }    
+ 
+  /* Find LEON3 Interrupt controler */
+  LEON3_IrqCtrl_Regs = (volatile LEON3_IrqCtrl_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_IRQMP, 0);
+  LEON3_GpTimer_Regs = (volatile LEON3_GpTimer_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_GPTIMER, &LEON3_GpTimer_Irq);
+  if (LEON3_IrqCtrl_Regs) {
+    LEON3_BYPASS_STORE_PA(&(LEON3_IrqCtrl_Regs ->mask[0]),0);
+  }
+}
+
+unsigned long amba_find_apbslv_addr(unsigned long vendor, unsigned long device, unsigned long *irq) {
+  unsigned int i,conf,iobar;
+  for (i = 0; i < amba_conf.apbslv.devnr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device))
+    {
+      if (irq) {
+        *irq = amba_irq(conf);
+      }
+      iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+      return amba_iobar_start(amba_conf.apbmst, iobar);
+    }
+  }
+  return 0;
+}
diff -Naur ../linux-2.6.10/drivers/amba/amba_driver.c linux-2.6.10/drivers/amba/amba_driver.c
--- ../linux-2.6.10/drivers/amba/amba_driver.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba_driver.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,78 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+extern amba_confarea_type amba_conf;
+ 
+//collect apb slaves
+int amba_get_free_apbslv_devices (int vendor, int device, amba_apb_device *dev,int nr) {
+  unsigned int i,conf,iobar,j = 0;
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: search for apdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.apbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.apbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Apbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.apbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+        iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+        dev[j].start = amba_iobar_start(amba_conf.apbmst, iobar);
+#ifdef DEBUG_CONFIG
+	printk(" +bar: 0x%x \n", k, dev[j].start);
+#endif
+        j++;
+      }
+    }
+  }
+  return j;
+}
+
+//collect ahb slaves
+int amba_get_free_ahbslv_devices (int vendor, int device, amba_ahb_device *dev,int nr) {
+  unsigned int addr, i,conf,iobar,j = 0,k;
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: search for ahdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.ahbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.ahbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Ahbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.ahbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+	for (k = 0; k < 4; k ++) {
+	  iobar = amba_ahb_get_membar(amba_conf.ahbslv, i, k);
+	  addr = amba_membar_start(iobar);
+	  if (amba_membar_type(iobar) == AMBA_TYPE_AHBIO) {
+	    addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	  }
+	  dev[j].start[k] = addr;
+#ifdef DEBUG_CONFIG
+	  printk(" +%i: 0x%x \n", k, dev[j].start[k]);
+#endif
+	}
+        j++;
+      }
+    }
+  }
+  return j;
+}
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Kconfig linux-2.6.10/drivers/amba/gaisler/Kconfig
--- ../linux-2.6.10/drivers/amba/gaisler/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,12 @@
+
+menu "Vendor Gaisler"
+
+config GRLIB_GAISLER_APBUART
+	bool "Grlib apbuart driver" 
+	default y
+	---help---
+	  Add the driver for the grlib apbuart serial core.
+
+endmenu
+
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Makefile linux-2.6.10/drivers/amba/gaisler/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_GAISLER_APBUART)		+= apbuart/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= apbuart.o
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,729 @@
+/*
+ *  linux/drivers/serial/leon.c
+ *
+ *  Driver for Leon serial ports
+ *
+ *  Based on linux/drivers/serial/amba.c , Documentation/serial/driver
+ * 
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ * 
+ *  Modified for Leon by Konrad Eisele <eiselekd@web.de>, 2003
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+
+#if defined(CONFIG_SERIAL_LEON_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <asm/leon.h>
+
+#define UART_NR		8
+int leon_ports_nr = 0;
+
+#define SERIAL_LEON_MAJOR	TTY_MAJOR
+#define SERIAL_LEON_MINOR	64
+#define SERIAL_LEON_NR		UART_NR
+
+#define AMBA_ISR_PASS_LIMIT	256
+
+#define APBBASE(port) ((LEON3_APBUART_Regs_Map *)((port)->membase))
+
+#define APBBASE_DATA_P(port) (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port)	(LEON_BYPASS_LOAD_PA(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v)	(LEON_BYPASS_STORE_PA(APBBASE_DATA_P(port),v))
+#define UART_GET_STATUS(port)	(LEON_BYPASS_LOAD_PA(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port,v)	(LEON_BYPASS_STORE_PA(APBBASE_STATUS_P(port),v))
+#define UART_GET_CTRL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_CTRL_P(port),v))
+#define UART_GET_SCAL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_SCALAR_P(port),v))
+#define UART_RX_DATA(s)       (((s) & LEON_REG_UART_STATUS_DR) != 0)
+#define UART_TX_READY(s)	(((s) & LEON_REG_UART_STATUS_THE) != 0)
+
+#define UART_DUMMY_RSR_RX	0x8000 /* for ignore all read */
+
+/* We wrap our port structure around the generic uart_port */
+struct uart_leon_port {
+	struct uart_port	port;
+	unsigned int		old_status;
+};
+
+static void leonuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port);
+static void leonuart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr |= LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+	
+	if (UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars (port);
+	}
+}
+
+static void leonuart_stop_rx(struct uart_port *port)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~(LEON_REG_UART_CTRL_RI);
+	UART_PUT_CTRL(port, cr);
+}
+
+static void leonuart_enable_ms(struct uart_port *port)
+{
+	/* no modem status for leon */
+}
+
+//static 
+void
+#ifdef SUPPORT_SYSRQ
+leonuart_rx_chars(struct uart_port *port, struct pt_regs *regs)
+#else
+leonuart_rx_chars(struct uart_port *port)
+#endif
+{
+	struct tty_struct *tty = port->info->tty;
+	unsigned int status, ch, rsr;
+
+	status = UART_GET_STATUS(port); 
+	if (UART_RX_DATA(status)) {
+      
+            if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.work.func((void *)tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+				return;
+			}
+		}
+
+		ch = UART_GET_CHAR(port); 
+
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = TTY_NORMAL;
+		port->icount.rx++;
+
+		/*
+		 * Note that the error handling code is
+		 * out of the main execution path
+		 */
+		rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX; 
+		UART_PUT_STATUS(port,0);
+		if (rsr & LEON_REG_UART_STATUS_ERR) { 
+
+		  if (rsr & LEON_REG_UART_STATUS_BR) {
+		    rsr &= ~(LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE);
+		    port->icount.brk++;
+		    if (uart_handle_break(port))
+		      goto ignore_char;
+		  } else if (rsr & LEON_REG_UART_STATUS_PE) {
+		    port->icount.parity++;
+		  } else if (rsr & LEON_REG_UART_STATUS_FE) {
+		    port->icount.frame++;
+		  }
+		  if (rsr & LEON_REG_UART_STATUS_OE)
+		    port->icount.overrun++;
+                  
+		  rsr &= port->read_status_mask;
+		  
+		  if (rsr & LEON_REG_UART_STATUS_PE)
+		    *tty->flip.flag_buf_ptr = TTY_PARITY;
+                  else if (rsr & LEON_REG_UART_STATUS_FE)
+		    *tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+            
+		if (uart_handle_sysrq_char(port, ch, regs))
+		    goto ignore_char;
+		
+		if ((rsr & port->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((rsr & LEON_REG_UART_STATUS_OE) &&
+		    tty->flip.count < TTY_FLIPBUF_SIZE) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.char_buf_ptr++ = 0;
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+			tty->flip.count++;
+		}
+	}
+ignore_char:
+	tty_flip_buffer_push(tty);
+	return;
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	int count;
+
+	if (port->x_char) {
+		UART_PUT_CHAR(port, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		leonuart_stop_tx(port, 0);
+		return;
+	}
+
+	count = port->fifosize >> 1; //amba: fill FIFO
+	do {
+		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		leonuart_stop_tx(port, 0);
+}
+
+//static 
+irqreturn_t leonuart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	unsigned int status;
+
+	spin_lock(port ->lock);
+
+	status = UART_GET_STATUS(port);
+	if (status & LEON_REG_UART_STATUS_DR) {
+#ifdef SUPPORT_SYSRQ
+	  leonuart_rx_chars(port,regs);
+#else
+	  leonuart_rx_chars(port);
+#endif          
+	}
+	if (status & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars(port);
+	}
+	spin_unlock(port ->lock);
+	return IRQ_HANDLED;
+}
+
+static unsigned int leonuart_tx_empty(struct uart_port *port)
+{
+	return UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int leonuart_get_mctrl(struct uart_port *port)
+{
+	unsigned int result = 0;
+
+	/*
+	  no modem status for leon
+	*/
+
+	return result;
+}
+
+static void leonuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* no modem status for leon */
+}
+
+static void leonuart_break_ctl(struct uart_port *port, int break_state)
+{
+	/* no break for leon */
+}
+
+static int leonuart_startup(struct uart_port *port)
+{
+	struct uart_leon_port *uap = (struct uart_leon_port *)port;
+	int retval;
+	unsigned int cr;
+
+	/*
+	 * Allocate the IRQ
+	 */
+	retval = request_irq(port->irq, leonuart_int, 0, "leon", port);
+	if (retval)
+		return retval;
+
+	/*
+	 * initialise the old status of the modem signals
+	 */
+	uap->old_status = 0;
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr | LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI );	
+      
+	return 0;
+}
+
+static void leonuart_shutdown(struct uart_port *port)
+{
+	unsigned int cr;
+
+	/*
+	 * Free the interrupt
+	 */
+	free_irq(port->irq, port);
+
+	/*
+	 * disable all interrupts, disable the port
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr & ~( LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI ));	
+      
+}
+
+static void
+leonuart_set_termios(struct uart_port *port, struct termios *termios,
+		     struct termios *old)
+{
+	unsigned int cr;
+	unsigned long flags;
+	unsigned int baud, quot;
+
+	/*
+	 * Ask the core to calculate the divisor for us.
+	 */
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	if (baud == 0) {
+	  panic("invalid baudrate %i\n", port->uartclk/16);
+	}
+	quot = (uart_get_divisor(port, baud)) * 2; //uart_get_divisor calc a *16 uart freq, leon is *8
+	cr = UART_GET_CTRL(port);
+	cr &= ~( LEON_REG_UART_CTRL_PE | LEON_REG_UART_CTRL_PS );
+	  
+	if (termios->c_cflag & PARENB) { 
+		cr |= LEON_REG_UART_CTRL_PE; 
+		if ((termios->c_cflag & PARODD))
+			cr |= LEON_REG_UART_CTRL_PS;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/*
+	 * Update the per-port timeout.
+	 */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	port->read_status_mask = LEON_REG_UART_STATUS_OE;
+	if (termios->c_iflag & INPCK) 
+		port->read_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE ;
+
+	/*
+	 * Characters to ignore
+	 */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_OE | LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/* Set baud rate */
+	quot -= 1;
+	UART_PUT_SCAL(port, quot);
+	UART_PUT_CTRL(port, cr);
+      
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *leonuart_type(struct uart_port *port)
+{
+	return port->type == PORT_LEON ? "Leon" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void leonuart_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int leonuart_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void leonuart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_LEON;
+		leonuart_request_port(port);
+	}
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int leonuart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_LEON)
+		ret = -EINVAL;
+	if (ser->irq < 0 || ser->irq >= NR_IRQS)
+		ret = -EINVAL;
+	if (ser->baud_base < 9600)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops leon_pops = {
+	.tx_empty	= leonuart_tx_empty,
+	.set_mctrl	= leonuart_set_mctrl,
+	.get_mctrl	= leonuart_get_mctrl,
+	.stop_tx	= leonuart_stop_tx,
+	.start_tx	= leonuart_start_tx,
+	.stop_rx	= leonuart_stop_rx,
+	.enable_ms	= leonuart_enable_ms,
+	.break_ctl	= leonuart_break_ctl,
+	.startup	= leonuart_startup,
+	.shutdown	= leonuart_shutdown,
+	.set_termios	= leonuart_set_termios,
+	.type		= leonuart_type,
+	.release_port	= leonuart_release_port,
+	.request_port	= leonuart_request_port,
+	.config_port	= leonuart_config_port,
+	.verify_port	= leonuart_verify_port,
+};
+
+static struct uart_leon_port leon_ports[UART_NR];
+/* = {
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART0),
+			.mapbase	= (LEON_PREGS+LEON_UART0),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_0_RX_TX,
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+	},
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART1),
+			.mapbase	= (LEON_PREGS+LEON_UART1),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_1_RX_TX, 
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+	}
+};*/
+
+extern volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs;
+
+/* rs_init inits the driver */
+static int _apbuart_init_bases_done = 0;
+static void __init 
+_apbuart_init_bases(void)
+{
+  int  i; 
+  amba_apb_device dev[8];
+  if (!_apbuart_init_bases_done ) {
+    unsigned long clk = ((unsigned long)(((LEON3_BYPASS_LOAD_PA(&LEON3_GpTimer_Regs->scalar_reload)) + 1))); 
+    printk("Attaching grlib apbuart serial drivers (clk:%ihz):\n",(int)clk);
+    leon_ports_nr = amba_get_free_apbslv_devices (VENDOR_GAISLER, GAISLER_APBUART, dev, 8);
+
+    for (i = 0;i < leon_ports_nr;i++) {
+      leon_ports[i].port.membase = (void *)dev[i].start;
+      leon_ports[i].port.mapbase = dev[i].start;
+      leon_ports[i].port.irq = dev[i].irq;
+      leon_ports[i].port.iotype = SERIAL_IO_MEM;
+      leon_ports[i].port.uartclk = clk * 1000 * 1000;
+      leon_ports[i].port.fifosize = 1;
+      leon_ports[i].port.ops	= &leon_pops;
+      leon_ports[i].port.flags = ASYNC_BOOT_AUTOCONF;
+      leon_ports[i].port.line =i;
+    }
+    _apbuart_init_bases_done = 1;
+  }
+}
+
+
+#ifdef CONFIG_SERIAL_LEON_CONSOLE
+
+static void
+leonuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_port *port = &leon_ports[co->index].port;
+	unsigned int status, old_cr;
+	int i;
+
+	/*
+	 *	First save the CR then disable the interrupts
+	 */
+	old_cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, (old_cr & ~(LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI)) | (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE) ); 
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++) {
+		do {
+			status = UART_GET_STATUS(port);
+		} while (!UART_TX_READY(status));
+		UART_PUT_CHAR(port, s[i]);
+		if (s[i] == '\n') {
+			do {
+				status = UART_GET_STATUS(port);
+			} while (!UART_TX_READY(status));
+			UART_PUT_CHAR(port, '\r');
+		}
+	}
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore the TCR
+	 */
+	do {
+		status = UART_GET_STATUS(port);
+	} while (!UART_TX_READY(status));
+	UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+leonuart_console_get_options(struct uart_port *port, int *baud,
+			     int *parity, int *bits)
+{
+      if (UART_GET_CTRL(port) & (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE)) {
+	
+		unsigned int quot, status;
+		status = UART_GET_STATUS(port);
+
+		*parity = 'n';
+		if (status & LEON_REG_UART_CTRL_PE) {
+			if ((status & LEON_REG_UART_CTRL_PS) == 0 )
+				*parity = 'e';
+			else
+				*parity = 'o';
+		}
+            
+		*bits = 8;
+            quot = UART_GET_SCAL(port) / 8;
+		*baud = port->uartclk / (16 * (quot + 1));
+	}
+}
+
+static int __init leonuart_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 38400;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	/*
+	 * Check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	if (co->index >= leon_ports_nr)
+		co->index = 0;
+	port = &leon_ports[co->index].port;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		leonuart_console_get_options(port, &baud, &parity, &bits);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+static struct uart_driver leon_reg;
+static struct console leon_console = {
+	.name		= "ttyS",
+	.write		= leonuart_console_write,
+	.device		= uart_console_device,
+	.setup		= leonuart_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &leon_reg,
+};
+
+//static int leonuart_init(void);
+static int __init leonuart_console_init(void)
+{
+	_apbuart_init_bases();
+	register_console(&leon_console);
+	return 0;
+}
+console_initcall(leonuart_console_init);
+
+#define LEON_CONSOLE	&leon_console
+#else
+#define LEON_CONSOLE	NULL
+#endif
+
+static struct uart_driver leon_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "serial",
+	.devfs_name	= "tts/",
+	.dev_name	= "ttyS",
+	.major		= SERIAL_LEON_MAJOR,
+	.minor		= SERIAL_LEON_MINOR,
+	.nr		= UART_NR,
+	.cons		= LEON_CONSOLE,
+};
+
+
+static int __init gaisler_apbuart_init(void)
+{
+	int ret;
+	int i;
+	int node;
+	int freq_khz;
+	int baud_rates[UART_NR];
+
+	_apbuart_init_bases();
+	node = prom_getchild(prom_root_node);
+	freq_khz = prom_getint(node, "frequency");
+	
+	printk(KERN_INFO "grlib apbuart: %i serial driver(s) at [",leon_ports_nr);
+	for (i = 0; i < leon_ports_nr; i++) {
+	  baud_rates[i] = prom_getintdefault(node, "uart1_baud", 9600);
+	  if (i != 0) {printk(",");}
+	  printk("0x%x",(unsigned int) leon_ports[i].port.mapbase);
+	  printk("(irq %i)",leon_ports[i].port.irq);
+	}
+	printk("]\n");
+
+	baud_rates[0] = prom_getintdefault(node, "uart1_baud", 9600);
+	baud_rates[1] = prom_getintdefault(node, "uart2_baud", 9600);
+
+	printk(KERN_INFO "grlib apbuart: system frequency: %i khz, baud rates: %i %i\n", freq_khz, baud_rates[0], baud_rates[1]);
+
+	ret = uart_register_driver(&leon_reg);
+	leon_reg.tty_driver->init_termios.c_cflag = 
+		(leon_reg.tty_driver->init_termios.c_cflag & ~CBAUD) | B38400;
+	
+	if (ret) return ret;
+
+	for (i = 0; i < leon_ports_nr; i++) {
+		struct console co;
+		leon_ports[i].port.uartclk = freq_khz * 1000;
+		uart_add_one_port(&leon_reg, &leon_ports[i].port);
+		uart_set_options(&leon_ports[i].port, &co,
+				 baud_rates[i], 'n', 8, 'n');
+	}
+
+	return ret;
+}
+
+static void __exit gaisler_apbuart_exit(void)
+{
+	int i;
+
+	for (i = 0; i < leon_ports_nr; i++)
+		uart_remove_one_port(&leon_reg, &leon_ports[i].port);
+
+	uart_unregister_driver(&leon_reg);
+}
+
+module_init(gaisler_apbuart_init);
+module_exit(gaisler_apbuart_exit);
+
+MODULE_AUTHOR("Konrad Eisele<eiselekd@web.de>, based on AMBA serial");
+MODULE_DESCRIPTION("grlib apbuart serial driver");
+MODULE_LICENSE("GPL");
+
+
+
+
+
+void leon3_rs_put_char_base(LEON3_APBUART_Regs_Map *uart_regs,char ch)
+{
+        int flags, loops;
+
+        save_flags(flags); cli();
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_THE) && (loops < 100000))
+        	loops++;
+
+	LEON3_BYPASS_STORE_PA(&(uart_regs->data),ch);
+
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_TSE) && (loops < 100000))
+        	loops++;
+        restore_flags(flags);
+}
+
+void leon3_rs_put_char(char ch)
+{
+  LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+  if (b) {
+    leon3_rs_put_char_base(b,ch);
+  }
+}
+
+void console_print_LEON(const char *p)
+{
+	char c;
+
+        LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+        
+	while((c=*(p++)) != 0) {
+          if(c == '\n')
+            leon3_rs_put_char_base(b,'\r');
+          leon3_rs_put_char_base(b,c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	/* rs_fair_output(); */
+
+	return;
+}
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Kconfig linux-2.6.10/drivers/amba/opencores/Kconfig
--- ../linux-2.6.10/drivers/amba/opencores/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,36 @@
+
+menu "Vendor Opencores"
+
+config GRLIB_OPENCORES_ETHERMAC
+	bool "Grlib's opencores ethermac driver" 
+	default y
+	depends on NETDEVICES
+	---help---
+	  Add the driver for the grlib opencore ethermac.
+
+
+config GRLIB_OPENCORES_ETHERMAC_MACMSB
+	hex "MSB 24 bits of ethern number (hex)" 
+	default 00007A
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Most significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is 00007A.
+
+config GRLIB_OPENCORES_ETHERMAC_MACLSB
+	hex "LSB 24 bits of ethern number (hex)" 
+	default CC0012
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Least significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is CC0012.
+
+
+
+
+endmenu
+
+
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Makefile linux-2.6.10/drivers/amba/opencores/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_OPENCORES_ETHERMAC)		+= ethermac/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile linux-2.6.10/drivers/amba/opencores/ethermac/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= open_eth.o
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,1181 @@
+/*
+ * Ethernet driver for Open Ethernet Controller (www.opencores.org).
+ *      Copyright (c) 2002 Simon Srot (simons@opencores.org)
+ *
+ * Based on:
+ *
+ * Ethernet driver for Motorola MPC8xx.
+ *      Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * mcen302.c: A Linux network driver for Mototrola 68EN302 MCU
+ *
+ *      Copyright (C) 1999 Aplio S.A. Written by Vadim Lebedev
+ *
+ * Right now XXBUFF_PREALLOC must be used, because MAC does not 
+ * handle unaligned buffers yet.  Also the cache inhibit calls
+ * should be used some day.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/cacheflush.h>
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/rtnetlink.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <asm/processor.h>	/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+ 
+#ifdef CONFIG_LEON
+#include <asm/leon.h>
+//#define OETH_INTERRUPT LEON_INTERRUPT_OPEN_ETH
+#define DEBUG 1
+#endif
+
+/*
+#define MACADDR1 0
+#define MACADDR2 0
+#define MACADDR3 0
+#define MACADDR4 0
+#define MACADDR5 0
+*/
+ 
+#define MACADDR0 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 16) & 0xff)
+#define MACADDR1 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 8) & 0xff)
+#define MACADDR2 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 0) & 0xff)
+#define MACADDR3 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 16) & 0xff)
+#define MACADDR4 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 8) & 0xff)
+#define MACADDR5 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 0) & 0xff)
+
+#include "open_eth.h"
+
+//#define net_device device
+//#define __pa(x) (x)
+//#define __va(x) (x)
+#define __clear_user(add,len) memset((add),0,(len))
+
+
+#define RXBUFF_PREALLOC	1
+#define TXBUFF_PREALLOC	1
+
+//#define SRAM_BUFF	1
+//#define SRAM_BUFF_BASE	(FBMEM_BASE_ADD + 0x80000)
+
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT	(2*HZ)
+
+/* Buffer number (must be 2^n) 
+ */
+#define OETH_RXBD_NUM		8
+#define OETH_TXBD_NUM		8
+#define OETH_RXBD_NUM_MASK	(OETH_RXBD_NUM-1)
+#define OETH_TXBD_NUM_MASK	(OETH_TXBD_NUM-1)
+
+/* Buffer size 
+ */
+#define OETH_RX_BUFF_SIZE	2048
+#define OETH_TX_BUFF_SIZE	2048
+
+/* How many buffers per page 
+ */
+#define OETH_RX_BUFF_PPGAE	(PAGE_SIZE/OETH_RX_BUFF_SIZE)
+#define OETH_TX_BUFF_PPGAE	(PAGE_SIZE/OETH_TX_BUFF_SIZE)
+
+/* How many pages is needed for buffers 
+ */
+#define OETH_RX_BUFF_PAGE_NUM	(OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE)
+#define OETH_TX_BUFF_PAGE_NUM	(OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE)
+
+/* Buffer size  (if not XXBUF_PREALLOC 
+ */
+#define MAX_FRAME_SIZE		1518
+
+/* The buffer descriptors track the ring buffers.   
+ */
+struct oeth_private {
+	struct	sk_buff* rx_skbuff[OETH_RXBD_NUM];
+	struct	sk_buff* tx_skbuff[OETH_TXBD_NUM];
+
+	ushort	tx_next;			/* Next buffer to be sent */
+	ushort	tx_last;			/* Next buffer to be checked if packet sent */
+	ushort	tx_full;			/* Buffer ring fuul indicator */
+	ushort	rx_cur;				/* Next buffer to be checked if packet received */
+
+	oeth_regs	*regs;			/* Address of controller registers. */
+	oeth_bd		*rx_bd_base;		/* Address of Rx BDs. */
+	oeth_bd		*tx_bd_base;		/* Address of Tx BDs. */
+        ushort          irq;
+
+	struct net_device_stats stats;
+};
+
+static int oeth_open(struct net_device *dev);
+static int oeth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void oeth_rx(struct net_device *dev);
+static void oeth_tx(struct net_device *dev);
+static irqreturn_t oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int oeth_close(struct net_device *dev);
+static struct net_device_stats *oeth_get_stats(struct net_device *dev);
+static void oeth_set_multicast_list(struct net_device *dev);
+static int oeth_set_mac_address(struct net_device *dev,void *p);
+static int calc_crc(char *mac_addr);
+
+#define OETH_REGLOAD(a)	(LEON3_BYPASS_LOAD_PA(&(a)))
+#define OETH_REGSAVE(a,v) (LEON3_BYPASS_STORE_PA(&(a),v))
+#define OETH_REGORIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) | (v))))
+#define OETH_REGANDIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) & (v))))
+
+
+#if DEBUG
+static void
+oeth_print_packet(unsigned long add, int len)
+{
+  //	int i;
+
+	printk("ipacket: add = %x len = %d\n", (unsigned int)add, len);
+/*
+	for(i = 0; i < len; i++) {
+  		if(!(i % 16))
+    			printk("\n");
+  		printk(" %.2x", *(((unsigned char *)add) + i));
+	}
+*/
+      printk("\n");
+	printk("                             \n");
+}
+#endif
+
+static int
+oeth_open(struct net_device *dev)
+{
+
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	
+#if DEBUG
+	printk("oeth_open\n");
+#endif
+#ifndef RXBUFF_PREALLOC
+	struct  sk_buff *skb;
+	volatile oeth_bd *rx_bd;
+	int i;
+
+	rx_bd = cep->rx_bd_base;
+
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+		skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+		if (skb == NULL)
+      		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+		else
+		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = skb;
+
+		OETH_REGSAVE(rx_bd[i].addr,(unsigned long)skb->tail);
+		//rx_bd[i].addr = (unsigned long)skb->tail;
+	}
+        OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+#endif
+
+	/* Install our interrupt handler.
+	 */
+	request_irq(cep->irq, oeth_interrupt, 0, "eth", (void *)dev);
+
+	/* Enable receiver and transmiter 
+	 */
+        OETH_REGORIN(regs->moder , OETH_MODER_RXEN | OETH_MODER_TXEN);
+	//regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
+
+	return 0;
+}
+
+static int
+oeth_close(struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	volatile oeth_bd *bdp;
+	int i;
+
+#if DEBUG
+	printk("oeth_close\n");
+#endif
+	/* Free interrupt hadler 
+	 */
+	free_irq(cep->irq, (void *)dev);
+
+	/* Disable receiver and transmitesr 
+	 */
+        OETH_REGANDIN(regs->moder , ~(OETH_MODER_RXEN | OETH_MODER_TXEN));
+	//regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);	
+
+	bdp = cep->rx_bd_base;
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status, ~(OETH_TX_BD_STATS | OETH_TX_BD_READY));
+		//bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
+		bdp++;
+	}
+
+	bdp = cep->tx_bd_base;
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status , ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY));
+		//bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
+		bdp++;
+	}
+
+#ifndef RXBUFF_PREALLOC
+
+	/* Free all alocated rx buffers 
+	 */
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	
+		if (cep->rx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->rx_skbuff[i]); //, FREE_READ);
+		
+	}
+#endif
+#ifndef TXBUFF_PREALLOC
+
+	/* Free all alocated tx buffers 
+	 */
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	
+		if (cep->tx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->tx_skbuff[i]);//, FREE_WRITE);
+	}
+#endif
+
+	return 0;
+}
+
+static int
+oeth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	volatile oeth_bd *bdp;
+	unsigned long flags;
+
+	/* Fill in a Tx ring entry 
+	 */
+	bdp = cep->tx_bd_base + cep->tx_next;
+
+	if (cep->tx_full) {
+
+		/* All transmit buffers are full.  Bail out.
+		 */
+		printk("%s: tx queue full!.\n", dev->name);
+		return 1;
+	}
+
+	/* Clear all of the status flags.
+	 */
+	OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_STATS);
+	//bdp->len_status &= ~OETH_TX_BD_STATS;
+
+	/* If the frame is short, tell CPM to pad it.
+	 */
+	if (skb->len <= ETH_ZLEN)
+	        OETH_REGORIN(bdp->len_status , OETH_TX_BD_PAD);
+	        //bdp->len_status |= OETH_TX_BD_PAD;
+	else
+	        OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_PAD);
+	        //bdp->len_status &= ~OETH_TX_BD_PAD;
+
+#if DEBUG
+	printk("TX\n");
+	oeth_print_packet((unsigned long)skb->data, skb->len);
+#endif
+
+#ifdef TXBUFF_PREALLOC
+
+	/* Copy data in preallocated buffer */
+	if (skb->len > OETH_TX_BUFF_SIZE) {
+		printk("%s: tx frame too long!.\n", dev->name);
+		return 1;
+	}
+	else {
+	  
+	  memcpy(__va((unsigned char *)OETH_REGLOAD(bdp->addr)), skb->data, skb->len); 
+            __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+	    //memcpy(__va((unsigned char *)bdp->addr), skb->data, skb->len); 
+            //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+      }
+
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16));
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+
+	dev_kfree_skb(skb); // 	dev_kfree_skb(skb, FREE_WRITE);
+#else
+	/* Set buffer length and buffer pointer.
+	 */
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16))
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+	OETH_REGSAVE(bdp->addr , (uint)__pa(skb->data));
+	//bdp->addr = (uint)__pa(skb->data);
+
+	/* Save skb pointer.
+	 */
+	cep->tx_skbuff[cep->tx_next] = skb;
+#endif
+
+	cep->tx_next = (cep->tx_next + 1) & OETH_TXBD_NUM_MASK;
+	
+	save_flags(flags); cli();
+
+	if (cep->tx_next == cep->tx_last)
+		cep->tx_full = 1;
+
+	/* Send it on its way.  Tell controller its ready, interrupt when done,
+	 * and to put the CRC on the end.
+	 */
+        OETH_REGORIN(bdp->len_status , (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC));
+	//bdp->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
+
+	dev->trans_start = jiffies;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The interrupt handler.
+ */
+static irqreturn_t
+oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct	net_device *dev = dev_id;
+	volatile struct	oeth_private *cep;
+	uint	int_events;
+      
+#if DEBUG
+      printk ("oeth_interrupt()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get the interrupt events that caused us to be here.
+	 */
+        int_events = OETH_REGLOAD( cep->regs->int_src);
+	//int_events = cep->regs->int_src;
+        OETH_REGSAVE(cep->regs->int_src , int_events);
+	//cep->regs->int_src = int_events;
+
+	/* Handle receive event in its own function.
+	 */
+	if (int_events & (OETH_INT_RXF | OETH_INT_RXE))
+		oeth_rx(dev_id);
+
+	/* Handle transmit event in its own function.
+	 */
+	if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
+		oeth_tx(dev_id);
+            netif_wake_queue(dev); //mark_bh(NET_BH);
+	}
+
+	/* Check for receive busy, i.e. packets coming but no place to
+	 * put them. 
+	 */
+	if (int_events & OETH_INT_BUSY) {
+		if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE)))
+			oeth_rx(dev_id);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static void
+oeth_tx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+
+#ifndef TXBUFF_PREALLOC
+	struct	sk_buff *skb;
+#endif
+
+#if DEBUG
+      printk ("oeth_tx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) {
+
+		bdp = cep->tx_bd_base + cep->tx_last;
+
+		if ((OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_READY) || 
+		//if ((bdp->len_status & OETH_TX_BD_READY) || 
+			((cep->tx_last == cep->tx_next) && !cep->tx_full))
+			break;
+
+		/* Check status for errors
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+
+		/* Check status for errors
+		 */
+                /*
+		if (bdp->len_status & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (bdp->len_status & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (bdp->len_status & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (bdp->len_status & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (bdp->len_status & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+		*/
+
+		cep->stats.tx_packets++;
+		cep->stats.collisions += (OETH_REGLOAD(bdp->len_status) >> 4) & 0x000f;
+		//cep->stats.collisions += (bdp->len_status >> 4) & 0x000f;
+
+#ifndef TXBUFF_PREALLOC
+		skb = cep->tx_skbuff[cep->tx_last];
+
+		/* Free the sk buffer associated with this last transmit.
+		*/
+		dev_kfree_skb(skb);//, FREE_WRITE);
+#endif
+
+		if (cep->tx_full)
+			cep->tx_full = 0;
+	}
+}
+
+static void
+oeth_rx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+	struct	sk_buff *skb;
+	int	pkt_len;
+	int	bad = 0;
+#ifndef RXBUFF_PREALLOC
+	struct	sk_buff *small_skb;
+#endif
+      
+#if DEBUG
+      printk ("oeth_rx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* First, grab all of the stats for the incoming packet.
+	 * These get messed up if we get called due to a busy condition.
+	 */
+	for (;;cep->rx_cur = (cep->rx_cur + 1) & OETH_RXBD_NUM_MASK) {
+
+		bdp = cep->rx_bd_base + cep->rx_cur;
+
+#ifndef RXBUFF_PREALLOC
+		skb = cep->rx_skbuff[cep->rx_cur];
+
+		if (skb == NULL) {
+
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			if (skb != NULL)
+			{
+				OETH_REGSAVE(bdp->addr , (unsigned long) skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long) skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+
+			continue;
+		}
+#endif
+			
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_EMPTY)
+		//if (bdp->len_status & OETH_RX_BD_EMPTY)
+			break;
+			
+		/* Check status for errors.
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+		//if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+                  printk ("oeth: length error\n");
+			cep->stats.rx_length_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_DRIBBLE) {
+		//if (bdp->len_status & OETH_RX_BD_DRIBBLE) {
+                  printk ("oeth: dribble error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_CRCERR) {
+		//if (bdp->len_status & OETH_RX_BD_CRCERR) {
+                  printk ("oeth: crc error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_OVERRUN) {
+		//if (bdp->len_status & OETH_RX_BD_OVERRUN) {
+                  printk ("oeth: overrun error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_MISS) {
+		//if (bdp->len_status & OETH_RX_BD_MISS) {
+                  printk ("oeth: miss error\n");
+
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_LATECOL) {
+		//if (bdp->len_status & OETH_RX_BD_LATECOL) {
+                  printk ("oeth: latecol error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		
+		
+		if (bad) {
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+      //bdp->len_status &= ~OETH_RX_BD_STATS;
+      //bdp->len_status |= OETH_RX_BD_EMPTY;
+
+			continue;
+		}
+
+		/* Process the incoming frame.
+		 */
+		pkt_len = OETH_REGLOAD(bdp->len_status) >> 16;
+		//pkt_len = bdp->len_status >> 16;
+        
+#ifdef RXBUFF_PREALLOC
+		//skb = dev_alloc_skb(pkt_len);
+                skb = alloc_skb(pkt_len + 4, GFP_ATOMIC); //added from michael wurm's patches
+
+		if (skb == NULL) {
+			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+			cep->stats.rx_dropped++;
+		}
+		else {
+			skb_reserve(skb, 2); //added from michael wurm's patches
+			skb->dev = dev;
+
+                  __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+                  //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+#if DEBUG
+			printk("RX\n");
+                  oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), pkt_len);
+                  //oeth_print_packet((unsigned long)(__va(bdp->addr)), pkt_len);
+#endif
+			memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+			//memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+		}
+
+		OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+		OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+		//bdp->len_status &= ~OETH_RX_BD_STATS;
+		//bdp->len_status |= OETH_RX_BD_EMPTY;
+#else //RXBUFF_PREALLOC
+
+		if (pkt_len < 128) {
+
+			small_skb = dev_alloc_skb(pkt_len);
+
+			if (small_skb) {
+				small_skb->dev = dev;
+
+                        __flush_page_to_ram(__va(OETH_REGLOAD(bdp->addr)));
+                        //__flush_page_to_ram(__va(bdp->addr));
+#if DEBUG
+				printk("RX short\n");
+                        oeth_print_packet((unsigned long)(__va(bdp->addr)), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+                        memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+                        //memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+
+                        small_skb->protocol = eth_type_trans(small_skb,dev);
+                        netif_rx(small_skb);
+				cep->stats.rx_packets++;
+			}
+			else {
+				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+	                        cep->stats.rx_dropped++;
+			}
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+			//bdp->len_status |= OETH_RX_BD_EMPTY;
+		}
+		else {
+        		skb->dev = dev;
+			skb_put(skb, OETH_REGLOAD(bdp->len_status) >> 16);
+			//skb_put(skb, bdp->len_status >> 16);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+#if DEBUG
+			printk("RX long\n");
+                        oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+		
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+        
+			if (skb) {
+				cep->rx_skbuff[cep->rx_cur] = skb;
+
+				OETH_REGSAVE(bdp->addr , (unsigned long)skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long)skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+			else {
+				cep->rx_skbuff[cep->rx_cur] = NULL;	
+			}
+		}
+#endif //!RXBUFF_PREALLOC
+	}
+
+#if DEBUG
+      printk ("oeth_rx sent()\n");
+#endif
+}
+
+static int calc_crc(char *mac_addr)
+{
+	int result = 0;
+	return (result & 0x3f);
+}
+
+static struct net_device_stats *oeth_get_stats(struct net_device *dev)
+{
+        struct oeth_private *cep = (struct oeth_private *)dev->priv;
+ 
+        return &cep->stats;
+}
+
+static void oeth_set_multicast_list(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	struct	dev_mc_list *dmi;
+	volatile oeth_regs *regs;
+	int	i;
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get pointer of controller registers.
+	 */
+	regs = (oeth_regs *)dev->base_addr;
+
+	if (dev->flags & IFF_PROMISC) {
+	  
+		/* Log any net taps. 
+		 */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		OETH_REGORIN(regs->moder , OETH_MODER_PRO);
+		//regs->moder |= OETH_MODER_PRO;
+	} else {
+
+		OETH_REGANDIN(regs->moder , ~OETH_MODER_PRO);
+		//regs->moder &= ~OETH_MODER_PRO;
+
+		if (dev->flags & IFF_ALLMULTI) {
+
+			/* Catch all multicast addresses, so set the
+			 * filter to all 1's.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0xffffffff);
+			OETH_REGSAVE(regs->hash_addr1 , 0xffffffff);
+			//regs->hash_addr0 = 0xffffffff;
+			//regs->hash_addr1 = 0xffffffff;
+		}
+		else if (dev->mc_count) {
+
+                        OETH_REGORIN(regs->moder , OETH_MODER_IAM);
+                        //regs->moder |= OETH_MODER_IAM;
+                        
+			/* Clear filter and add the addresses in the list.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			//regs->hash_addr0 = 0x00000000;
+			//regs->hash_addr0 = 0x00000000;
+
+			dmi = dev->mc_list;
+
+			for (i = 0; i < dev->mc_count; i++) {
+				
+				int hash_b;
+
+				/* Only support group multicast for now.
+				 */
+				if (!(dmi->dmi_addr[0] & 1))
+					continue;
+
+				hash_b = calc_crc(dmi->dmi_addr); 
+				if(hash_b >= 32)
+					OETH_REGORIN(regs->hash_addr1 , 1 << (hash_b - 32));
+				        //regs->hash_addr1 |= 1 << (hash_b - 32);
+				else
+					OETH_REGORIN(regs->hash_addr0 , 1 << hash_b);
+				        //regs->hash_addr0 |= 1 << hash_b;
+			}
+		}
+	}
+}
+
+static int oeth_set_mac_address(struct net_device *dev,void *p)
+{
+	struct sockaddr *addr=p;
+	volatile oeth_regs *regs;
+      
+	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+      
+	regs = (oeth_regs *)dev->base_addr;
+      
+    
+	    
+// old version: sa_data is of type char, will be expanded to int when ored
+// so negative values e.g 0xB5 will be expanded to 0xffffffB5 and ored
+/*
+	regs->mac_addr1 = 	addr->sa_data[0] << 8 	|
+            			addr->sa_data[1];
+        regs->mac_addr0 = 	addr->sa_data[2] << 24 	|
+            			addr->sa_data[3] << 16 	|
+            			addr->sa_data[4] << 8 	|
+            			addr->sa_data[5];
+
+*/
+
+// dev_addr is of type unsigned char and will be expanded to unsigned int which is ok
+	OETH_REGSAVE(regs->mac_addr1 , 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1]);
+        OETH_REGSAVE(regs->mac_addr0 , 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5]);
+
+	/*	    
+	regs->mac_addr1 = 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1];
+        regs->mac_addr0 = 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5];
+	*/  
+	    
+	    
+	return 0;
+}
+
+/* Initialize the Open Ethernet MAC.
+ */
+int do_oeth_probe(struct net_device *dev)
+{
+	struct oeth_private *cep;
+	volatile oeth_regs *regs;
+	volatile oeth_bd *tx_bd, *rx_bd;
+	int i, j, k, l;
+#ifdef SRAM_BUFF
+	unsigned long mem_addr = SRAM_BUFF_BASE;
+#else
+	unsigned long mem_addr;
+#endif
+	unsigned long base;
+
+	amba_ahb_device adev[1];
+	l = amba_get_free_ahbslv_devices (VENDOR_GAISLER, GAISLER_ETHAHB, adev, 1);
+	if (l == 0) {
+	  return 1;
+	}
+	
+	base = adev[0].start[0];
+
+	//printk("Probing Open Ethernet Core at 0x%x (irq:%i,n:%s)\n",adev[0].start[0], adev[0].irq, dev ->name);
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Allocate a new 'dev' if needed. 
+	 */
+	if (dev == NULL) {
+		/*
+		 * Don't allocate the private data here, it is done later
+		 * This makes it easier to free the memory when this driver
+		 * is used as a module.
+		 */
+//		dev = init_etherdev(0, 0);
+                dev=alloc_etherdev(0);		
+//		dev = alloc_netdev(0, "eth0", setup_ether);
+		if (dev == NULL)
+			return -ENOMEM;
+	}
+
+
+
+
+	/* Initialize the device structure. 
+	 */
+	if (dev->priv == NULL) {
+		cep = (struct oeth_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+		dev->priv = cep;
+		if (dev->priv == NULL)
+			return -ENOMEM;
+	}
+	
+	__clear_user(cep,sizeof(*cep));
+
+	/* Get pointer ethernet controller configuration registers.
+	 */
+	cep->regs = (oeth_regs *)(OETH_REG_BASE(base));
+	regs = (oeth_regs *)(OETH_REG_BASE(base));
+	cep->irq = adev[0].irq;
+
+	/* Reset the controller.
+	 */
+	OETH_REGSAVE(regs->moder , OETH_MODER_RST);	/* Reset ON */
+	OETH_REGANDIN(regs->moder , ~OETH_MODER_RST);	/* Reset OFF */
+	//regs->moder = OETH_MODER_RST;	/* Reset ON */
+	//regs->moder &= ~OETH_MODER_RST;	/* Reset OFF */
+
+	/* Setting TXBD base to OETH_TXBD_NUM.
+	 */
+	OETH_REGSAVE(regs->tx_bd_num , OETH_TXBD_NUM);
+	//regs->tx_bd_num = OETH_TXBD_NUM;
+	
+	/* Initialize TXBD pointer
+	 */
+	cep->tx_bd_base = (oeth_bd *)OETH_BD_BASE(base);
+	tx_bd = (volatile oeth_bd *)OETH_BD_BASE(base);
+
+	/* Initialize RXBD pointer
+	 */
+	cep->rx_bd_base = ((oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+	rx_bd = ((volatile oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+
+	/* Initialize transmit pointers.
+	 */
+	cep->rx_cur = 0;
+	cep->tx_next = 0;
+	cep->tx_last = 0;
+	cep->tx_full = 0;
+
+	/* Set min/max packet length 
+	 */
+	OETH_REGSAVE(regs->packet_len , 0x00400600);
+	//regs->packet_len = 0x00400600;
+
+	/* Set IPGT register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgt , 0x00000012);
+	//regs->ipgt = 0x00000012;
+
+	/* Set IPGR1 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr1 , 0x0000000c);
+	//regs->ipgr1 = 0x0000000c;
+
+	/* Set IPGR2 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr2 , 0x00000012);
+	//regs->ipgr2 = 0x00000012;
+
+	/* Set COLLCONF register to recomended value 
+	 */
+	OETH_REGSAVE(regs->collconf , 0x000f003f);
+	//regs->collconf = 0x000f003f;
+
+	/* Set control module mode 
+	 */
+#if 0
+	OETH_REGSAVE(regs->ctrlmoder , OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW);
+	//regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW;
+#else
+	OETH_REGSAVE(regs->ctrlmoder , 0);
+	//regs->ctrlmoder = 0;
+#endif
+
+  /* Set PHY to show Tx status, Rx status and Link status */
+  /*regs->miiaddress = 20<<8;
+  regs->miitx_data = 0x1422;
+  regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;*/
+ 
+  // switch to 10 mbit ethernet
+  OETH_REGSAVE(regs->miiaddress , 0);
+  OETH_REGSAVE(regs->miitx_data , 0);
+  OETH_REGSAVE(regs->miicommand , OETH_MIICOMMAND_WCTRLDATA);
+  //regs->miiaddress = 0;
+  //regs->miitx_data = 0;
+  //regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
+  
+#ifdef TXBUFF_PREALLOC
+
+	/* Initialize TXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(tx_bd[k].len_status , OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(tx_bd[k].addr , __pa(mem_addr));
+			//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+			//tx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_TX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#else
+
+ 	/* Initialize TXBDs.
+	 */
+	for(i = 0; i < OETH_TXBD_NUM; i++) {
+
+		cep->tx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(tx_bd[i].len_status , (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+		OETH_REGSAVE(tx_bd[i].addr , 0);
+		//tx_bd[i].len_status = (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+		//tx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#endif
+
+#ifdef RXBUFF_PREALLOC
+
+	/* Initialize RXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(rx_bd[k].len_status , OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(rx_bd[k].addr , __pa(mem_addr));
+			//rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+			//rx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_RX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#else
+	/* Initialize RXBDs.
+	 */
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+
+		OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		//rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(rx_bd[i].addr , 0);
+		//rx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#endif
+	
+	/* Set default ethernet station address.
+	 */
+	dev->dev_addr[0] = MACADDR0;
+	dev->dev_addr[1] = MACADDR1;
+	dev->dev_addr[2] = MACADDR2;
+	dev->dev_addr[3] = MACADDR3;
+	dev->dev_addr[4] = MACADDR4;
+	dev->dev_addr[5] = MACADDR5;
+
+	OETH_REGSAVE(regs->mac_addr1 , MACADDR0 << 8 | MACADDR1);
+	OETH_REGSAVE(regs->mac_addr0 , MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5);
+	//regs->mac_addr1 = MACADDR0 << 8 | MACADDR1;
+	//regs->mac_addr0 = MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5;
+	
+	/* Clear all pending interrupts 
+	 */
+	OETH_REGSAVE(regs->int_src , 0xffffffff);
+	//regs->int_src = 0xffffffff;
+
+	/* Promisc, IFG, CRCEn
+	 */
+	OETH_REGORIN(regs->moder , OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN);
+	//regs->moder |= OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN;
+
+	/* Enable interrupt sources.
+	 */
+	OETH_REGSAVE(regs->int_mask , OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC);
+	/*	regs->int_mask = OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC;
+	*/
+	/* Fill in the fields of the device structure with ethernet values. 
+	 */
+	ether_setup(dev);
+
+	dev->base_addr = (unsigned long)OETH_REG_BASE(base);
+
+	/* The Open Ethernet specific entries in the device structure. 
+	 */
+	dev->open = oeth_open;
+	dev->hard_start_xmit = oeth_start_xmit;
+	dev->stop = oeth_close;
+	dev->get_stats = oeth_get_stats;
+	dev->set_multicast_list = oeth_set_multicast_list;
+	dev->set_mac_address = oeth_set_mac_address;
+
+	if (register_netdev(dev)) {
+	  kfree(dev->priv);
+	  printk(KERN_ERR "open_eth: netdevice registration failed.\n");
+	  return -ENOMEM;
+        }
+
+	printk("%s: Open Ethernet Core Version 1.0 at [0x%x] irq %i\n", dev->name,(unsigned int)(cep->regs),(unsigned int)(cep->irq));
+
+	return 0;
+}
+	
+struct net_device *grlib_oeth_probe(int unit) {
+  
+  struct net_device *dev = alloc_etherdev(0);
+  int err;
+  
+  if (!dev)
+    return ERR_PTR(-ENOMEM);
+  if (unit >= 0)
+    sprintf(dev->name, "eth%d", unit);
+  SET_MODULE_OWNER(dev);
+  err = do_oeth_probe(dev);
+  if (err) {
+    free_netdev(dev);
+    return ERR_PTR(err);
+  }
+  return dev;
+
+  //      printk("Init: Open Ethernet probe\n");
+  //    oeth_dev=alloc_etherdev(sizeof(struct oeth_private));
+  //    return do_oeth_probe(oeth_dev);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef MODULE
+static struct net_device		*oeth_dev;		/* netdevice struct */
+
+int
+init_module(void)
+{
+  oeth_dev = grlib_oeth_probe(-1);
+  if (IS_ERR(oeth_dev)) {
+    printk(KERN_WARNING "Grlib Oeth: No core found\n");
+    return PTR_ERR(oeth_dev);
+  }
+  return 0;
+}
+
+void cleanup_module(void) {
+	
+  printk("Open Ethernet Core cleanup\n");
+  if (oeth_dev) {
+    unregister_netdev(oeth_dev);
+    kfree(oeth_dev);
+  }
+}
+
+//module_init(grlib_oeth_probe);
+//module_exit(oeth_cleanup);
+MODULE_LICENSE("GPL");
+
+#endif
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,143 @@
+/* Ethernet configuration registers */
+typedef struct _oeth_regs {
+        uint    moder;          /* Mode Register */
+        uint    int_src;        /* Interrupt Source Register */
+        uint    int_mask;       /* Interrupt Mask Register */
+        uint    ipgt;           /* Back to Bak Inter Packet Gap Register */
+        uint    ipgr1;          /* Non Back to Back Inter Packet Gap Register 1 */
+        uint    ipgr2;          /* Non Back to Back Inter Packet Gap Register 2 */
+        uint    packet_len;     /* Packet Length Register (min. and max.) */
+        uint    collconf;       /* Collision and Retry Configuration Register */
+        uint    tx_bd_num;      /* Transmit Buffer Descriptor Number Register */
+        uint    ctrlmoder;      /* Control Module Mode Register */
+        uint    miimoder;       /* MII Mode Register */
+        uint    miicommand;     /* MII Command Register */
+        uint    miiaddress;     /* MII Address Register */
+        uint    miitx_data;     /* MII Transmit Data Register */
+        uint    miirx_data;     /* MII Receive Data Register */
+        uint    miistatus;      /* MII Status Register */
+        uint    mac_addr0;      /* MAC Individual Address Register 0 */
+        uint    mac_addr1;      /* MAC Individual Address Register 1 */
+        uint    hash_addr0;     /* Hash Register 0 */
+        uint    hash_addr1;     /* Hash Register 1 */                           
+} oeth_regs;
+
+/* Ethernet buffer descriptor */
+typedef struct _oeth_bd {
+#if 0
+        ushort  len;            /* Buffer length */
+        ushort  status;         /* Buffer status */
+#else
+        uint    len_status;
+#endif
+        uint    addr;           /* Buffer address */
+} oeth_bd;
+
+#define OETH_REG_BASE(b)        (b)
+#define OETH_BD_BASE(b)         ((b) + 0x400)
+#define OETH_TOTAL_BD           128
+#define OETH_MAXBUF_LEN         0x600
+                                
+/* Tx BD */                     
+#define OETH_TX_BD_READY        0x8000 /* Tx BD Ready */
+#define OETH_TX_BD_IRQ          0x4000 /* Tx BD IRQ Enable */
+#define OETH_TX_BD_WRAP         0x2000 /* Tx BD Wrap (last BD) */
+#define OETH_TX_BD_PAD          0x1000 /* Tx BD Pad Enable */
+#define OETH_TX_BD_CRC          0x0800 /* Tx BD CRC Enable */
+                                
+#define OETH_TX_BD_UNDERRUN     0x0100 /* Tx BD Underrun Status */
+#define OETH_TX_BD_RETRY        0x00F0 /* Tx BD Retry Status */
+#define OETH_TX_BD_RETLIM       0x0008 /* Tx BD Retransmission Limit Status */
+#define OETH_TX_BD_LATECOL      0x0004 /* Tx BD Late Collision Status */
+#define OETH_TX_BD_DEFER        0x0002 /* Tx BD Defer Status */
+#define OETH_TX_BD_CARRIER      0x0001 /* Tx BD Carrier Sense Lost Status */
+#define OETH_TX_BD_STATS        (OETH_TX_BD_UNDERRUN            | \
+                                OETH_TX_BD_RETRY                | \
+                                OETH_TX_BD_RETLIM               | \
+                                OETH_TX_BD_LATECOL              | \
+                                OETH_TX_BD_DEFER                | \
+                                OETH_TX_BD_CARRIER)
+                                
+/* Rx BD */                     
+#define OETH_RX_BD_EMPTY        0x8000 /* Rx BD Empty */
+#define OETH_RX_BD_IRQ          0x4000 /* Rx BD IRQ Enable */
+#define OETH_RX_BD_WRAP         0x2000 /* Rx BD Wrap (last BD) */
+                                
+#define OETH_RX_BD_MISS         0x0080 /* Rx BD Miss Status */
+#define OETH_RX_BD_OVERRUN      0x0040 /* Rx BD Overrun Status */
+#define OETH_RX_BD_INVSIMB      0x0020 /* Rx BD Invalid Symbol Status */
+#define OETH_RX_BD_DRIBBLE      0x0010 /* Rx BD Dribble Nibble Status */
+#define OETH_RX_BD_TOOLONG      0x0008 /* Rx BD Too Long Status */
+#define OETH_RX_BD_SHORT        0x0004 /* Rx BD Too Short Frame Status */
+#define OETH_RX_BD_CRCERR       0x0002 /* Rx BD CRC Error Status */
+#define OETH_RX_BD_LATECOL      0x0001 /* Rx BD Late Collision Status */
+#define OETH_RX_BD_STATS        (OETH_RX_BD_MISS                | \
+                                OETH_RX_BD_OVERRUN              | \
+                                OETH_RX_BD_INVSIMB              | \
+                                OETH_RX_BD_DRIBBLE              | \
+                                OETH_RX_BD_TOOLONG              | \
+                                OETH_RX_BD_SHORT                | \
+                                OETH_RX_BD_CRCERR               | \
+                                OETH_RX_BD_LATECOL)
+
+/* MODER Register */
+#define OETH_MODER_RXEN         0x00000001 /* Receive Enable  */
+#define OETH_MODER_TXEN         0x00000002 /* Transmit Enable */
+#define OETH_MODER_NOPRE        0x00000004 /* No Preamble  */
+#define OETH_MODER_BRO          0x00000008 /* Reject Broadcast */
+#define OETH_MODER_IAM          0x00000010 /* Use Individual Hash */
+#define OETH_MODER_PRO          0x00000020 /* Promiscuous (receive all) */
+#define OETH_MODER_IFG          0x00000040 /* Min. IFG not required */
+#define OETH_MODER_LOOPBCK      0x00000080 /* Loop Back */
+#define OETH_MODER_NOBCKOF      0x00000100 /* No Backoff */
+#define OETH_MODER_EXDFREN      0x00000200 /* Excess Defer */
+#define OETH_MODER_FULLD        0x00000400 /* Full Duplex */
+#define OETH_MODER_RST          0x00000800 /* Reset MAC */
+#define OETH_MODER_DLYCRCEN     0x00001000 /* Delayed CRC Enable */
+#define OETH_MODER_CRCEN        0x00002000 /* CRC Enable */
+#define OETH_MODER_HUGEN        0x00004000 /* Huge Enable */
+#define OETH_MODER_PAD          0x00008000 /* Pad Enable */
+#define OETH_MODER_RECSMALL     0x00010000 /* Receive Small */
+ 
+/* Interrupt Source Register */
+#define OETH_INT_TXB            0x00000001 /* Transmit Buffer IRQ */
+#define OETH_INT_TXE            0x00000002 /* Transmit Error IRQ */
+#define OETH_INT_RXF            0x00000004 /* Receive Frame IRQ */
+#define OETH_INT_RXE            0x00000008 /* Receive Error IRQ */
+#define OETH_INT_BUSY           0x00000010 /* Busy IRQ */
+#define OETH_INT_TXC            0x00000020 /* Transmit Control Frame IRQ */
+#define OETH_INT_RXC            0x00000040 /* Received Control Frame IRQ */
+
+/* Interrupt Mask Register */
+#define OETH_INT_MASK_TXB       0x00000001 /* Transmit Buffer IRQ Mask */
+#define OETH_INT_MASK_TXE       0x00000002 /* Transmit Error IRQ Mask */
+#define OETH_INT_MASK_RXF       0x00000004 /* Receive Frame IRQ Mask */
+#define OETH_INT_MASK_RXE       0x00000008 /* Receive Error IRQ Mask */
+#define OETH_INT_MASK_BUSY      0x00000010 /* Busy IRQ Mask */
+#define OETH_INT_MASK_TXC       0x00000020 /* Transmit Control Frame IRQ Mask */
+#define OETH_INT_MASK_RXC       0x00000040 /* Received Control Frame IRQ Mask */
+ 
+/* Control Module Mode Register */
+#define OETH_CTRLMODER_PASSALL  0x00000001 /* Pass Control Frames */
+#define OETH_CTRLMODER_RXFLOW   0x00000002 /* Receive Control Flow Enable */
+#define OETH_CTRLMODER_TXFLOW   0x00000004 /* Transmit Control Flow Enable */
+                               
+/* MII Mode Register */        
+#define OETH_MIIMODER_CLKDIV    0x000000FF /* Clock Divider */
+#define OETH_MIIMODER_NOPRE     0x00000100 /* No Preamble */
+#define OETH_MIIMODER_RST       0x00000200 /* MIIM Reset */
+ 
+/* MII Command Register */
+#define OETH_MIICOMMAND_SCANSTAT  0x00000001 /* Scan Status */
+#define OETH_MIICOMMAND_RSTAT     0x00000002 /* Read Status */
+#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */
+ 
+/* MII Address Register */
+#define OETH_MIIADDRESS_FIAD    0x0000001F /* PHY Address */
+#define OETH_MIIADDRESS_RGAD    0x00001F00 /* RGAD Address */
+ 
+/* MII Status Register */
+#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */
+#define OETH_MIISTATUS_BUSY     0x00000002 /* MII Busy */
+#define OETH_MIISTATUS_NVALID   0x00000004 /* Data in MII Status Register is invalid */
+

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [4/7] LEON SPARC V8 processor support for linux-2.6.10
  2005-01-04 19:04 ` Jiri Gaisler
@ 2005-01-05 15:18   ` Jiri Gaisler
  -1 siblings, 0 replies; 4+ messages in thread
From: Jiri Gaisler @ 2005-01-05 15:18 UTC (permalink / raw)
  To: sparclinux; +Cc: linux-kernel, wli

[-- Attachment #1: Type: text/plain, Size: 419 bytes --]

Leon3 serial+ethermac driver, updated.

[4/7] diff2.6.10_driver_amba.diff         diff for drivers/amba


-- 
--------------------------------------------------------------------------
Gaisler Research, 1:a Långgatan 19, 413 27 Goteborg, Sweden, +46-317758650
fax: +46-31421407 email: info@gaisler.com, home page: www.gaisler.com
--------------------------------------------------------------------------



[-- Attachment #2: diff2.6.10_driver_amba.diff --]
[-- Type: text/plain, Size: 74624 bytes --]

diff -Naur ../linux-2.6.10/drivers/Makefile linux-2.6.10/drivers/Makefile
--- ../linux-2.6.10/drivers/Makefile	2004-12-24 22:36:00.000000000 +0100
+++ linux-2.6.10/drivers/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -60,3 +60,4 @@
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-y				+= firmware/
+obj-$(CONFIG_LEON_3)            += amba/
diff -Naur ../linux-2.6.10/drivers/amba/Kconfig linux-2.6.10/drivers/amba/Kconfig
--- ../linux-2.6.10/drivers/amba/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Kconfig	2005-01-03 17:10:41.000000000 +0100
@@ -0,0 +1,12 @@
+
+#------------------------------------------------------------------------------
+# Amba device driver configuration
+#------------------------------------------------------------------------------
+
+menu "Grlib: Amba device driver configuration"
+
+source "drivers/amba/gaisler/Kconfig"
+source "drivers/amba/opencores/Kconfig"
+
+endmenu
+
diff -Naur ../linux-2.6.10/drivers/amba/Makefile linux-2.6.10/drivers/amba/Makefile
--- ../linux-2.6.10/drivers/amba/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,7 @@
+#
+# Makefile for the PCI bus specific drivers.
+#
+
+obj-y		+= amba.o amba_driver.o
+
+obj-y           += gaisler/ opencores/
diff -Naur ../linux-2.6.10/drivers/amba/amba.c linux-2.6.10/drivers/amba/amba.c
--- ../linux-2.6.10/drivers/amba/amba.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,181 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+amba_confarea_type amba_conf;
+
+/* Pointers to Interrupt Controller configuration registers */
+volatile LEON3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs = 0;
+volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs = 0;
+unsigned long LEON3_GpTimer_Irq = 0;
+
+static void vendor_dev_string(unsigned long conf, char *vendorbuf,char *devbuf) {
+  int vendor = amba_vendor(conf); int dev = amba_device(conf);
+  char *devstr; char *vendorstr; 
+  sprintf(vendorbuf, "Unknown vendor %2x",vendor);
+  sprintf(devbuf, "Unknown device %2x",dev);
+  vendorstr = vendor_id2str(vendor);
+  if (vendorstr) {
+    sprintf(vendorbuf, "%s",vendorstr);
+  } 
+  devstr = device_id2str(vendor,dev);
+  if (devstr) {
+    sprintf(devbuf, "%s",devstr);
+  }
+}
+
+void amba_prinf_config(void)  
+{
+  char devbuf[128]; char vendorbuf[128]; unsigned int conf;
+  int i = 0; int j = 0; 
+  unsigned int addr; unsigned int m;
+  printk("             Vendors         Slaves\n");
+  printk("Ahb masters:\n");
+  i = 0;
+  while (i < amba_conf.ahbmst.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbmst, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbmst,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+        printk(" +%i: 0x%x \n", j, addr);
+      }
+    }
+    i++;
+  }
+  printk("Ahb slaves:\n");
+  i = 0;
+  while (i < amba_conf.ahbslv.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbslv,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+	if (amba_membar_type(m) == AMBA_TYPE_AHBIO) {
+	  addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	} else if (amba_membar_type(m) == AMBA_TYPE_APBIO) {
+	  printk("Warning: apbio membar\n");
+	}
+	printk(" +%i: 0x%x (raw:0x%x)\n", j, addr, m);
+      }
+    }
+    i++;
+  }
+  printk("Apb slaves:\n");
+  i = 0;
+  while (i < amba_conf.apbslv.devnr) 
+  {
+    
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    
+    m = amba_apb_get_membar(amba_conf.apbslv, i);
+    addr = amba_iobar_start(amba_conf.apbmst, m);
+    printk(" +%2i: 0x%x (raw:0x%x) \n", 0, addr, m);
+    
+    i++;
+    
+  }
+  
+}
+
+#define amba_insert_device(tab, address) \
+{ \
+  if (LEON3_BYPASS_LOAD_PA(address)) \
+  { \
+    (tab)->addr[(tab)->devnr] = (address); \
+    (tab)->devnr ++; \
+  } \
+} while(0)
+
+/*
+ *  Used to scan system bus. Probes for AHB masters, AHB slaves and 
+ *  APB slaves. Addresses to configuration areas of the AHB masters,
+ *  AHB slaves, APB slaves and APB master are storeds in 
+ *  amba_ahb_masters, amba_ahb_slaves and amba.
+ */
+
+void amba_init(void) 
+{
+  unsigned int *cfg_area;  /* address to configuration area */
+  unsigned int mbar, conf;
+  int i, j;
+  
+#ifdef DEBUG_CONFIG
+  printk("Reading AMBA Plug&Play configuration area\n");
+#endif
+
+  memset(&amba_conf,0,sizeof(amba_conf));
+  //amba_conf.ahbmst.devnr = 0; amba_conf.ahbslv.devnr = 0; amba_conf.apbslv.devnr = 0;
+  
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA);
+
+  for (i = 0; i < LEON3_AHB_MASTERS; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbmst, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }
+
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA | LEON3_AHB_SLAVE_CONF_AREA);
+  for (i = 0; i < LEON3_AHB_SLAVES; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbslv, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }  
+
+  for (i = 0; i < amba_conf.ahbslv.devnr; i ++) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    mbar = amba_ahb_get_membar(amba_conf.ahbslv, i, 0);
+    if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_APBMST))
+    {
+      amba_conf.apbmst = amba_membar_start(mbar);
+      cfg_area = (unsigned int *) (amba_conf.apbmst | LEON3_CONF_AREA);
+      
+      printk("Found apbmst, cfg: 0x%x\n",(unsigned int)cfg_area);
+      
+      for (j = amba_conf.apbslv.devnr; j < LEON3_APB_SLAVES; j++)
+      {
+	amba_insert_device(&amba_conf.apbslv, cfg_area);
+	cfg_area += LEON3_APB_CONF_WORDS;
+      }
+    }
+  }    
+ 
+  /* Find LEON3 Interrupt controler */
+  LEON3_IrqCtrl_Regs = (volatile LEON3_IrqCtrl_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_IRQMP, 0);
+  LEON3_GpTimer_Regs = (volatile LEON3_GpTimer_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_GPTIMER, &LEON3_GpTimer_Irq);
+  if (LEON3_IrqCtrl_Regs) {
+    LEON3_BYPASS_STORE_PA(&(LEON3_IrqCtrl_Regs ->mask[0]),0);
+  }
+}
+
+unsigned long amba_find_apbslv_addr(unsigned long vendor, unsigned long device, unsigned long *irq) {
+  unsigned int i,conf,iobar;
+  for (i = 0; i < amba_conf.apbslv.devnr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device))
+    {
+      if (irq) {
+        *irq = amba_irq(conf);
+      }
+      iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+      return amba_iobar_start(amba_conf.apbmst, iobar);
+    }
+  }
+  return 0;
+}
diff -Naur ../linux-2.6.10/drivers/amba/amba_driver.c linux-2.6.10/drivers/amba/amba_driver.c
--- ../linux-2.6.10/drivers/amba/amba_driver.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba_driver.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,78 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+extern amba_confarea_type amba_conf;
+ 
+//collect apb slaves
+int amba_get_free_apbslv_devices (int vendor, int device, amba_apb_device *dev,int nr) {
+  unsigned int i,conf,iobar,j = 0;
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: search for apdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.apbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.apbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Apbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.apbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+        iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+        dev[j].start = amba_iobar_start(amba_conf.apbmst, iobar);
+#ifdef DEBUG_CONFIG
+	printk(" +bar: 0x%x \n", k, dev[j].start);
+#endif
+        j++;
+      }
+    }
+  }
+  return j;
+}
+
+//collect ahb slaves
+int amba_get_free_ahbslv_devices (int vendor, int device, amba_ahb_device *dev,int nr) {
+  unsigned int addr, i,conf,iobar,j = 0,k;
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: search for ahdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.ahbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.ahbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Ahbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.ahbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+	for (k = 0; k < 4; k ++) {
+	  iobar = amba_ahb_get_membar(amba_conf.ahbslv, i, k);
+	  addr = amba_membar_start(iobar);
+	  if (amba_membar_type(iobar) == AMBA_TYPE_AHBIO) {
+	    addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	  }
+	  dev[j].start[k] = addr;
+#ifdef DEBUG_CONFIG
+	  printk(" +%i: 0x%x \n", k, dev[j].start[k]);
+#endif
+	}
+        j++;
+      }
+    }
+  }
+  return j;
+}
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Kconfig linux-2.6.10/drivers/amba/gaisler/Kconfig
--- ../linux-2.6.10/drivers/amba/gaisler/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,12 @@
+
+menu "Vendor Gaisler"
+
+config GRLIB_GAISLER_APBUART
+	bool "Grlib apbuart driver" 
+	default y
+	---help---
+	  Add the driver for the grlib apbuart serial core.
+
+endmenu
+
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Makefile linux-2.6.10/drivers/amba/gaisler/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_GAISLER_APBUART)		+= apbuart/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= apbuart.o
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,729 @@
+/*
+ *  linux/drivers/serial/leon.c
+ *
+ *  Driver for Leon serial ports
+ *
+ *  Based on linux/drivers/serial/amba.c , Documentation/serial/driver
+ * 
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ * 
+ *  Modified for Leon by Konrad Eisele <eiselekd@web.de>, 2003
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+
+#if defined(CONFIG_SERIAL_LEON_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <asm/leon.h>
+
+#define UART_NR		8
+int leon_ports_nr = 0;
+
+#define SERIAL_LEON_MAJOR	TTY_MAJOR
+#define SERIAL_LEON_MINOR	64
+#define SERIAL_LEON_NR		UART_NR
+
+#define AMBA_ISR_PASS_LIMIT	256
+
+#define APBBASE(port) ((LEON3_APBUART_Regs_Map *)((port)->membase))
+
+#define APBBASE_DATA_P(port) (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port)	(LEON_BYPASS_LOAD_PA(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v)	(LEON_BYPASS_STORE_PA(APBBASE_DATA_P(port),v))
+#define UART_GET_STATUS(port)	(LEON_BYPASS_LOAD_PA(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port,v)	(LEON_BYPASS_STORE_PA(APBBASE_STATUS_P(port),v))
+#define UART_GET_CTRL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_CTRL_P(port),v))
+#define UART_GET_SCAL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_SCALAR_P(port),v))
+#define UART_RX_DATA(s)       (((s) & LEON_REG_UART_STATUS_DR) != 0)
+#define UART_TX_READY(s)	(((s) & LEON_REG_UART_STATUS_THE) != 0)
+
+#define UART_DUMMY_RSR_RX	0x8000 /* for ignore all read */
+
+/* We wrap our port structure around the generic uart_port */
+struct uart_leon_port {
+	struct uart_port	port;
+	unsigned int		old_status;
+};
+
+static void leonuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port);
+static void leonuart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr |= LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+	
+	if (UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars (port);
+	}
+}
+
+static void leonuart_stop_rx(struct uart_port *port)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~(LEON_REG_UART_CTRL_RI);
+	UART_PUT_CTRL(port, cr);
+}
+
+static void leonuart_enable_ms(struct uart_port *port)
+{
+	/* no modem status for leon */
+}
+
+//static 
+void
+#ifdef SUPPORT_SYSRQ
+leonuart_rx_chars(struct uart_port *port, struct pt_regs *regs)
+#else
+leonuart_rx_chars(struct uart_port *port)
+#endif
+{
+	struct tty_struct *tty = port->info->tty;
+	unsigned int status, ch, rsr;
+
+	status = UART_GET_STATUS(port); 
+	if (UART_RX_DATA(status)) {
+      
+            if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.work.func((void *)tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+				return;
+			}
+		}
+
+		ch = UART_GET_CHAR(port); 
+
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = TTY_NORMAL;
+		port->icount.rx++;
+
+		/*
+		 * Note that the error handling code is
+		 * out of the main execution path
+		 */
+		rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX; 
+		UART_PUT_STATUS(port,0);
+		if (rsr & LEON_REG_UART_STATUS_ERR) { 
+
+		  if (rsr & LEON_REG_UART_STATUS_BR) {
+		    rsr &= ~(LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE);
+		    port->icount.brk++;
+		    if (uart_handle_break(port))
+		      goto ignore_char;
+		  } else if (rsr & LEON_REG_UART_STATUS_PE) {
+		    port->icount.parity++;
+		  } else if (rsr & LEON_REG_UART_STATUS_FE) {
+		    port->icount.frame++;
+		  }
+		  if (rsr & LEON_REG_UART_STATUS_OE)
+		    port->icount.overrun++;
+                  
+		  rsr &= port->read_status_mask;
+		  
+		  if (rsr & LEON_REG_UART_STATUS_PE)
+		    *tty->flip.flag_buf_ptr = TTY_PARITY;
+                  else if (rsr & LEON_REG_UART_STATUS_FE)
+		    *tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+            
+		if (uart_handle_sysrq_char(port, ch, regs))
+		    goto ignore_char;
+		
+		if ((rsr & port->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((rsr & LEON_REG_UART_STATUS_OE) &&
+		    tty->flip.count < TTY_FLIPBUF_SIZE) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.char_buf_ptr++ = 0;
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+			tty->flip.count++;
+		}
+	}
+ignore_char:
+	tty_flip_buffer_push(tty);
+	return;
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	int count;
+
+	if (port->x_char) {
+		UART_PUT_CHAR(port, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		leonuart_stop_tx(port, 0);
+		return;
+	}
+
+	count = port->fifosize >> 1; //amba: fill FIFO
+	do {
+		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		leonuart_stop_tx(port, 0);
+}
+
+//static 
+irqreturn_t leonuart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	unsigned int status;
+
+	spin_lock(port ->lock);
+
+	status = UART_GET_STATUS(port);
+	if (status & LEON_REG_UART_STATUS_DR) {
+#ifdef SUPPORT_SYSRQ
+	  leonuart_rx_chars(port,regs);
+#else
+	  leonuart_rx_chars(port);
+#endif          
+	}
+	if (status & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars(port);
+	}
+	spin_unlock(port ->lock);
+	return IRQ_HANDLED;
+}
+
+static unsigned int leonuart_tx_empty(struct uart_port *port)
+{
+	return UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int leonuart_get_mctrl(struct uart_port *port)
+{
+	unsigned int result = 0;
+
+	/*
+	  no modem status for leon
+	*/
+
+	return result;
+}
+
+static void leonuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* no modem status for leon */
+}
+
+static void leonuart_break_ctl(struct uart_port *port, int break_state)
+{
+	/* no break for leon */
+}
+
+static int leonuart_startup(struct uart_port *port)
+{
+	struct uart_leon_port *uap = (struct uart_leon_port *)port;
+	int retval;
+	unsigned int cr;
+
+	/*
+	 * Allocate the IRQ
+	 */
+	retval = request_irq(port->irq, leonuart_int, 0, "leon", port);
+	if (retval)
+		return retval;
+
+	/*
+	 * initialise the old status of the modem signals
+	 */
+	uap->old_status = 0;
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr | LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI );	
+      
+	return 0;
+}
+
+static void leonuart_shutdown(struct uart_port *port)
+{
+	unsigned int cr;
+
+	/*
+	 * Free the interrupt
+	 */
+	free_irq(port->irq, port);
+
+	/*
+	 * disable all interrupts, disable the port
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr & ~( LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI ));	
+      
+}
+
+static void
+leonuart_set_termios(struct uart_port *port, struct termios *termios,
+		     struct termios *old)
+{
+	unsigned int cr;
+	unsigned long flags;
+	unsigned int baud, quot;
+
+	/*
+	 * Ask the core to calculate the divisor for us.
+	 */
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	if (baud == 0) {
+	  panic("invalid baudrate %i\n", port->uartclk/16);
+	}
+	quot = (uart_get_divisor(port, baud)) * 2; //uart_get_divisor calc a *16 uart freq, leon is *8
+	cr = UART_GET_CTRL(port);
+	cr &= ~( LEON_REG_UART_CTRL_PE | LEON_REG_UART_CTRL_PS );
+	  
+	if (termios->c_cflag & PARENB) { 
+		cr |= LEON_REG_UART_CTRL_PE; 
+		if ((termios->c_cflag & PARODD))
+			cr |= LEON_REG_UART_CTRL_PS;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/*
+	 * Update the per-port timeout.
+	 */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	port->read_status_mask = LEON_REG_UART_STATUS_OE;
+	if (termios->c_iflag & INPCK) 
+		port->read_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE ;
+
+	/*
+	 * Characters to ignore
+	 */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_OE | LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/* Set baud rate */
+	quot -= 1;
+	UART_PUT_SCAL(port, quot);
+	UART_PUT_CTRL(port, cr);
+      
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *leonuart_type(struct uart_port *port)
+{
+	return port->type == PORT_LEON ? "Leon" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void leonuart_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int leonuart_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void leonuart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_LEON;
+		leonuart_request_port(port);
+	}
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int leonuart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_LEON)
+		ret = -EINVAL;
+	if (ser->irq < 0 || ser->irq >= NR_IRQS)
+		ret = -EINVAL;
+	if (ser->baud_base < 9600)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops leon_pops = {
+	.tx_empty	= leonuart_tx_empty,
+	.set_mctrl	= leonuart_set_mctrl,
+	.get_mctrl	= leonuart_get_mctrl,
+	.stop_tx	= leonuart_stop_tx,
+	.start_tx	= leonuart_start_tx,
+	.stop_rx	= leonuart_stop_rx,
+	.enable_ms	= leonuart_enable_ms,
+	.break_ctl	= leonuart_break_ctl,
+	.startup	= leonuart_startup,
+	.shutdown	= leonuart_shutdown,
+	.set_termios	= leonuart_set_termios,
+	.type		= leonuart_type,
+	.release_port	= leonuart_release_port,
+	.request_port	= leonuart_request_port,
+	.config_port	= leonuart_config_port,
+	.verify_port	= leonuart_verify_port,
+};
+
+static struct uart_leon_port leon_ports[UART_NR];
+/* = {
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART0),
+			.mapbase	= (LEON_PREGS+LEON_UART0),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_0_RX_TX,
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+	},
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART1),
+			.mapbase	= (LEON_PREGS+LEON_UART1),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_1_RX_TX, 
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+	}
+};*/
+
+extern volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs;
+
+/* rs_init inits the driver */
+static int _apbuart_init_bases_done = 0;
+static void __init 
+_apbuart_init_bases(void)
+{
+  int  i; 
+  amba_apb_device dev[8];
+  if (!_apbuart_init_bases_done ) {
+    unsigned long clk = ((unsigned long)(((LEON3_BYPASS_LOAD_PA(&LEON3_GpTimer_Regs->scalar_reload)) + 1))); 
+    printk("Attaching grlib apbuart serial drivers (clk:%ihz):\n",(int)clk);
+    leon_ports_nr = amba_get_free_apbslv_devices (VENDOR_GAISLER, GAISLER_APBUART, dev, 8);
+
+    for (i = 0;i < leon_ports_nr;i++) {
+      leon_ports[i].port.membase = (void *)dev[i].start;
+      leon_ports[i].port.mapbase = dev[i].start;
+      leon_ports[i].port.irq = dev[i].irq;
+      leon_ports[i].port.iotype = SERIAL_IO_MEM;
+      leon_ports[i].port.uartclk = clk * 1000 * 1000;
+      leon_ports[i].port.fifosize = 1;
+      leon_ports[i].port.ops	= &leon_pops;
+      leon_ports[i].port.flags = ASYNC_BOOT_AUTOCONF;
+      leon_ports[i].port.line =i;
+    }
+    _apbuart_init_bases_done = 1;
+  }
+}
+
+
+#ifdef CONFIG_SERIAL_LEON_CONSOLE
+
+static void
+leonuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_port *port = &leon_ports[co->index].port;
+	unsigned int status, old_cr;
+	int i;
+
+	/*
+	 *	First save the CR then disable the interrupts
+	 */
+	old_cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, (old_cr & ~(LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI)) | (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE) ); 
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++) {
+		do {
+			status = UART_GET_STATUS(port);
+		} while (!UART_TX_READY(status));
+		UART_PUT_CHAR(port, s[i]);
+		if (s[i] == '\n') {
+			do {
+				status = UART_GET_STATUS(port);
+			} while (!UART_TX_READY(status));
+			UART_PUT_CHAR(port, '\r');
+		}
+	}
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore the TCR
+	 */
+	do {
+		status = UART_GET_STATUS(port);
+	} while (!UART_TX_READY(status));
+	UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+leonuart_console_get_options(struct uart_port *port, int *baud,
+			     int *parity, int *bits)
+{
+      if (UART_GET_CTRL(port) & (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE)) {
+	
+		unsigned int quot, status;
+		status = UART_GET_STATUS(port);
+
+		*parity = 'n';
+		if (status & LEON_REG_UART_CTRL_PE) {
+			if ((status & LEON_REG_UART_CTRL_PS) == 0 )
+				*parity = 'e';
+			else
+				*parity = 'o';
+		}
+            
+		*bits = 8;
+            quot = UART_GET_SCAL(port) / 8;
+		*baud = port->uartclk / (16 * (quot + 1));
+	}
+}
+
+static int __init leonuart_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 38400;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	/*
+	 * Check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	if (co->index >= leon_ports_nr)
+		co->index = 0;
+	port = &leon_ports[co->index].port;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		leonuart_console_get_options(port, &baud, &parity, &bits);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+static struct uart_driver leon_reg;
+static struct console leon_console = {
+	.name		= "ttyS",
+	.write		= leonuart_console_write,
+	.device		= uart_console_device,
+	.setup		= leonuart_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &leon_reg,
+};
+
+//static int leonuart_init(void);
+static int __init leonuart_console_init(void)
+{
+	_apbuart_init_bases();
+	register_console(&leon_console);
+	return 0;
+}
+console_initcall(leonuart_console_init);
+
+#define LEON_CONSOLE	&leon_console
+#else
+#define LEON_CONSOLE	NULL
+#endif
+
+static struct uart_driver leon_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "serial",
+	.devfs_name	= "tts/",
+	.dev_name	= "ttyS",
+	.major		= SERIAL_LEON_MAJOR,
+	.minor		= SERIAL_LEON_MINOR,
+	.nr		= UART_NR,
+	.cons		= LEON_CONSOLE,
+};
+
+
+static int __init gaisler_apbuart_init(void)
+{
+	int ret;
+	int i;
+	int node;
+	int freq_khz;
+	int baud_rates[UART_NR];
+
+	_apbuart_init_bases();
+	node = prom_getchild(prom_root_node);
+	freq_khz = prom_getint(node, "frequency");
+	
+	printk(KERN_INFO "grlib apbuart: %i serial driver(s) at [",leon_ports_nr);
+	for (i = 0; i < leon_ports_nr; i++) {
+	  baud_rates[i] = prom_getintdefault(node, "uart1_baud", 9600);
+	  if (i != 0) {printk(",");}
+	  printk("0x%x",(unsigned int) leon_ports[i].port.mapbase);
+	  printk("(irq %i)",leon_ports[i].port.irq);
+	}
+	printk("]\n");
+
+	baud_rates[0] = prom_getintdefault(node, "uart1_baud", 9600);
+	baud_rates[1] = prom_getintdefault(node, "uart2_baud", 9600);
+
+	printk(KERN_INFO "grlib apbuart: system frequency: %i khz, baud rates: %i %i\n", freq_khz, baud_rates[0], baud_rates[1]);
+
+	ret = uart_register_driver(&leon_reg);
+	leon_reg.tty_driver->init_termios.c_cflag = 
+		(leon_reg.tty_driver->init_termios.c_cflag & ~CBAUD) | B38400;
+	
+	if (ret) return ret;
+
+	for (i = 0; i < leon_ports_nr; i++) {
+		struct console co;
+		leon_ports[i].port.uartclk = freq_khz * 1000;
+		uart_add_one_port(&leon_reg, &leon_ports[i].port);
+		uart_set_options(&leon_ports[i].port, &co,
+				 baud_rates[i], 'n', 8, 'n');
+	}
+
+	return ret;
+}
+
+static void __exit gaisler_apbuart_exit(void)
+{
+	int i;
+
+	for (i = 0; i < leon_ports_nr; i++)
+		uart_remove_one_port(&leon_reg, &leon_ports[i].port);
+
+	uart_unregister_driver(&leon_reg);
+}
+
+module_init(gaisler_apbuart_init);
+module_exit(gaisler_apbuart_exit);
+
+MODULE_AUTHOR("Konrad Eisele<eiselekd@web.de>, based on AMBA serial");
+MODULE_DESCRIPTION("grlib apbuart serial driver");
+MODULE_LICENSE("GPL");
+
+
+
+
+
+void leon3_rs_put_char_base(LEON3_APBUART_Regs_Map *uart_regs,char ch)
+{
+        int flags, loops;
+
+        save_flags(flags); cli();
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_THE) && (loops < 100000))
+        	loops++;
+
+	LEON3_BYPASS_STORE_PA(&(uart_regs->data),ch);
+
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_TSE) && (loops < 100000))
+        	loops++;
+        restore_flags(flags);
+}
+
+void leon3_rs_put_char(char ch)
+{
+  LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+  if (b) {
+    leon3_rs_put_char_base(b,ch);
+  }
+}
+
+void console_print_LEON(const char *p)
+{
+	char c;
+
+        LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+        
+	while((c=*(p++)) != 0) {
+          if(c == '\n')
+            leon3_rs_put_char_base(b,'\r');
+          leon3_rs_put_char_base(b,c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	/* rs_fair_output(); */
+
+	return;
+}
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Kconfig linux-2.6.10/drivers/amba/opencores/Kconfig
--- ../linux-2.6.10/drivers/amba/opencores/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,36 @@
+
+menu "Vendor Opencores"
+
+config GRLIB_OPENCORES_ETHERMAC
+	bool "Grlib's opencores ethermac driver" 
+	default y
+	depends on NETDEVICES
+	---help---
+	  Add the driver for the grlib opencore ethermac.
+
+
+config GRLIB_OPENCORES_ETHERMAC_MACMSB
+	hex "MSB 24 bits of ethern number (hex)" 
+	default 00007A
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Most significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is 00007A.
+
+config GRLIB_OPENCORES_ETHERMAC_MACLSB
+	hex "LSB 24 bits of ethern number (hex)" 
+	default CC0012
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Least significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is CC0012.
+
+
+
+
+endmenu
+
+
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Makefile linux-2.6.10/drivers/amba/opencores/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_OPENCORES_ETHERMAC)		+= ethermac/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile linux-2.6.10/drivers/amba/opencores/ethermac/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= open_eth.o
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,1181 @@
+/*
+ * Ethernet driver for Open Ethernet Controller (www.opencores.org).
+ *      Copyright (c) 2002 Simon Srot (simons@opencores.org)
+ *
+ * Based on:
+ *
+ * Ethernet driver for Motorola MPC8xx.
+ *      Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * mcen302.c: A Linux network driver for Mototrola 68EN302 MCU
+ *
+ *      Copyright (C) 1999 Aplio S.A. Written by Vadim Lebedev
+ *
+ * Right now XXBUFF_PREALLOC must be used, because MAC does not 
+ * handle unaligned buffers yet.  Also the cache inhibit calls
+ * should be used some day.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/cacheflush.h>
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/rtnetlink.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <asm/processor.h>	/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+ 
+#ifdef CONFIG_LEON
+#include <asm/leon.h>
+//#define OETH_INTERRUPT LEON_INTERRUPT_OPEN_ETH
+#define DEBUG 1
+#endif
+
+/*
+#define MACADDR1 0
+#define MACADDR2 0
+#define MACADDR3 0
+#define MACADDR4 0
+#define MACADDR5 0
+*/
+ 
+#define MACADDR0 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 16) & 0xff)
+#define MACADDR1 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 8) & 0xff)
+#define MACADDR2 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 0) & 0xff)
+#define MACADDR3 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 16) & 0xff)
+#define MACADDR4 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 8) & 0xff)
+#define MACADDR5 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 0) & 0xff)
+
+#include "open_eth.h"
+
+//#define net_device device
+//#define __pa(x) (x)
+//#define __va(x) (x)
+#define __clear_user(add,len) memset((add),0,(len))
+
+
+#define RXBUFF_PREALLOC	1
+#define TXBUFF_PREALLOC	1
+
+//#define SRAM_BUFF	1
+//#define SRAM_BUFF_BASE	(FBMEM_BASE_ADD + 0x80000)
+
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT	(2*HZ)
+
+/* Buffer number (must be 2^n) 
+ */
+#define OETH_RXBD_NUM		8
+#define OETH_TXBD_NUM		8
+#define OETH_RXBD_NUM_MASK	(OETH_RXBD_NUM-1)
+#define OETH_TXBD_NUM_MASK	(OETH_TXBD_NUM-1)
+
+/* Buffer size 
+ */
+#define OETH_RX_BUFF_SIZE	2048
+#define OETH_TX_BUFF_SIZE	2048
+
+/* How many buffers per page 
+ */
+#define OETH_RX_BUFF_PPGAE	(PAGE_SIZE/OETH_RX_BUFF_SIZE)
+#define OETH_TX_BUFF_PPGAE	(PAGE_SIZE/OETH_TX_BUFF_SIZE)
+
+/* How many pages is needed for buffers 
+ */
+#define OETH_RX_BUFF_PAGE_NUM	(OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE)
+#define OETH_TX_BUFF_PAGE_NUM	(OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE)
+
+/* Buffer size  (if not XXBUF_PREALLOC 
+ */
+#define MAX_FRAME_SIZE		1518
+
+/* The buffer descriptors track the ring buffers.   
+ */
+struct oeth_private {
+	struct	sk_buff* rx_skbuff[OETH_RXBD_NUM];
+	struct	sk_buff* tx_skbuff[OETH_TXBD_NUM];
+
+	ushort	tx_next;			/* Next buffer to be sent */
+	ushort	tx_last;			/* Next buffer to be checked if packet sent */
+	ushort	tx_full;			/* Buffer ring fuul indicator */
+	ushort	rx_cur;				/* Next buffer to be checked if packet received */
+
+	oeth_regs	*regs;			/* Address of controller registers. */
+	oeth_bd		*rx_bd_base;		/* Address of Rx BDs. */
+	oeth_bd		*tx_bd_base;		/* Address of Tx BDs. */
+        ushort          irq;
+
+	struct net_device_stats stats;
+};
+
+static int oeth_open(struct net_device *dev);
+static int oeth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void oeth_rx(struct net_device *dev);
+static void oeth_tx(struct net_device *dev);
+static irqreturn_t oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int oeth_close(struct net_device *dev);
+static struct net_device_stats *oeth_get_stats(struct net_device *dev);
+static void oeth_set_multicast_list(struct net_device *dev);
+static int oeth_set_mac_address(struct net_device *dev,void *p);
+static int calc_crc(char *mac_addr);
+
+#define OETH_REGLOAD(a)	(LEON3_BYPASS_LOAD_PA(&(a)))
+#define OETH_REGSAVE(a,v) (LEON3_BYPASS_STORE_PA(&(a),v))
+#define OETH_REGORIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) | (v))))
+#define OETH_REGANDIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) & (v))))
+
+
+#if DEBUG
+static void
+oeth_print_packet(unsigned long add, int len)
+{
+  //	int i;
+
+	printk("ipacket: add = %x len = %d\n", (unsigned int)add, len);
+/*
+	for(i = 0; i < len; i++) {
+  		if(!(i % 16))
+    			printk("\n");
+  		printk(" %.2x", *(((unsigned char *)add) + i));
+	}
+*/
+      printk("\n");
+	printk("                             \n");
+}
+#endif
+
+static int
+oeth_open(struct net_device *dev)
+{
+
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	
+#if DEBUG
+	printk("oeth_open\n");
+#endif
+#ifndef RXBUFF_PREALLOC
+	struct  sk_buff *skb;
+	volatile oeth_bd *rx_bd;
+	int i;
+
+	rx_bd = cep->rx_bd_base;
+
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+		skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+		if (skb == NULL)
+      		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+		else
+		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = skb;
+
+		OETH_REGSAVE(rx_bd[i].addr,(unsigned long)skb->tail);
+		//rx_bd[i].addr = (unsigned long)skb->tail;
+	}
+        OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+#endif
+
+	/* Install our interrupt handler.
+	 */
+	request_irq(cep->irq, oeth_interrupt, 0, "eth", (void *)dev);
+
+	/* Enable receiver and transmiter 
+	 */
+        OETH_REGORIN(regs->moder , OETH_MODER_RXEN | OETH_MODER_TXEN);
+	//regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
+
+	return 0;
+}
+
+static int
+oeth_close(struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	volatile oeth_bd *bdp;
+	int i;
+
+#if DEBUG
+	printk("oeth_close\n");
+#endif
+	/* Free interrupt hadler 
+	 */
+	free_irq(cep->irq, (void *)dev);
+
+	/* Disable receiver and transmitesr 
+	 */
+        OETH_REGANDIN(regs->moder , ~(OETH_MODER_RXEN | OETH_MODER_TXEN));
+	//regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);	
+
+	bdp = cep->rx_bd_base;
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status, ~(OETH_TX_BD_STATS | OETH_TX_BD_READY));
+		//bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
+		bdp++;
+	}
+
+	bdp = cep->tx_bd_base;
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status , ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY));
+		//bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
+		bdp++;
+	}
+
+#ifndef RXBUFF_PREALLOC
+
+	/* Free all alocated rx buffers 
+	 */
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	
+		if (cep->rx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->rx_skbuff[i]); //, FREE_READ);
+		
+	}
+#endif
+#ifndef TXBUFF_PREALLOC
+
+	/* Free all alocated tx buffers 
+	 */
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	
+		if (cep->tx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->tx_skbuff[i]);//, FREE_WRITE);
+	}
+#endif
+
+	return 0;
+}
+
+static int
+oeth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	volatile oeth_bd *bdp;
+	unsigned long flags;
+
+	/* Fill in a Tx ring entry 
+	 */
+	bdp = cep->tx_bd_base + cep->tx_next;
+
+	if (cep->tx_full) {
+
+		/* All transmit buffers are full.  Bail out.
+		 */
+		printk("%s: tx queue full!.\n", dev->name);
+		return 1;
+	}
+
+	/* Clear all of the status flags.
+	 */
+	OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_STATS);
+	//bdp->len_status &= ~OETH_TX_BD_STATS;
+
+	/* If the frame is short, tell CPM to pad it.
+	 */
+	if (skb->len <= ETH_ZLEN)
+	        OETH_REGORIN(bdp->len_status , OETH_TX_BD_PAD);
+	        //bdp->len_status |= OETH_TX_BD_PAD;
+	else
+	        OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_PAD);
+	        //bdp->len_status &= ~OETH_TX_BD_PAD;
+
+#if DEBUG
+	printk("TX\n");
+	oeth_print_packet((unsigned long)skb->data, skb->len);
+#endif
+
+#ifdef TXBUFF_PREALLOC
+
+	/* Copy data in preallocated buffer */
+	if (skb->len > OETH_TX_BUFF_SIZE) {
+		printk("%s: tx frame too long!.\n", dev->name);
+		return 1;
+	}
+	else {
+	  
+	  memcpy(__va((unsigned char *)OETH_REGLOAD(bdp->addr)), skb->data, skb->len); 
+            __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+	    //memcpy(__va((unsigned char *)bdp->addr), skb->data, skb->len); 
+            //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+      }
+
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16));
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+
+	dev_kfree_skb(skb); // 	dev_kfree_skb(skb, FREE_WRITE);
+#else
+	/* Set buffer length and buffer pointer.
+	 */
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16))
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+	OETH_REGSAVE(bdp->addr , (uint)__pa(skb->data));
+	//bdp->addr = (uint)__pa(skb->data);
+
+	/* Save skb pointer.
+	 */
+	cep->tx_skbuff[cep->tx_next] = skb;
+#endif
+
+	cep->tx_next = (cep->tx_next + 1) & OETH_TXBD_NUM_MASK;
+	
+	save_flags(flags); cli();
+
+	if (cep->tx_next == cep->tx_last)
+		cep->tx_full = 1;
+
+	/* Send it on its way.  Tell controller its ready, interrupt when done,
+	 * and to put the CRC on the end.
+	 */
+        OETH_REGORIN(bdp->len_status , (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC));
+	//bdp->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
+
+	dev->trans_start = jiffies;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The interrupt handler.
+ */
+static irqreturn_t
+oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct	net_device *dev = dev_id;
+	volatile struct	oeth_private *cep;
+	uint	int_events;
+      
+#if DEBUG
+      printk ("oeth_interrupt()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get the interrupt events that caused us to be here.
+	 */
+        int_events = OETH_REGLOAD( cep->regs->int_src);
+	//int_events = cep->regs->int_src;
+        OETH_REGSAVE(cep->regs->int_src , int_events);
+	//cep->regs->int_src = int_events;
+
+	/* Handle receive event in its own function.
+	 */
+	if (int_events & (OETH_INT_RXF | OETH_INT_RXE))
+		oeth_rx(dev_id);
+
+	/* Handle transmit event in its own function.
+	 */
+	if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
+		oeth_tx(dev_id);
+            netif_wake_queue(dev); //mark_bh(NET_BH);
+	}
+
+	/* Check for receive busy, i.e. packets coming but no place to
+	 * put them. 
+	 */
+	if (int_events & OETH_INT_BUSY) {
+		if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE)))
+			oeth_rx(dev_id);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static void
+oeth_tx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+
+#ifndef TXBUFF_PREALLOC
+	struct	sk_buff *skb;
+#endif
+
+#if DEBUG
+      printk ("oeth_tx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) {
+
+		bdp = cep->tx_bd_base + cep->tx_last;
+
+		if ((OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_READY) || 
+		//if ((bdp->len_status & OETH_TX_BD_READY) || 
+			((cep->tx_last == cep->tx_next) && !cep->tx_full))
+			break;
+
+		/* Check status for errors
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+
+		/* Check status for errors
+		 */
+                /*
+		if (bdp->len_status & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (bdp->len_status & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (bdp->len_status & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (bdp->len_status & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (bdp->len_status & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+		*/
+
+		cep->stats.tx_packets++;
+		cep->stats.collisions += (OETH_REGLOAD(bdp->len_status) >> 4) & 0x000f;
+		//cep->stats.collisions += (bdp->len_status >> 4) & 0x000f;
+
+#ifndef TXBUFF_PREALLOC
+		skb = cep->tx_skbuff[cep->tx_last];
+
+		/* Free the sk buffer associated with this last transmit.
+		*/
+		dev_kfree_skb(skb);//, FREE_WRITE);
+#endif
+
+		if (cep->tx_full)
+			cep->tx_full = 0;
+	}
+}
+
+static void
+oeth_rx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+	struct	sk_buff *skb;
+	int	pkt_len;
+	int	bad = 0;
+#ifndef RXBUFF_PREALLOC
+	struct	sk_buff *small_skb;
+#endif
+      
+#if DEBUG
+      printk ("oeth_rx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* First, grab all of the stats for the incoming packet.
+	 * These get messed up if we get called due to a busy condition.
+	 */
+	for (;;cep->rx_cur = (cep->rx_cur + 1) & OETH_RXBD_NUM_MASK) {
+
+		bdp = cep->rx_bd_base + cep->rx_cur;
+
+#ifndef RXBUFF_PREALLOC
+		skb = cep->rx_skbuff[cep->rx_cur];
+
+		if (skb == NULL) {
+
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			if (skb != NULL)
+			{
+				OETH_REGSAVE(bdp->addr , (unsigned long) skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long) skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+
+			continue;
+		}
+#endif
+			
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_EMPTY)
+		//if (bdp->len_status & OETH_RX_BD_EMPTY)
+			break;
+			
+		/* Check status for errors.
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+		//if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+                  printk ("oeth: length error\n");
+			cep->stats.rx_length_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_DRIBBLE) {
+		//if (bdp->len_status & OETH_RX_BD_DRIBBLE) {
+                  printk ("oeth: dribble error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_CRCERR) {
+		//if (bdp->len_status & OETH_RX_BD_CRCERR) {
+                  printk ("oeth: crc error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_OVERRUN) {
+		//if (bdp->len_status & OETH_RX_BD_OVERRUN) {
+                  printk ("oeth: overrun error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_MISS) {
+		//if (bdp->len_status & OETH_RX_BD_MISS) {
+                  printk ("oeth: miss error\n");
+
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_LATECOL) {
+		//if (bdp->len_status & OETH_RX_BD_LATECOL) {
+                  printk ("oeth: latecol error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		
+		
+		if (bad) {
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+      //bdp->len_status &= ~OETH_RX_BD_STATS;
+      //bdp->len_status |= OETH_RX_BD_EMPTY;
+
+			continue;
+		}
+
+		/* Process the incoming frame.
+		 */
+		pkt_len = OETH_REGLOAD(bdp->len_status) >> 16;
+		//pkt_len = bdp->len_status >> 16;
+        
+#ifdef RXBUFF_PREALLOC
+		//skb = dev_alloc_skb(pkt_len);
+                skb = alloc_skb(pkt_len + 4, GFP_ATOMIC); //added from michael wurm's patches
+
+		if (skb == NULL) {
+			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+			cep->stats.rx_dropped++;
+		}
+		else {
+			skb_reserve(skb, 2); //added from michael wurm's patches
+			skb->dev = dev;
+
+                  __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+                  //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+#if DEBUG
+			printk("RX\n");
+                  oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), pkt_len);
+                  //oeth_print_packet((unsigned long)(__va(bdp->addr)), pkt_len);
+#endif
+			memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+			//memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+		}
+
+		OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+		OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+		//bdp->len_status &= ~OETH_RX_BD_STATS;
+		//bdp->len_status |= OETH_RX_BD_EMPTY;
+#else //RXBUFF_PREALLOC
+
+		if (pkt_len < 128) {
+
+			small_skb = dev_alloc_skb(pkt_len);
+
+			if (small_skb) {
+				small_skb->dev = dev;
+
+                        __flush_page_to_ram(__va(OETH_REGLOAD(bdp->addr)));
+                        //__flush_page_to_ram(__va(bdp->addr));
+#if DEBUG
+				printk("RX short\n");
+                        oeth_print_packet((unsigned long)(__va(bdp->addr)), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+                        memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+                        //memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+
+                        small_skb->protocol = eth_type_trans(small_skb,dev);
+                        netif_rx(small_skb);
+				cep->stats.rx_packets++;
+			}
+			else {
+				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+	                        cep->stats.rx_dropped++;
+			}
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+			//bdp->len_status |= OETH_RX_BD_EMPTY;
+		}
+		else {
+        		skb->dev = dev;
+			skb_put(skb, OETH_REGLOAD(bdp->len_status) >> 16);
+			//skb_put(skb, bdp->len_status >> 16);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+#if DEBUG
+			printk("RX long\n");
+                        oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+		
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+        
+			if (skb) {
+				cep->rx_skbuff[cep->rx_cur] = skb;
+
+				OETH_REGSAVE(bdp->addr , (unsigned long)skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long)skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+			else {
+				cep->rx_skbuff[cep->rx_cur] = NULL;	
+			}
+		}
+#endif //!RXBUFF_PREALLOC
+	}
+
+#if DEBUG
+      printk ("oeth_rx sent()\n");
+#endif
+}
+
+static int calc_crc(char *mac_addr)
+{
+	int result = 0;
+	return (result & 0x3f);
+}
+
+static struct net_device_stats *oeth_get_stats(struct net_device *dev)
+{
+        struct oeth_private *cep = (struct oeth_private *)dev->priv;
+ 
+        return &cep->stats;
+}
+
+static void oeth_set_multicast_list(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	struct	dev_mc_list *dmi;
+	volatile oeth_regs *regs;
+	int	i;
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get pointer of controller registers.
+	 */
+	regs = (oeth_regs *)dev->base_addr;
+
+	if (dev->flags & IFF_PROMISC) {
+	  
+		/* Log any net taps. 
+		 */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		OETH_REGORIN(regs->moder , OETH_MODER_PRO);
+		//regs->moder |= OETH_MODER_PRO;
+	} else {
+
+		OETH_REGANDIN(regs->moder , ~OETH_MODER_PRO);
+		//regs->moder &= ~OETH_MODER_PRO;
+
+		if (dev->flags & IFF_ALLMULTI) {
+
+			/* Catch all multicast addresses, so set the
+			 * filter to all 1's.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0xffffffff);
+			OETH_REGSAVE(regs->hash_addr1 , 0xffffffff);
+			//regs->hash_addr0 = 0xffffffff;
+			//regs->hash_addr1 = 0xffffffff;
+		}
+		else if (dev->mc_count) {
+
+                        OETH_REGORIN(regs->moder , OETH_MODER_IAM);
+                        //regs->moder |= OETH_MODER_IAM;
+                        
+			/* Clear filter and add the addresses in the list.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			//regs->hash_addr0 = 0x00000000;
+			//regs->hash_addr0 = 0x00000000;
+
+			dmi = dev->mc_list;
+
+			for (i = 0; i < dev->mc_count; i++) {
+				
+				int hash_b;
+
+				/* Only support group multicast for now.
+				 */
+				if (!(dmi->dmi_addr[0] & 1))
+					continue;
+
+				hash_b = calc_crc(dmi->dmi_addr); 
+				if(hash_b >= 32)
+					OETH_REGORIN(regs->hash_addr1 , 1 << (hash_b - 32));
+				        //regs->hash_addr1 |= 1 << (hash_b - 32);
+				else
+					OETH_REGORIN(regs->hash_addr0 , 1 << hash_b);
+				        //regs->hash_addr0 |= 1 << hash_b;
+			}
+		}
+	}
+}
+
+static int oeth_set_mac_address(struct net_device *dev,void *p)
+{
+	struct sockaddr *addr=p;
+	volatile oeth_regs *regs;
+      
+	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+      
+	regs = (oeth_regs *)dev->base_addr;
+      
+    
+	    
+// old version: sa_data is of type char, will be expanded to int when ored
+// so negative values e.g 0xB5 will be expanded to 0xffffffB5 and ored
+/*
+	regs->mac_addr1 = 	addr->sa_data[0] << 8 	|
+            			addr->sa_data[1];
+        regs->mac_addr0 = 	addr->sa_data[2] << 24 	|
+            			addr->sa_data[3] << 16 	|
+            			addr->sa_data[4] << 8 	|
+            			addr->sa_data[5];
+
+*/
+
+// dev_addr is of type unsigned char and will be expanded to unsigned int which is ok
+	OETH_REGSAVE(regs->mac_addr1 , 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1]);
+        OETH_REGSAVE(regs->mac_addr0 , 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5]);
+
+	/*	    
+	regs->mac_addr1 = 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1];
+        regs->mac_addr0 = 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5];
+	*/  
+	    
+	    
+	return 0;
+}
+
+/* Initialize the Open Ethernet MAC.
+ */
+int do_oeth_probe(struct net_device *dev)
+{
+	struct oeth_private *cep;
+	volatile oeth_regs *regs;
+	volatile oeth_bd *tx_bd, *rx_bd;
+	int i, j, k, l;
+#ifdef SRAM_BUFF
+	unsigned long mem_addr = SRAM_BUFF_BASE;
+#else
+	unsigned long mem_addr;
+#endif
+	unsigned long base;
+
+	amba_ahb_device adev[1];
+	l = amba_get_free_ahbslv_devices (VENDOR_GAISLER, GAISLER_ETHAHB, adev, 1);
+	if (l == 0) {
+	  return 1;
+	}
+	
+	base = adev[0].start[0];
+
+	//printk("Probing Open Ethernet Core at 0x%x (irq:%i,n:%s)\n",adev[0].start[0], adev[0].irq, dev ->name);
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Allocate a new 'dev' if needed. 
+	 */
+	if (dev == NULL) {
+		/*
+		 * Don't allocate the private data here, it is done later
+		 * This makes it easier to free the memory when this driver
+		 * is used as a module.
+		 */
+//		dev = init_etherdev(0, 0);
+                dev=alloc_etherdev(0);		
+//		dev = alloc_netdev(0, "eth0", setup_ether);
+		if (dev == NULL)
+			return -ENOMEM;
+	}
+
+
+
+
+	/* Initialize the device structure. 
+	 */
+	if (dev->priv == NULL) {
+		cep = (struct oeth_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+		dev->priv = cep;
+		if (dev->priv == NULL)
+			return -ENOMEM;
+	}
+	
+	__clear_user(cep,sizeof(*cep));
+
+	/* Get pointer ethernet controller configuration registers.
+	 */
+	cep->regs = (oeth_regs *)(OETH_REG_BASE(base));
+	regs = (oeth_regs *)(OETH_REG_BASE(base));
+	cep->irq = adev[0].irq;
+
+	/* Reset the controller.
+	 */
+	OETH_REGSAVE(regs->moder , OETH_MODER_RST);	/* Reset ON */
+	OETH_REGANDIN(regs->moder , ~OETH_MODER_RST);	/* Reset OFF */
+	//regs->moder = OETH_MODER_RST;	/* Reset ON */
+	//regs->moder &= ~OETH_MODER_RST;	/* Reset OFF */
+
+	/* Setting TXBD base to OETH_TXBD_NUM.
+	 */
+	OETH_REGSAVE(regs->tx_bd_num , OETH_TXBD_NUM);
+	//regs->tx_bd_num = OETH_TXBD_NUM;
+	
+	/* Initialize TXBD pointer
+	 */
+	cep->tx_bd_base = (oeth_bd *)OETH_BD_BASE(base);
+	tx_bd = (volatile oeth_bd *)OETH_BD_BASE(base);
+
+	/* Initialize RXBD pointer
+	 */
+	cep->rx_bd_base = ((oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+	rx_bd = ((volatile oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+
+	/* Initialize transmit pointers.
+	 */
+	cep->rx_cur = 0;
+	cep->tx_next = 0;
+	cep->tx_last = 0;
+	cep->tx_full = 0;
+
+	/* Set min/max packet length 
+	 */
+	OETH_REGSAVE(regs->packet_len , 0x00400600);
+	//regs->packet_len = 0x00400600;
+
+	/* Set IPGT register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgt , 0x00000012);
+	//regs->ipgt = 0x00000012;
+
+	/* Set IPGR1 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr1 , 0x0000000c);
+	//regs->ipgr1 = 0x0000000c;
+
+	/* Set IPGR2 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr2 , 0x00000012);
+	//regs->ipgr2 = 0x00000012;
+
+	/* Set COLLCONF register to recomended value 
+	 */
+	OETH_REGSAVE(regs->collconf , 0x000f003f);
+	//regs->collconf = 0x000f003f;
+
+	/* Set control module mode 
+	 */
+#if 0
+	OETH_REGSAVE(regs->ctrlmoder , OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW);
+	//regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW;
+#else
+	OETH_REGSAVE(regs->ctrlmoder , 0);
+	//regs->ctrlmoder = 0;
+#endif
+
+  /* Set PHY to show Tx status, Rx status and Link status */
+  /*regs->miiaddress = 20<<8;
+  regs->miitx_data = 0x1422;
+  regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;*/
+ 
+  // switch to 10 mbit ethernet
+  OETH_REGSAVE(regs->miiaddress , 0);
+  OETH_REGSAVE(regs->miitx_data , 0);
+  OETH_REGSAVE(regs->miicommand , OETH_MIICOMMAND_WCTRLDATA);
+  //regs->miiaddress = 0;
+  //regs->miitx_data = 0;
+  //regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
+  
+#ifdef TXBUFF_PREALLOC
+
+	/* Initialize TXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(tx_bd[k].len_status , OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(tx_bd[k].addr , __pa(mem_addr));
+			//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+			//tx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_TX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#else
+
+ 	/* Initialize TXBDs.
+	 */
+	for(i = 0; i < OETH_TXBD_NUM; i++) {
+
+		cep->tx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(tx_bd[i].len_status , (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+		OETH_REGSAVE(tx_bd[i].addr , 0);
+		//tx_bd[i].len_status = (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+		//tx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#endif
+
+#ifdef RXBUFF_PREALLOC
+
+	/* Initialize RXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(rx_bd[k].len_status , OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(rx_bd[k].addr , __pa(mem_addr));
+			//rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+			//rx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_RX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#else
+	/* Initialize RXBDs.
+	 */
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+
+		OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		//rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(rx_bd[i].addr , 0);
+		//rx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#endif
+	
+	/* Set default ethernet station address.
+	 */
+	dev->dev_addr[0] = MACADDR0;
+	dev->dev_addr[1] = MACADDR1;
+	dev->dev_addr[2] = MACADDR2;
+	dev->dev_addr[3] = MACADDR3;
+	dev->dev_addr[4] = MACADDR4;
+	dev->dev_addr[5] = MACADDR5;
+
+	OETH_REGSAVE(regs->mac_addr1 , MACADDR0 << 8 | MACADDR1);
+	OETH_REGSAVE(regs->mac_addr0 , MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5);
+	//regs->mac_addr1 = MACADDR0 << 8 | MACADDR1;
+	//regs->mac_addr0 = MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5;
+	
+	/* Clear all pending interrupts 
+	 */
+	OETH_REGSAVE(regs->int_src , 0xffffffff);
+	//regs->int_src = 0xffffffff;
+
+	/* Promisc, IFG, CRCEn
+	 */
+	OETH_REGORIN(regs->moder , OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN);
+	//regs->moder |= OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN;
+
+	/* Enable interrupt sources.
+	 */
+	OETH_REGSAVE(regs->int_mask , OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC);
+	/*	regs->int_mask = OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC;
+	*/
+	/* Fill in the fields of the device structure with ethernet values. 
+	 */
+	ether_setup(dev);
+
+	dev->base_addr = (unsigned long)OETH_REG_BASE(base);
+
+	/* The Open Ethernet specific entries in the device structure. 
+	 */
+	dev->open = oeth_open;
+	dev->hard_start_xmit = oeth_start_xmit;
+	dev->stop = oeth_close;
+	dev->get_stats = oeth_get_stats;
+	dev->set_multicast_list = oeth_set_multicast_list;
+	dev->set_mac_address = oeth_set_mac_address;
+
+	if (register_netdev(dev)) {
+	  kfree(dev->priv);
+	  printk(KERN_ERR "open_eth: netdevice registration failed.\n");
+	  return -ENOMEM;
+        }
+
+	printk("%s: Open Ethernet Core Version 1.0 at [0x%x] irq %i\n", dev->name,(unsigned int)(cep->regs),(unsigned int)(cep->irq));
+
+	return 0;
+}
+	
+struct net_device *grlib_oeth_probe(int unit) {
+  
+  struct net_device *dev = alloc_etherdev(0);
+  int err;
+  
+  if (!dev)
+    return ERR_PTR(-ENOMEM);
+  if (unit >= 0)
+    sprintf(dev->name, "eth%d", unit);
+  SET_MODULE_OWNER(dev);
+  err = do_oeth_probe(dev);
+  if (err) {
+    free_netdev(dev);
+    return ERR_PTR(err);
+  }
+  return dev;
+
+  //      printk("Init: Open Ethernet probe\n");
+  //    oeth_dev=alloc_etherdev(sizeof(struct oeth_private));
+  //    return do_oeth_probe(oeth_dev);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef MODULE
+static struct net_device		*oeth_dev;		/* netdevice struct */
+
+int
+init_module(void)
+{
+  oeth_dev = grlib_oeth_probe(-1);
+  if (IS_ERR(oeth_dev)) {
+    printk(KERN_WARNING "Grlib Oeth: No core found\n");
+    return PTR_ERR(oeth_dev);
+  }
+  return 0;
+}
+
+void cleanup_module(void) {
+	
+  printk("Open Ethernet Core cleanup\n");
+  if (oeth_dev) {
+    unregister_netdev(oeth_dev);
+    kfree(oeth_dev);
+  }
+}
+
+//module_init(grlib_oeth_probe);
+//module_exit(oeth_cleanup);
+MODULE_LICENSE("GPL");
+
+#endif
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,143 @@
+/* Ethernet configuration registers */
+typedef struct _oeth_regs {
+        uint    moder;          /* Mode Register */
+        uint    int_src;        /* Interrupt Source Register */
+        uint    int_mask;       /* Interrupt Mask Register */
+        uint    ipgt;           /* Back to Bak Inter Packet Gap Register */
+        uint    ipgr1;          /* Non Back to Back Inter Packet Gap Register 1 */
+        uint    ipgr2;          /* Non Back to Back Inter Packet Gap Register 2 */
+        uint    packet_len;     /* Packet Length Register (min. and max.) */
+        uint    collconf;       /* Collision and Retry Configuration Register */
+        uint    tx_bd_num;      /* Transmit Buffer Descriptor Number Register */
+        uint    ctrlmoder;      /* Control Module Mode Register */
+        uint    miimoder;       /* MII Mode Register */
+        uint    miicommand;     /* MII Command Register */
+        uint    miiaddress;     /* MII Address Register */
+        uint    miitx_data;     /* MII Transmit Data Register */
+        uint    miirx_data;     /* MII Receive Data Register */
+        uint    miistatus;      /* MII Status Register */
+        uint    mac_addr0;      /* MAC Individual Address Register 0 */
+        uint    mac_addr1;      /* MAC Individual Address Register 1 */
+        uint    hash_addr0;     /* Hash Register 0 */
+        uint    hash_addr1;     /* Hash Register 1 */                           
+} oeth_regs;
+
+/* Ethernet buffer descriptor */
+typedef struct _oeth_bd {
+#if 0
+        ushort  len;            /* Buffer length */
+        ushort  status;         /* Buffer status */
+#else
+        uint    len_status;
+#endif
+        uint    addr;           /* Buffer address */
+} oeth_bd;
+
+#define OETH_REG_BASE(b)        (b)
+#define OETH_BD_BASE(b)         ((b) + 0x400)
+#define OETH_TOTAL_BD           128
+#define OETH_MAXBUF_LEN         0x600
+                                
+/* Tx BD */                     
+#define OETH_TX_BD_READY        0x8000 /* Tx BD Ready */
+#define OETH_TX_BD_IRQ          0x4000 /* Tx BD IRQ Enable */
+#define OETH_TX_BD_WRAP         0x2000 /* Tx BD Wrap (last BD) */
+#define OETH_TX_BD_PAD          0x1000 /* Tx BD Pad Enable */
+#define OETH_TX_BD_CRC          0x0800 /* Tx BD CRC Enable */
+                                
+#define OETH_TX_BD_UNDERRUN     0x0100 /* Tx BD Underrun Status */
+#define OETH_TX_BD_RETRY        0x00F0 /* Tx BD Retry Status */
+#define OETH_TX_BD_RETLIM       0x0008 /* Tx BD Retransmission Limit Status */
+#define OETH_TX_BD_LATECOL      0x0004 /* Tx BD Late Collision Status */
+#define OETH_TX_BD_DEFER        0x0002 /* Tx BD Defer Status */
+#define OETH_TX_BD_CARRIER      0x0001 /* Tx BD Carrier Sense Lost Status */
+#define OETH_TX_BD_STATS        (OETH_TX_BD_UNDERRUN            | \
+                                OETH_TX_BD_RETRY                | \
+                                OETH_TX_BD_RETLIM               | \
+                                OETH_TX_BD_LATECOL              | \
+                                OETH_TX_BD_DEFER                | \
+                                OETH_TX_BD_CARRIER)
+                                
+/* Rx BD */                     
+#define OETH_RX_BD_EMPTY        0x8000 /* Rx BD Empty */
+#define OETH_RX_BD_IRQ          0x4000 /* Rx BD IRQ Enable */
+#define OETH_RX_BD_WRAP         0x2000 /* Rx BD Wrap (last BD) */
+                                
+#define OETH_RX_BD_MISS         0x0080 /* Rx BD Miss Status */
+#define OETH_RX_BD_OVERRUN      0x0040 /* Rx BD Overrun Status */
+#define OETH_RX_BD_INVSIMB      0x0020 /* Rx BD Invalid Symbol Status */
+#define OETH_RX_BD_DRIBBLE      0x0010 /* Rx BD Dribble Nibble Status */
+#define OETH_RX_BD_TOOLONG      0x0008 /* Rx BD Too Long Status */
+#define OETH_RX_BD_SHORT        0x0004 /* Rx BD Too Short Frame Status */
+#define OETH_RX_BD_CRCERR       0x0002 /* Rx BD CRC Error Status */
+#define OETH_RX_BD_LATECOL      0x0001 /* Rx BD Late Collision Status */
+#define OETH_RX_BD_STATS        (OETH_RX_BD_MISS                | \
+                                OETH_RX_BD_OVERRUN              | \
+                                OETH_RX_BD_INVSIMB              | \
+                                OETH_RX_BD_DRIBBLE              | \
+                                OETH_RX_BD_TOOLONG              | \
+                                OETH_RX_BD_SHORT                | \
+                                OETH_RX_BD_CRCERR               | \
+                                OETH_RX_BD_LATECOL)
+
+/* MODER Register */
+#define OETH_MODER_RXEN         0x00000001 /* Receive Enable  */
+#define OETH_MODER_TXEN         0x00000002 /* Transmit Enable */
+#define OETH_MODER_NOPRE        0x00000004 /* No Preamble  */
+#define OETH_MODER_BRO          0x00000008 /* Reject Broadcast */
+#define OETH_MODER_IAM          0x00000010 /* Use Individual Hash */
+#define OETH_MODER_PRO          0x00000020 /* Promiscuous (receive all) */
+#define OETH_MODER_IFG          0x00000040 /* Min. IFG not required */
+#define OETH_MODER_LOOPBCK      0x00000080 /* Loop Back */
+#define OETH_MODER_NOBCKOF      0x00000100 /* No Backoff */
+#define OETH_MODER_EXDFREN      0x00000200 /* Excess Defer */
+#define OETH_MODER_FULLD        0x00000400 /* Full Duplex */
+#define OETH_MODER_RST          0x00000800 /* Reset MAC */
+#define OETH_MODER_DLYCRCEN     0x00001000 /* Delayed CRC Enable */
+#define OETH_MODER_CRCEN        0x00002000 /* CRC Enable */
+#define OETH_MODER_HUGEN        0x00004000 /* Huge Enable */
+#define OETH_MODER_PAD          0x00008000 /* Pad Enable */
+#define OETH_MODER_RECSMALL     0x00010000 /* Receive Small */
+ 
+/* Interrupt Source Register */
+#define OETH_INT_TXB            0x00000001 /* Transmit Buffer IRQ */
+#define OETH_INT_TXE            0x00000002 /* Transmit Error IRQ */
+#define OETH_INT_RXF            0x00000004 /* Receive Frame IRQ */
+#define OETH_INT_RXE            0x00000008 /* Receive Error IRQ */
+#define OETH_INT_BUSY           0x00000010 /* Busy IRQ */
+#define OETH_INT_TXC            0x00000020 /* Transmit Control Frame IRQ */
+#define OETH_INT_RXC            0x00000040 /* Received Control Frame IRQ */
+
+/* Interrupt Mask Register */
+#define OETH_INT_MASK_TXB       0x00000001 /* Transmit Buffer IRQ Mask */
+#define OETH_INT_MASK_TXE       0x00000002 /* Transmit Error IRQ Mask */
+#define OETH_INT_MASK_RXF       0x00000004 /* Receive Frame IRQ Mask */
+#define OETH_INT_MASK_RXE       0x00000008 /* Receive Error IRQ Mask */
+#define OETH_INT_MASK_BUSY      0x00000010 /* Busy IRQ Mask */
+#define OETH_INT_MASK_TXC       0x00000020 /* Transmit Control Frame IRQ Mask */
+#define OETH_INT_MASK_RXC       0x00000040 /* Received Control Frame IRQ Mask */
+ 
+/* Control Module Mode Register */
+#define OETH_CTRLMODER_PASSALL  0x00000001 /* Pass Control Frames */
+#define OETH_CTRLMODER_RXFLOW   0x00000002 /* Receive Control Flow Enable */
+#define OETH_CTRLMODER_TXFLOW   0x00000004 /* Transmit Control Flow Enable */
+                               
+/* MII Mode Register */        
+#define OETH_MIIMODER_CLKDIV    0x000000FF /* Clock Divider */
+#define OETH_MIIMODER_NOPRE     0x00000100 /* No Preamble */
+#define OETH_MIIMODER_RST       0x00000200 /* MIIM Reset */
+ 
+/* MII Command Register */
+#define OETH_MIICOMMAND_SCANSTAT  0x00000001 /* Scan Status */
+#define OETH_MIICOMMAND_RSTAT     0x00000002 /* Read Status */
+#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */
+ 
+/* MII Address Register */
+#define OETH_MIIADDRESS_FIAD    0x0000001F /* PHY Address */
+#define OETH_MIIADDRESS_RGAD    0x00001F00 /* RGAD Address */
+ 
+/* MII Status Register */
+#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */
+#define OETH_MIISTATUS_BUSY     0x00000002 /* MII Busy */
+#define OETH_MIISTATUS_NVALID   0x00000004 /* Data in MII Status Register is invalid */
+
diff -Naur ../linux-2.6.10/drivers/net/Space.c linux-2.6.10/drivers/net/Space.c
--- ../linux-2.6.10/drivers/net/Space.c	2004-12-24 22:33:59.000000000 +0100
+++ linux-2.6.10/drivers/net/Space.c	2005-01-03 11:36:33.000000000 +0100
@@ -93,6 +93,7 @@
 extern struct net_device *mc32_probe(int unit);
 extern struct net_device *cops_probe(int unit);
 extern struct net_device *ltpc_probe(void);
+extern struct net_device *grlib_oeth_probe(int unit);
   
 /* Detachable devices ("pocket adaptors") */
 extern struct net_device *de620_probe(int unit);
@@ -312,6 +313,13 @@
 	{NULL, 0},
 };
 
+static struct devprobe2 sparc_probes[] __initdata = {
+#ifdef CONFIG_GRLIB_OPENCORES_ETHERMAC
+	{grlib_oeth_probe, 0},
+#endif
+	{NULL, 0},
+};
+
 /*
  * Unified ethernet device probe, segmented per architecture and
  * per bus interface. This drives the legacy devices only for now.
@@ -326,6 +334,7 @@
 
 	(void)(	probe_list2(unit, m68k_probes, base_addr == 0) &&
 		probe_list2(unit, mips_probes, base_addr == 0) &&
+		probe_list2(unit, sparc_probes, base_addr == 0) &&
 		probe_list2(unit, eisa_probes, base_addr == 0) &&
 		probe_list2(unit, mca_probes, base_addr == 0) &&
 		probe_list2(unit, isa_probes, base_addr == 0) &&

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [4/7] LEON SPARC V8 processor support for linux-2.6.10
@ 2005-01-05 15:18   ` Jiri Gaisler
  0 siblings, 0 replies; 4+ messages in thread
From: Jiri Gaisler @ 2005-01-05 15:18 UTC (permalink / raw)
  To: sparclinux; +Cc: linux-kernel, wli

[-- Attachment #1: Type: text/plain, Size: 407 bytes --]

Leon3 serial+ethermac driver, updated.

[4/7] diff2.6.10_driver_amba.diff         diff for drivers/amba


-- 
--------------------------------------------------------------------------
Gaisler Research, 1:a Långgatan 19, 413 27 Goteborg, Sweden, +46-317758650
fax: +46-31421407 email: info@gaisler.com, home page: www.gaisler.com
--------------------------------------------------------------------------



[-- Attachment #2: diff2.6.10_driver_amba.diff --]
[-- Type: text/plain, Size: 74624 bytes --]

diff -Naur ../linux-2.6.10/drivers/Makefile linux-2.6.10/drivers/Makefile
--- ../linux-2.6.10/drivers/Makefile	2004-12-24 22:36:00.000000000 +0100
+++ linux-2.6.10/drivers/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -60,3 +60,4 @@
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-y				+= firmware/
+obj-$(CONFIG_LEON_3)            += amba/
diff -Naur ../linux-2.6.10/drivers/amba/Kconfig linux-2.6.10/drivers/amba/Kconfig
--- ../linux-2.6.10/drivers/amba/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Kconfig	2005-01-03 17:10:41.000000000 +0100
@@ -0,0 +1,12 @@
+
+#------------------------------------------------------------------------------
+# Amba device driver configuration
+#------------------------------------------------------------------------------
+
+menu "Grlib: Amba device driver configuration"
+
+source "drivers/amba/gaisler/Kconfig"
+source "drivers/amba/opencores/Kconfig"
+
+endmenu
+
diff -Naur ../linux-2.6.10/drivers/amba/Makefile linux-2.6.10/drivers/amba/Makefile
--- ../linux-2.6.10/drivers/amba/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,7 @@
+#
+# Makefile for the PCI bus specific drivers.
+#
+
+obj-y		+= amba.o amba_driver.o
+
+obj-y           += gaisler/ opencores/
diff -Naur ../linux-2.6.10/drivers/amba/amba.c linux-2.6.10/drivers/amba/amba.c
--- ../linux-2.6.10/drivers/amba/amba.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,181 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+amba_confarea_type amba_conf;
+
+/* Pointers to Interrupt Controller configuration registers */
+volatile LEON3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs = 0;
+volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs = 0;
+unsigned long LEON3_GpTimer_Irq = 0;
+
+static void vendor_dev_string(unsigned long conf, char *vendorbuf,char *devbuf) {
+  int vendor = amba_vendor(conf); int dev = amba_device(conf);
+  char *devstr; char *vendorstr; 
+  sprintf(vendorbuf, "Unknown vendor %2x",vendor);
+  sprintf(devbuf, "Unknown device %2x",dev);
+  vendorstr = vendor_id2str(vendor);
+  if (vendorstr) {
+    sprintf(vendorbuf, "%s",vendorstr);
+  } 
+  devstr = device_id2str(vendor,dev);
+  if (devstr) {
+    sprintf(devbuf, "%s",devstr);
+  }
+}
+
+void amba_prinf_config(void)  
+{
+  char devbuf[128]; char vendorbuf[128]; unsigned int conf;
+  int i = 0; int j = 0; 
+  unsigned int addr; unsigned int m;
+  printk("             Vendors         Slaves\n");
+  printk("Ahb masters:\n");
+  i = 0;
+  while (i < amba_conf.ahbmst.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbmst, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbmst,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+        printk(" +%i: 0x%x \n", j, addr);
+      }
+    }
+    i++;
+  }
+  printk("Ahb slaves:\n");
+  i = 0;
+  while (i < amba_conf.ahbslv.devnr) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    for (j = 0;j < 4;j++) {
+      m = amba_ahb_get_membar(amba_conf.ahbslv,i,j);
+      if (m) {
+        addr = amba_membar_start(m);
+	if (amba_membar_type(m) == AMBA_TYPE_AHBIO) {
+	  addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	} else if (amba_membar_type(m) == AMBA_TYPE_APBIO) {
+	  printk("Warning: apbio membar\n");
+	}
+	printk(" +%i: 0x%x (raw:0x%x)\n", j, addr, m);
+      }
+    }
+    i++;
+  }
+  printk("Apb slaves:\n");
+  i = 0;
+  while (i < amba_conf.apbslv.devnr) 
+  {
+    
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    vendor_dev_string(conf,vendorbuf,devbuf);
+    printk("%2i(%2x:%3x|%2i): %16s %16s \n", i, amba_vendor(conf), amba_device(conf), amba_irq(conf), vendorbuf, devbuf);
+    
+    m = amba_apb_get_membar(amba_conf.apbslv, i);
+    addr = amba_iobar_start(amba_conf.apbmst, m);
+    printk(" +%2i: 0x%x (raw:0x%x) \n", 0, addr, m);
+    
+    i++;
+    
+  }
+  
+}
+
+#define amba_insert_device(tab, address) \
+{ \
+  if (LEON3_BYPASS_LOAD_PA(address)) \
+  { \
+    (tab)->addr[(tab)->devnr] = (address); \
+    (tab)->devnr ++; \
+  } \
+} while(0)
+
+/*
+ *  Used to scan system bus. Probes for AHB masters, AHB slaves and 
+ *  APB slaves. Addresses to configuration areas of the AHB masters,
+ *  AHB slaves, APB slaves and APB master are storeds in 
+ *  amba_ahb_masters, amba_ahb_slaves and amba.
+ */
+
+void amba_init(void) 
+{
+  unsigned int *cfg_area;  /* address to configuration area */
+  unsigned int mbar, conf;
+  int i, j;
+  
+#ifdef DEBUG_CONFIG
+  printk("Reading AMBA Plug&Play configuration area\n");
+#endif
+
+  memset(&amba_conf,0,sizeof(amba_conf));
+  //amba_conf.ahbmst.devnr = 0; amba_conf.ahbslv.devnr = 0; amba_conf.apbslv.devnr = 0;
+  
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA);
+
+  for (i = 0; i < LEON3_AHB_MASTERS; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbmst, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }
+
+  cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA | LEON3_AHB_SLAVE_CONF_AREA);
+  for (i = 0; i < LEON3_AHB_SLAVES; i++) 
+  {
+    amba_insert_device(&amba_conf.ahbslv, cfg_area);
+    cfg_area += LEON3_AHB_CONF_WORDS;
+  }  
+
+  for (i = 0; i < amba_conf.ahbslv.devnr; i ++) 
+  {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+    mbar = amba_ahb_get_membar(amba_conf.ahbslv, i, 0);
+    if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_APBMST))
+    {
+      amba_conf.apbmst = amba_membar_start(mbar);
+      cfg_area = (unsigned int *) (amba_conf.apbmst | LEON3_CONF_AREA);
+      
+      printk("Found apbmst, cfg: 0x%x\n",(unsigned int)cfg_area);
+      
+      for (j = amba_conf.apbslv.devnr; j < LEON3_APB_SLAVES; j++)
+      {
+	amba_insert_device(&amba_conf.apbslv, cfg_area);
+	cfg_area += LEON3_APB_CONF_WORDS;
+      }
+    }
+  }    
+ 
+  /* Find LEON3 Interrupt controler */
+  LEON3_IrqCtrl_Regs = (volatile LEON3_IrqCtrl_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_IRQMP, 0);
+  LEON3_GpTimer_Regs = (volatile LEON3_GpTimer_Regs_Map *) amba_find_apbslv_addr(VENDOR_GAISLER, GAISLER_GPTIMER, &LEON3_GpTimer_Irq);
+  if (LEON3_IrqCtrl_Regs) {
+    LEON3_BYPASS_STORE_PA(&(LEON3_IrqCtrl_Regs ->mask[0]),0);
+  }
+}
+
+unsigned long amba_find_apbslv_addr(unsigned long vendor, unsigned long device, unsigned long *irq) {
+  unsigned int i,conf,iobar;
+  for (i = 0; i < amba_conf.apbslv.devnr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device))
+    {
+      if (irq) {
+        *irq = amba_irq(conf);
+      }
+      iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+      return amba_iobar_start(amba_conf.apbmst, iobar);
+    }
+  }
+  return 0;
+}
diff -Naur ../linux-2.6.10/drivers/amba/amba_driver.c linux-2.6.10/drivers/amba/amba_driver.c
--- ../linux-2.6.10/drivers/amba/amba_driver.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/amba_driver.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,78 @@
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/leon.h>
+
+//#define DEBUG_CONFIG
+
+/* Structure containing address to devices found on the Amba Plug&Play bus */
+extern amba_confarea_type amba_conf;
+ 
+//collect apb slaves
+int amba_get_free_apbslv_devices (int vendor, int device, amba_apb_device *dev,int nr) {
+  unsigned int i,conf,iobar,j = 0;
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: search for apdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.apbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.apbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Apbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.apbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Apbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.apbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+        iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+        dev[j].start = amba_iobar_start(amba_conf.apbmst, iobar);
+#ifdef DEBUG_CONFIG
+	printk(" +bar: 0x%x \n", k, dev[j].start);
+#endif
+        j++;
+      }
+    }
+  }
+  return j;
+}
+
+//collect ahb slaves
+int amba_get_free_ahbslv_devices (int vendor, int device, amba_ahb_device *dev,int nr) {
+  unsigned int addr, i,conf,iobar,j = 0,k;
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: search for ahdslv devices\n");
+#endif
+  for (i = 0; i < amba_conf.ahbslv.devnr && j < nr; i++) {
+    conf = amba_get_confword(amba_conf.ahbslv, i, 0);
+#ifdef DEBUG_CONFIG
+    printk("Ahbslv: check(%x:%x)==(%x:%x)\n",vendor,device,amba_vendor(conf),amba_device(conf));
+#endif
+    if ((amba_vendor(conf) == vendor) && (amba_device(conf) == device)) {
+      if (!(amba_conf.ahbslv.allocbits[i / 32] & (1 << (i & (32-1))))) {
+#ifdef DEBUG_CONFIG
+        printk("Ahbslv: alloc device idx %i (%x:%x)\n",j,vendor,device);
+#endif
+        amba_conf.ahbslv.allocbits[i / 32] |= (1 << (i & (32-1)));
+        dev[j].irq = amba_irq(conf);
+	for (k = 0; k < 4; k ++) {
+	  iobar = amba_ahb_get_membar(amba_conf.ahbslv, i, k);
+	  addr = amba_membar_start(iobar);
+	  if (amba_membar_type(iobar) == AMBA_TYPE_AHBIO) {
+	    addr = AMBA_TYPE_AHBIO_ADDR(addr);
+	  }
+	  dev[j].start[k] = addr;
+#ifdef DEBUG_CONFIG
+	  printk(" +%i: 0x%x \n", k, dev[j].start[k]);
+#endif
+	}
+        j++;
+      }
+    }
+  }
+  return j;
+}
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Kconfig linux-2.6.10/drivers/amba/gaisler/Kconfig
--- ../linux-2.6.10/drivers/amba/gaisler/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,12 @@
+
+menu "Vendor Gaisler"
+
+config GRLIB_GAISLER_APBUART
+	bool "Grlib apbuart driver" 
+	default y
+	---help---
+	  Add the driver for the grlib apbuart serial core.
+
+endmenu
+
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/Makefile linux-2.6.10/drivers/amba/gaisler/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_GAISLER_APBUART)		+= apbuart/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= apbuart.o
+
diff -Naur ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c
--- ../linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/gaisler/apbuart/apbuart.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,729 @@
+/*
+ *  linux/drivers/serial/leon.c
+ *
+ *  Driver for Leon serial ports
+ *
+ *  Based on linux/drivers/serial/amba.c , Documentation/serial/driver
+ * 
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ * 
+ *  Modified for Leon by Konrad Eisele <eiselekd@web.de>, 2003
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+
+#if defined(CONFIG_SERIAL_LEON_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <asm/leon.h>
+
+#define UART_NR		8
+int leon_ports_nr = 0;
+
+#define SERIAL_LEON_MAJOR	TTY_MAJOR
+#define SERIAL_LEON_MINOR	64
+#define SERIAL_LEON_NR		UART_NR
+
+#define AMBA_ISR_PASS_LIMIT	256
+
+#define APBBASE(port) ((LEON3_APBUART_Regs_Map *)((port)->membase))
+
+#define APBBASE_DATA_P(port) (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port)	(LEON_BYPASS_LOAD_PA(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v)	(LEON_BYPASS_STORE_PA(APBBASE_DATA_P(port),v))
+#define UART_GET_STATUS(port)	(LEON_BYPASS_LOAD_PA(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port,v)	(LEON_BYPASS_STORE_PA(APBBASE_STATUS_P(port),v))
+#define UART_GET_CTRL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_CTRL_P(port),v))
+#define UART_GET_SCAL(port)   (LEON_BYPASS_LOAD_PA(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port,v) (LEON_BYPASS_STORE_PA(APBBASE_SCALAR_P(port),v))
+#define UART_RX_DATA(s)       (((s) & LEON_REG_UART_STATUS_DR) != 0)
+#define UART_TX_READY(s)	(((s) & LEON_REG_UART_STATUS_THE) != 0)
+
+#define UART_DUMMY_RSR_RX	0x8000 /* for ignore all read */
+
+/* We wrap our port structure around the generic uart_port */
+struct uart_leon_port {
+	struct uart_port	port;
+	unsigned int		old_status;
+};
+
+static void leonuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port);
+static void leonuart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr |= LEON_REG_UART_CTRL_TI; 
+	UART_PUT_CTRL(port, cr);
+	
+	if (UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars (port);
+	}
+}
+
+static void leonuart_stop_rx(struct uart_port *port)
+{
+	unsigned int cr;
+
+	cr = UART_GET_CTRL(port);
+	cr &= ~(LEON_REG_UART_CTRL_RI);
+	UART_PUT_CTRL(port, cr);
+}
+
+static void leonuart_enable_ms(struct uart_port *port)
+{
+	/* no modem status for leon */
+}
+
+//static 
+void
+#ifdef SUPPORT_SYSRQ
+leonuart_rx_chars(struct uart_port *port, struct pt_regs *regs)
+#else
+leonuart_rx_chars(struct uart_port *port)
+#endif
+{
+	struct tty_struct *tty = port->info->tty;
+	unsigned int status, ch, rsr;
+
+	status = UART_GET_STATUS(port); 
+	if (UART_RX_DATA(status)) {
+      
+            if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.work.func((void *)tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+				return;
+			}
+		}
+
+		ch = UART_GET_CHAR(port); 
+
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = TTY_NORMAL;
+		port->icount.rx++;
+
+		/*
+		 * Note that the error handling code is
+		 * out of the main execution path
+		 */
+		rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX; 
+		UART_PUT_STATUS(port,0);
+		if (rsr & LEON_REG_UART_STATUS_ERR) { 
+
+		  if (rsr & LEON_REG_UART_STATUS_BR) {
+		    rsr &= ~(LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE);
+		    port->icount.brk++;
+		    if (uart_handle_break(port))
+		      goto ignore_char;
+		  } else if (rsr & LEON_REG_UART_STATUS_PE) {
+		    port->icount.parity++;
+		  } else if (rsr & LEON_REG_UART_STATUS_FE) {
+		    port->icount.frame++;
+		  }
+		  if (rsr & LEON_REG_UART_STATUS_OE)
+		    port->icount.overrun++;
+                  
+		  rsr &= port->read_status_mask;
+		  
+		  if (rsr & LEON_REG_UART_STATUS_PE)
+		    *tty->flip.flag_buf_ptr = TTY_PARITY;
+                  else if (rsr & LEON_REG_UART_STATUS_FE)
+		    *tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+            
+		if (uart_handle_sysrq_char(port, ch, regs))
+		    goto ignore_char;
+		
+		if ((rsr & port->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((rsr & LEON_REG_UART_STATUS_OE) &&
+		    tty->flip.count < TTY_FLIPBUF_SIZE) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.char_buf_ptr++ = 0;
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+			tty->flip.count++;
+		}
+	}
+ignore_char:
+	tty_flip_buffer_push(tty);
+	return;
+}
+
+//static 
+void leonuart_tx_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	int count;
+
+	if (port->x_char) {
+		UART_PUT_CHAR(port, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		leonuart_stop_tx(port, 0);
+		return;
+	}
+
+	count = port->fifosize >> 1; //amba: fill FIFO
+	do {
+		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		leonuart_stop_tx(port, 0);
+}
+
+//static 
+irqreturn_t leonuart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	unsigned int status;
+
+	spin_lock(port ->lock);
+
+	status = UART_GET_STATUS(port);
+	if (status & LEON_REG_UART_STATUS_DR) {
+#ifdef SUPPORT_SYSRQ
+	  leonuart_rx_chars(port,regs);
+#else
+	  leonuart_rx_chars(port);
+#endif          
+	}
+	if (status & LEON_REG_UART_STATUS_THE) {
+	  leonuart_tx_chars(port);
+	}
+	spin_unlock(port ->lock);
+	return IRQ_HANDLED;
+}
+
+static unsigned int leonuart_tx_empty(struct uart_port *port)
+{
+	return UART_GET_STATUS(port) & LEON_REG_UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int leonuart_get_mctrl(struct uart_port *port)
+{
+	unsigned int result = 0;
+
+	/*
+	  no modem status for leon
+	*/
+
+	return result;
+}
+
+static void leonuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* no modem status for leon */
+}
+
+static void leonuart_break_ctl(struct uart_port *port, int break_state)
+{
+	/* no break for leon */
+}
+
+static int leonuart_startup(struct uart_port *port)
+{
+	struct uart_leon_port *uap = (struct uart_leon_port *)port;
+	int retval;
+	unsigned int cr;
+
+	/*
+	 * Allocate the IRQ
+	 */
+	retval = request_irq(port->irq, leonuart_int, 0, "leon", port);
+	if (retval)
+		return retval;
+
+	/*
+	 * initialise the old status of the modem signals
+	 */
+	uap->old_status = 0;
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr | LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI );	
+      
+	return 0;
+}
+
+static void leonuart_shutdown(struct uart_port *port)
+{
+	unsigned int cr;
+
+	/*
+	 * Free the interrupt
+	 */
+	free_irq(port->irq, port);
+
+	/*
+	 * disable all interrupts, disable the port
+	 */
+	cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, cr & ~( LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE	| LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI ));	
+      
+}
+
+static void
+leonuart_set_termios(struct uart_port *port, struct termios *termios,
+		     struct termios *old)
+{
+	unsigned int cr;
+	unsigned long flags;
+	unsigned int baud, quot;
+
+	/*
+	 * Ask the core to calculate the divisor for us.
+	 */
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	if (baud == 0) {
+	  panic("invalid baudrate %i\n", port->uartclk/16);
+	}
+	quot = (uart_get_divisor(port, baud)) * 2; //uart_get_divisor calc a *16 uart freq, leon is *8
+	cr = UART_GET_CTRL(port);
+	cr &= ~( LEON_REG_UART_CTRL_PE | LEON_REG_UART_CTRL_PS );
+	  
+	if (termios->c_cflag & PARENB) { 
+		cr |= LEON_REG_UART_CTRL_PE; 
+		if ((termios->c_cflag & PARODD))
+			cr |= LEON_REG_UART_CTRL_PS;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/*
+	 * Update the per-port timeout.
+	 */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	port->read_status_mask = LEON_REG_UART_STATUS_OE;
+	if (termios->c_iflag & INPCK) 
+		port->read_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE ;
+
+	/*
+	 * Characters to ignore
+	 */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= LEON_REG_UART_STATUS_OE | LEON_REG_UART_STATUS_FE | LEON_REG_UART_STATUS_PE;
+
+	/* Set baud rate */
+	quot -= 1;
+	UART_PUT_SCAL(port, quot);
+	UART_PUT_CTRL(port, cr);
+      
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *leonuart_type(struct uart_port *port)
+{
+	return port->type == PORT_LEON ? "Leon" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void leonuart_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int leonuart_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void leonuart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_LEON;
+		leonuart_request_port(port);
+	}
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int leonuart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_LEON)
+		ret = -EINVAL;
+	if (ser->irq < 0 || ser->irq >= NR_IRQS)
+		ret = -EINVAL;
+	if (ser->baud_base < 9600)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops leon_pops = {
+	.tx_empty	= leonuart_tx_empty,
+	.set_mctrl	= leonuart_set_mctrl,
+	.get_mctrl	= leonuart_get_mctrl,
+	.stop_tx	= leonuart_stop_tx,
+	.start_tx	= leonuart_start_tx,
+	.stop_rx	= leonuart_stop_rx,
+	.enable_ms	= leonuart_enable_ms,
+	.break_ctl	= leonuart_break_ctl,
+	.startup	= leonuart_startup,
+	.shutdown	= leonuart_shutdown,
+	.set_termios	= leonuart_set_termios,
+	.type		= leonuart_type,
+	.release_port	= leonuart_release_port,
+	.request_port	= leonuart_request_port,
+	.config_port	= leonuart_config_port,
+	.verify_port	= leonuart_verify_port,
+};
+
+static struct uart_leon_port leon_ports[UART_NR];
+/* = {
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART0),
+			.mapbase	= (LEON_PREGS+LEON_UART0),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_0_RX_TX,
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+	},
+	{
+		.port	= {
+			.membase	= (void*) (LEON_PREGS+LEON_UART1),
+			.mapbase	= (LEON_PREGS+LEON_UART1),
+			.iotype	= SERIAL_IO_MEM,
+			.irq		= LEON_INTERRUPT_UART_1_RX_TX, 
+			.uartclk	= 0,
+			.fifosize	= 1,
+			.ops		= &leon_pops,
+			.flags	= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+	}
+};*/
+
+extern volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs;
+
+/* rs_init inits the driver */
+static int _apbuart_init_bases_done = 0;
+static void __init 
+_apbuart_init_bases(void)
+{
+  int  i; 
+  amba_apb_device dev[8];
+  if (!_apbuart_init_bases_done ) {
+    unsigned long clk = ((unsigned long)(((LEON3_BYPASS_LOAD_PA(&LEON3_GpTimer_Regs->scalar_reload)) + 1))); 
+    printk("Attaching grlib apbuart serial drivers (clk:%ihz):\n",(int)clk);
+    leon_ports_nr = amba_get_free_apbslv_devices (VENDOR_GAISLER, GAISLER_APBUART, dev, 8);
+
+    for (i = 0;i < leon_ports_nr;i++) {
+      leon_ports[i].port.membase = (void *)dev[i].start;
+      leon_ports[i].port.mapbase = dev[i].start;
+      leon_ports[i].port.irq = dev[i].irq;
+      leon_ports[i].port.iotype = SERIAL_IO_MEM;
+      leon_ports[i].port.uartclk = clk * 1000 * 1000;
+      leon_ports[i].port.fifosize = 1;
+      leon_ports[i].port.ops	= &leon_pops;
+      leon_ports[i].port.flags = ASYNC_BOOT_AUTOCONF;
+      leon_ports[i].port.line =i;
+    }
+    _apbuart_init_bases_done = 1;
+  }
+}
+
+
+#ifdef CONFIG_SERIAL_LEON_CONSOLE
+
+static void
+leonuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_port *port = &leon_ports[co->index].port;
+	unsigned int status, old_cr;
+	int i;
+
+	/*
+	 *	First save the CR then disable the interrupts
+	 */
+	old_cr = UART_GET_CTRL(port);
+	UART_PUT_CTRL(port, (old_cr & ~(LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI)) | (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE) ); 
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++) {
+		do {
+			status = UART_GET_STATUS(port);
+		} while (!UART_TX_READY(status));
+		UART_PUT_CHAR(port, s[i]);
+		if (s[i] == '\n') {
+			do {
+				status = UART_GET_STATUS(port);
+			} while (!UART_TX_READY(status));
+			UART_PUT_CHAR(port, '\r');
+		}
+	}
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore the TCR
+	 */
+	do {
+		status = UART_GET_STATUS(port);
+	} while (!UART_TX_READY(status));
+	UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+leonuart_console_get_options(struct uart_port *port, int *baud,
+			     int *parity, int *bits)
+{
+      if (UART_GET_CTRL(port) & (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE)) {
+	
+		unsigned int quot, status;
+		status = UART_GET_STATUS(port);
+
+		*parity = 'n';
+		if (status & LEON_REG_UART_CTRL_PE) {
+			if ((status & LEON_REG_UART_CTRL_PS) == 0 )
+				*parity = 'e';
+			else
+				*parity = 'o';
+		}
+            
+		*bits = 8;
+            quot = UART_GET_SCAL(port) / 8;
+		*baud = port->uartclk / (16 * (quot + 1));
+	}
+}
+
+static int __init leonuart_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 38400;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	/*
+	 * Check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	if (co->index >= leon_ports_nr)
+		co->index = 0;
+	port = &leon_ports[co->index].port;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		leonuart_console_get_options(port, &baud, &parity, &bits);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+static struct uart_driver leon_reg;
+static struct console leon_console = {
+	.name		= "ttyS",
+	.write		= leonuart_console_write,
+	.device		= uart_console_device,
+	.setup		= leonuart_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &leon_reg,
+};
+
+//static int leonuart_init(void);
+static int __init leonuart_console_init(void)
+{
+	_apbuart_init_bases();
+	register_console(&leon_console);
+	return 0;
+}
+console_initcall(leonuart_console_init);
+
+#define LEON_CONSOLE	&leon_console
+#else
+#define LEON_CONSOLE	NULL
+#endif
+
+static struct uart_driver leon_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "serial",
+	.devfs_name	= "tts/",
+	.dev_name	= "ttyS",
+	.major		= SERIAL_LEON_MAJOR,
+	.minor		= SERIAL_LEON_MINOR,
+	.nr		= UART_NR,
+	.cons		= LEON_CONSOLE,
+};
+
+
+static int __init gaisler_apbuart_init(void)
+{
+	int ret;
+	int i;
+	int node;
+	int freq_khz;
+	int baud_rates[UART_NR];
+
+	_apbuart_init_bases();
+	node = prom_getchild(prom_root_node);
+	freq_khz = prom_getint(node, "frequency");
+	
+	printk(KERN_INFO "grlib apbuart: %i serial driver(s) at [",leon_ports_nr);
+	for (i = 0; i < leon_ports_nr; i++) {
+	  baud_rates[i] = prom_getintdefault(node, "uart1_baud", 9600);
+	  if (i != 0) {printk(",");}
+	  printk("0x%x",(unsigned int) leon_ports[i].port.mapbase);
+	  printk("(irq %i)",leon_ports[i].port.irq);
+	}
+	printk("]\n");
+
+	baud_rates[0] = prom_getintdefault(node, "uart1_baud", 9600);
+	baud_rates[1] = prom_getintdefault(node, "uart2_baud", 9600);
+
+	printk(KERN_INFO "grlib apbuart: system frequency: %i khz, baud rates: %i %i\n", freq_khz, baud_rates[0], baud_rates[1]);
+
+	ret = uart_register_driver(&leon_reg);
+	leon_reg.tty_driver->init_termios.c_cflag = 
+		(leon_reg.tty_driver->init_termios.c_cflag & ~CBAUD) | B38400;
+	
+	if (ret) return ret;
+
+	for (i = 0; i < leon_ports_nr; i++) {
+		struct console co;
+		leon_ports[i].port.uartclk = freq_khz * 1000;
+		uart_add_one_port(&leon_reg, &leon_ports[i].port);
+		uart_set_options(&leon_ports[i].port, &co,
+				 baud_rates[i], 'n', 8, 'n');
+	}
+
+	return ret;
+}
+
+static void __exit gaisler_apbuart_exit(void)
+{
+	int i;
+
+	for (i = 0; i < leon_ports_nr; i++)
+		uart_remove_one_port(&leon_reg, &leon_ports[i].port);
+
+	uart_unregister_driver(&leon_reg);
+}
+
+module_init(gaisler_apbuart_init);
+module_exit(gaisler_apbuart_exit);
+
+MODULE_AUTHOR("Konrad Eisele<eiselekd@web.de>, based on AMBA serial");
+MODULE_DESCRIPTION("grlib apbuart serial driver");
+MODULE_LICENSE("GPL");
+
+
+
+
+
+void leon3_rs_put_char_base(LEON3_APBUART_Regs_Map *uart_regs,char ch)
+{
+        int flags, loops;
+
+        save_flags(flags); cli();
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_THE) && (loops < 100000))
+        	loops++;
+
+	LEON3_BYPASS_STORE_PA(&(uart_regs->data),ch);
+
+	loops = 0;
+	while (!(LEON3_BYPASS_LOAD_PA(&(uart_regs->status)) & LEON_REG_UART_STATUS_TSE) && (loops < 100000))
+        	loops++;
+        restore_flags(flags);
+}
+
+void leon3_rs_put_char(char ch)
+{
+  LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+  if (b) {
+    leon3_rs_put_char_base(b,ch);
+  }
+}
+
+void console_print_LEON(const char *p)
+{
+	char c;
+
+        LEON3_APBUART_Regs_Map *b = (LEON3_APBUART_Regs_Map *)amba_find_apbslv_addr(VENDOR_GAISLER,GAISLER_APBUART,0);
+        
+	while((c=*(p++)) != 0) {
+          if(c == '\n')
+            leon3_rs_put_char_base(b,'\r');
+          leon3_rs_put_char_base(b,c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	/* rs_fair_output(); */
+
+	return;
+}
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Kconfig linux-2.6.10/drivers/amba/opencores/Kconfig
--- ../linux-2.6.10/drivers/amba/opencores/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Kconfig	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,36 @@
+
+menu "Vendor Opencores"
+
+config GRLIB_OPENCORES_ETHERMAC
+	bool "Grlib's opencores ethermac driver" 
+	default y
+	depends on NETDEVICES
+	---help---
+	  Add the driver for the grlib opencore ethermac.
+
+
+config GRLIB_OPENCORES_ETHERMAC_MACMSB
+	hex "MSB 24 bits of ethern number (hex)" 
+	default 00007A
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Most significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is 00007A.
+
+config GRLIB_OPENCORES_ETHERMAC_MACLSB
+	hex "LSB 24 bits of ethern number (hex)" 
+	default CC0012
+	depends on GRLIB_OPENCORES_ETHERMAC
+	---help---
+	  Least significant 24 bits of the default MAC address
+	  that is initialized when driver probes. A good guess 
+	  is CC0012.
+
+
+
+
+endmenu
+
+
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/Makefile linux-2.6.10/drivers/amba/opencores/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GRLIB_OPENCORES_ETHERMAC)		+= ethermac/ 
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile linux-2.6.10/drivers/amba/opencores/ethermac/Makefile
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/Makefile	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-y		+= open_eth.o
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.c	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,1181 @@
+/*
+ * Ethernet driver for Open Ethernet Controller (www.opencores.org).
+ *      Copyright (c) 2002 Simon Srot (simons@opencores.org)
+ *
+ * Based on:
+ *
+ * Ethernet driver for Motorola MPC8xx.
+ *      Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * mcen302.c: A Linux network driver for Mototrola 68EN302 MCU
+ *
+ *      Copyright (C) 1999 Aplio S.A. Written by Vadim Lebedev
+ *
+ * Right now XXBUFF_PREALLOC must be used, because MAC does not 
+ * handle unaligned buffers yet.  Also the cache inhibit calls
+ * should be used some day.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/cacheflush.h>
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/rtnetlink.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <asm/processor.h>	/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+ 
+#ifdef CONFIG_LEON
+#include <asm/leon.h>
+//#define OETH_INTERRUPT LEON_INTERRUPT_OPEN_ETH
+#define DEBUG 1
+#endif
+
+/*
+#define MACADDR1 0
+#define MACADDR2 0
+#define MACADDR3 0
+#define MACADDR4 0
+#define MACADDR5 0
+*/
+ 
+#define MACADDR0 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 16) & 0xff)
+#define MACADDR1 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 8) & 0xff)
+#define MACADDR2 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACMSB >> 0) & 0xff)
+#define MACADDR3 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 16) & 0xff)
+#define MACADDR4 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 8) & 0xff)
+#define MACADDR5 ((CONFIG_GRLIB_OPENCORES_ETHERMAC_MACLSB >> 0) & 0xff)
+
+#include "open_eth.h"
+
+//#define net_device device
+//#define __pa(x) (x)
+//#define __va(x) (x)
+#define __clear_user(add,len) memset((add),0,(len))
+
+
+#define RXBUFF_PREALLOC	1
+#define TXBUFF_PREALLOC	1
+
+//#define SRAM_BUFF	1
+//#define SRAM_BUFF_BASE	(FBMEM_BASE_ADD + 0x80000)
+
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT	(2*HZ)
+
+/* Buffer number (must be 2^n) 
+ */
+#define OETH_RXBD_NUM		8
+#define OETH_TXBD_NUM		8
+#define OETH_RXBD_NUM_MASK	(OETH_RXBD_NUM-1)
+#define OETH_TXBD_NUM_MASK	(OETH_TXBD_NUM-1)
+
+/* Buffer size 
+ */
+#define OETH_RX_BUFF_SIZE	2048
+#define OETH_TX_BUFF_SIZE	2048
+
+/* How many buffers per page 
+ */
+#define OETH_RX_BUFF_PPGAE	(PAGE_SIZE/OETH_RX_BUFF_SIZE)
+#define OETH_TX_BUFF_PPGAE	(PAGE_SIZE/OETH_TX_BUFF_SIZE)
+
+/* How many pages is needed for buffers 
+ */
+#define OETH_RX_BUFF_PAGE_NUM	(OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE)
+#define OETH_TX_BUFF_PAGE_NUM	(OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE)
+
+/* Buffer size  (if not XXBUF_PREALLOC 
+ */
+#define MAX_FRAME_SIZE		1518
+
+/* The buffer descriptors track the ring buffers.   
+ */
+struct oeth_private {
+	struct	sk_buff* rx_skbuff[OETH_RXBD_NUM];
+	struct	sk_buff* tx_skbuff[OETH_TXBD_NUM];
+
+	ushort	tx_next;			/* Next buffer to be sent */
+	ushort	tx_last;			/* Next buffer to be checked if packet sent */
+	ushort	tx_full;			/* Buffer ring fuul indicator */
+	ushort	rx_cur;				/* Next buffer to be checked if packet received */
+
+	oeth_regs	*regs;			/* Address of controller registers. */
+	oeth_bd		*rx_bd_base;		/* Address of Rx BDs. */
+	oeth_bd		*tx_bd_base;		/* Address of Tx BDs. */
+        ushort          irq;
+
+	struct net_device_stats stats;
+};
+
+static int oeth_open(struct net_device *dev);
+static int oeth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void oeth_rx(struct net_device *dev);
+static void oeth_tx(struct net_device *dev);
+static irqreturn_t oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int oeth_close(struct net_device *dev);
+static struct net_device_stats *oeth_get_stats(struct net_device *dev);
+static void oeth_set_multicast_list(struct net_device *dev);
+static int oeth_set_mac_address(struct net_device *dev,void *p);
+static int calc_crc(char *mac_addr);
+
+#define OETH_REGLOAD(a)	(LEON3_BYPASS_LOAD_PA(&(a)))
+#define OETH_REGSAVE(a,v) (LEON3_BYPASS_STORE_PA(&(a),v))
+#define OETH_REGORIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) | (v))))
+#define OETH_REGANDIN(a,v) (OETH_REGSAVE(a,(OETH_REGLOAD(a) & (v))))
+
+
+#if DEBUG
+static void
+oeth_print_packet(unsigned long add, int len)
+{
+  //	int i;
+
+	printk("ipacket: add = %x len = %d\n", (unsigned int)add, len);
+/*
+	for(i = 0; i < len; i++) {
+  		if(!(i % 16))
+    			printk("\n");
+  		printk(" %.2x", *(((unsigned char *)add) + i));
+	}
+*/
+      printk("\n");
+	printk("                             \n");
+}
+#endif
+
+static int
+oeth_open(struct net_device *dev)
+{
+
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	
+#if DEBUG
+	printk("oeth_open\n");
+#endif
+#ifndef RXBUFF_PREALLOC
+	struct  sk_buff *skb;
+	volatile oeth_bd *rx_bd;
+	int i;
+
+	rx_bd = cep->rx_bd_base;
+
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+		skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+		if (skb == NULL)
+      		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+		else
+		        OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+		        //rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = skb;
+
+		OETH_REGSAVE(rx_bd[i].addr,(unsigned long)skb->tail);
+		//rx_bd[i].addr = (unsigned long)skb->tail;
+	}
+        OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+#endif
+
+	/* Install our interrupt handler.
+	 */
+	request_irq(cep->irq, oeth_interrupt, 0, "eth", (void *)dev);
+
+	/* Enable receiver and transmiter 
+	 */
+        OETH_REGORIN(regs->moder , OETH_MODER_RXEN | OETH_MODER_TXEN);
+	//regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
+
+	return 0;
+}
+
+static int
+oeth_close(struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	oeth_regs *regs = (oeth_regs *)dev->base_addr;
+	volatile oeth_bd *bdp;
+	int i;
+
+#if DEBUG
+	printk("oeth_close\n");
+#endif
+	/* Free interrupt hadler 
+	 */
+	free_irq(cep->irq, (void *)dev);
+
+	/* Disable receiver and transmitesr 
+	 */
+        OETH_REGANDIN(regs->moder , ~(OETH_MODER_RXEN | OETH_MODER_TXEN));
+	//regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);	
+
+	bdp = cep->rx_bd_base;
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status, ~(OETH_TX_BD_STATS | OETH_TX_BD_READY));
+		//bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
+		bdp++;
+	}
+
+	bdp = cep->tx_bd_base;
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	        OETH_REGANDIN(bdp->len_status , ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY));
+		//bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
+		bdp++;
+	}
+
+#ifndef RXBUFF_PREALLOC
+
+	/* Free all alocated rx buffers 
+	 */
+	for (i = 0; i < OETH_RXBD_NUM; i++) {
+	
+		if (cep->rx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->rx_skbuff[i]); //, FREE_READ);
+		
+	}
+#endif
+#ifndef TXBUFF_PREALLOC
+
+	/* Free all alocated tx buffers 
+	 */
+	for (i = 0; i < OETH_TXBD_NUM; i++) {
+	
+		if (cep->tx_skbuff[i] != NULL)
+			dev_kfree_skb(cep->tx_skbuff[i]);//, FREE_WRITE);
+	}
+#endif
+
+	return 0;
+}
+
+static int
+oeth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct oeth_private *cep = (struct oeth_private *)dev->priv;
+	volatile oeth_bd *bdp;
+	unsigned long flags;
+
+	/* Fill in a Tx ring entry 
+	 */
+	bdp = cep->tx_bd_base + cep->tx_next;
+
+	if (cep->tx_full) {
+
+		/* All transmit buffers are full.  Bail out.
+		 */
+		printk("%s: tx queue full!.\n", dev->name);
+		return 1;
+	}
+
+	/* Clear all of the status flags.
+	 */
+	OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_STATS);
+	//bdp->len_status &= ~OETH_TX_BD_STATS;
+
+	/* If the frame is short, tell CPM to pad it.
+	 */
+	if (skb->len <= ETH_ZLEN)
+	        OETH_REGORIN(bdp->len_status , OETH_TX_BD_PAD);
+	        //bdp->len_status |= OETH_TX_BD_PAD;
+	else
+	        OETH_REGANDIN(bdp->len_status , ~OETH_TX_BD_PAD);
+	        //bdp->len_status &= ~OETH_TX_BD_PAD;
+
+#if DEBUG
+	printk("TX\n");
+	oeth_print_packet((unsigned long)skb->data, skb->len);
+#endif
+
+#ifdef TXBUFF_PREALLOC
+
+	/* Copy data in preallocated buffer */
+	if (skb->len > OETH_TX_BUFF_SIZE) {
+		printk("%s: tx frame too long!.\n", dev->name);
+		return 1;
+	}
+	else {
+	  
+	  memcpy(__va((unsigned char *)OETH_REGLOAD(bdp->addr)), skb->data, skb->len); 
+            __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+	    //memcpy(__va((unsigned char *)bdp->addr), skb->data, skb->len); 
+            //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+      }
+
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16));
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+
+	dev_kfree_skb(skb); // 	dev_kfree_skb(skb, FREE_WRITE);
+#else
+	/* Set buffer length and buffer pointer.
+	 */
+	OETH_REGSAVE(bdp->len_status , (OETH_REGLOAD(bdp->len_status) & 0x0000ffff) | (skb->len << 16))
+	//bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
+	OETH_REGSAVE(bdp->addr , (uint)__pa(skb->data));
+	//bdp->addr = (uint)__pa(skb->data);
+
+	/* Save skb pointer.
+	 */
+	cep->tx_skbuff[cep->tx_next] = skb;
+#endif
+
+	cep->tx_next = (cep->tx_next + 1) & OETH_TXBD_NUM_MASK;
+	
+	save_flags(flags); cli();
+
+	if (cep->tx_next == cep->tx_last)
+		cep->tx_full = 1;
+
+	/* Send it on its way.  Tell controller its ready, interrupt when done,
+	 * and to put the CRC on the end.
+	 */
+        OETH_REGORIN(bdp->len_status , (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC));
+	//bdp->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
+
+	dev->trans_start = jiffies;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The interrupt handler.
+ */
+static irqreturn_t
+oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct	net_device *dev = dev_id;
+	volatile struct	oeth_private *cep;
+	uint	int_events;
+      
+#if DEBUG
+      printk ("oeth_interrupt()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get the interrupt events that caused us to be here.
+	 */
+        int_events = OETH_REGLOAD( cep->regs->int_src);
+	//int_events = cep->regs->int_src;
+        OETH_REGSAVE(cep->regs->int_src , int_events);
+	//cep->regs->int_src = int_events;
+
+	/* Handle receive event in its own function.
+	 */
+	if (int_events & (OETH_INT_RXF | OETH_INT_RXE))
+		oeth_rx(dev_id);
+
+	/* Handle transmit event in its own function.
+	 */
+	if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
+		oeth_tx(dev_id);
+            netif_wake_queue(dev); //mark_bh(NET_BH);
+	}
+
+	/* Check for receive busy, i.e. packets coming but no place to
+	 * put them. 
+	 */
+	if (int_events & OETH_INT_BUSY) {
+		if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE)))
+			oeth_rx(dev_id);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static void
+oeth_tx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+
+#ifndef TXBUFF_PREALLOC
+	struct	sk_buff *skb;
+#endif
+
+#if DEBUG
+      printk ("oeth_tx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) {
+
+		bdp = cep->tx_bd_base + cep->tx_last;
+
+		if ((OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_READY) || 
+		//if ((bdp->len_status & OETH_TX_BD_READY) || 
+			((cep->tx_last == cep->tx_next) && !cep->tx_full))
+			break;
+
+		/* Check status for errors
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+
+		/* Check status for errors
+		 */
+                /*
+		if (bdp->len_status & OETH_TX_BD_LATECOL)
+			cep->stats.tx_window_errors++;
+		if (bdp->len_status & OETH_TX_BD_RETLIM)
+			cep->stats.tx_aborted_errors++;
+		if (bdp->len_status & OETH_TX_BD_UNDERRUN)
+			cep->stats.tx_fifo_errors++;
+		if (bdp->len_status & OETH_TX_BD_CARRIER)
+			cep->stats.tx_carrier_errors++;
+		if (bdp->len_status & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
+			cep->stats.tx_errors++;
+		*/
+
+		cep->stats.tx_packets++;
+		cep->stats.collisions += (OETH_REGLOAD(bdp->len_status) >> 4) & 0x000f;
+		//cep->stats.collisions += (bdp->len_status >> 4) & 0x000f;
+
+#ifndef TXBUFF_PREALLOC
+		skb = cep->tx_skbuff[cep->tx_last];
+
+		/* Free the sk buffer associated with this last transmit.
+		*/
+		dev_kfree_skb(skb);//, FREE_WRITE);
+#endif
+
+		if (cep->tx_full)
+			cep->tx_full = 0;
+	}
+}
+
+static void
+oeth_rx(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	volatile oeth_bd *bdp;
+	struct	sk_buff *skb;
+	int	pkt_len;
+	int	bad = 0;
+#ifndef RXBUFF_PREALLOC
+	struct	sk_buff *small_skb;
+#endif
+      
+#if DEBUG
+      printk ("oeth_rx()\n");
+#endif
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* First, grab all of the stats for the incoming packet.
+	 * These get messed up if we get called due to a busy condition.
+	 */
+	for (;;cep->rx_cur = (cep->rx_cur + 1) & OETH_RXBD_NUM_MASK) {
+
+		bdp = cep->rx_bd_base + cep->rx_cur;
+
+#ifndef RXBUFF_PREALLOC
+		skb = cep->rx_skbuff[cep->rx_cur];
+
+		if (skb == NULL) {
+
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			if (skb != NULL)
+			{
+				OETH_REGSAVE(bdp->addr , (unsigned long) skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long) skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+
+			continue;
+		}
+#endif
+			
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_EMPTY)
+		//if (bdp->len_status & OETH_RX_BD_EMPTY)
+			break;
+			
+		/* Check status for errors.
+		 */
+		if (OETH_REGLOAD(bdp->len_status) & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+		//if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+                  printk ("oeth: length error\n");
+			cep->stats.rx_length_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_DRIBBLE) {
+		//if (bdp->len_status & OETH_RX_BD_DRIBBLE) {
+                  printk ("oeth: dribble error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_CRCERR) {
+		//if (bdp->len_status & OETH_RX_BD_CRCERR) {
+                  printk ("oeth: crc error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_OVERRUN) {
+		//if (bdp->len_status & OETH_RX_BD_OVERRUN) {
+                  printk ("oeth: overrun error\n");
+			cep->stats.rx_crc_errors++;
+			bad = 1;
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_MISS) {
+		//if (bdp->len_status & OETH_RX_BD_MISS) {
+                  printk ("oeth: miss error\n");
+
+		}
+		if (OETH_REGLOAD(bdp->len_status) & OETH_RX_BD_LATECOL) {
+		//if (bdp->len_status & OETH_RX_BD_LATECOL) {
+                  printk ("oeth: latecol error\n");
+			cep->stats.rx_frame_errors++;
+			bad = 1;
+		}
+		
+		
+		if (bad) {
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+      //bdp->len_status &= ~OETH_RX_BD_STATS;
+      //bdp->len_status |= OETH_RX_BD_EMPTY;
+
+			continue;
+		}
+
+		/* Process the incoming frame.
+		 */
+		pkt_len = OETH_REGLOAD(bdp->len_status) >> 16;
+		//pkt_len = bdp->len_status >> 16;
+        
+#ifdef RXBUFF_PREALLOC
+		//skb = dev_alloc_skb(pkt_len);
+                skb = alloc_skb(pkt_len + 4, GFP_ATOMIC); //added from michael wurm's patches
+
+		if (skb == NULL) {
+			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+			cep->stats.rx_dropped++;
+		}
+		else {
+			skb_reserve(skb, 2); //added from michael wurm's patches
+			skb->dev = dev;
+
+                  __flush_page_to_ram((unsigned long)__va(OETH_REGLOAD(bdp->addr)));
+                  //__flush_page_to_ram((unsigned long)__va(bdp->addr));
+#if DEBUG
+			printk("RX\n");
+                  oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), pkt_len);
+                  //oeth_print_packet((unsigned long)(__va(bdp->addr)), pkt_len);
+#endif
+			memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+			//memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+		}
+
+		OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+		OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+		//bdp->len_status &= ~OETH_RX_BD_STATS;
+		//bdp->len_status |= OETH_RX_BD_EMPTY;
+#else //RXBUFF_PREALLOC
+
+		if (pkt_len < 128) {
+
+			small_skb = dev_alloc_skb(pkt_len);
+
+			if (small_skb) {
+				small_skb->dev = dev;
+
+                        __flush_page_to_ram(__va(OETH_REGLOAD(bdp->addr)));
+                        //__flush_page_to_ram(__va(bdp->addr));
+#if DEBUG
+				printk("RX short\n");
+                        oeth_print_packet((unsigned long)(__va(bdp->addr)), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+                        memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(OETH_REGLOAD(bdp->addr)), pkt_len);
+                        //memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
+
+                        small_skb->protocol = eth_type_trans(small_skb,dev);
+                        netif_rx(small_skb);
+				cep->stats.rx_packets++;
+			}
+			else {
+				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+	                        cep->stats.rx_dropped++;
+			}
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+			//bdp->len_status |= OETH_RX_BD_EMPTY;
+		}
+		else {
+        		skb->dev = dev;
+			skb_put(skb, OETH_REGLOAD(bdp->len_status) >> 16);
+			//skb_put(skb, bdp->len_status >> 16);
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			cep->stats.rx_packets++;
+#if DEBUG
+			printk("RX long\n");
+                        oeth_print_packet((unsigned long)(__va(OETH_REGLOAD(bdp->addr))), OETH_REGLOAD(bdp->len_status) >> 16);
+                        //oeth_print_packet((unsigned long)(__va(bdp->addr)), bdp->len_status >> 16);
+#endif
+		
+			skb = dev_alloc_skb(MAX_FRAME_SIZE);
+
+			OETH_REGANDIN(bdp->len_status , ~OETH_RX_BD_STATS);
+			//bdp->len_status &= ~OETH_RX_BD_STATS;
+        
+			if (skb) {
+				cep->rx_skbuff[cep->rx_cur] = skb;
+
+				OETH_REGSAVE(bdp->addr , (unsigned long)skb->tail);
+				OETH_REGORIN(bdp->len_status , OETH_RX_BD_EMPTY);
+				//bdp->addr = (unsigned long)skb->tail;
+				//bdp->len_status |= OETH_RX_BD_EMPTY;
+			}
+			else {
+				cep->rx_skbuff[cep->rx_cur] = NULL;	
+			}
+		}
+#endif //!RXBUFF_PREALLOC
+	}
+
+#if DEBUG
+      printk ("oeth_rx sent()\n");
+#endif
+}
+
+static int calc_crc(char *mac_addr)
+{
+	int result = 0;
+	return (result & 0x3f);
+}
+
+static struct net_device_stats *oeth_get_stats(struct net_device *dev)
+{
+        struct oeth_private *cep = (struct oeth_private *)dev->priv;
+ 
+        return &cep->stats;
+}
+
+static void oeth_set_multicast_list(struct net_device *dev)
+{
+	struct	oeth_private *cep;
+	struct	dev_mc_list *dmi;
+	volatile oeth_regs *regs;
+	int	i;
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Get pointer of controller registers.
+	 */
+	regs = (oeth_regs *)dev->base_addr;
+
+	if (dev->flags & IFF_PROMISC) {
+	  
+		/* Log any net taps. 
+		 */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		OETH_REGORIN(regs->moder , OETH_MODER_PRO);
+		//regs->moder |= OETH_MODER_PRO;
+	} else {
+
+		OETH_REGANDIN(regs->moder , ~OETH_MODER_PRO);
+		//regs->moder &= ~OETH_MODER_PRO;
+
+		if (dev->flags & IFF_ALLMULTI) {
+
+			/* Catch all multicast addresses, so set the
+			 * filter to all 1's.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0xffffffff);
+			OETH_REGSAVE(regs->hash_addr1 , 0xffffffff);
+			//regs->hash_addr0 = 0xffffffff;
+			//regs->hash_addr1 = 0xffffffff;
+		}
+		else if (dev->mc_count) {
+
+                        OETH_REGORIN(regs->moder , OETH_MODER_IAM);
+                        //regs->moder |= OETH_MODER_IAM;
+                        
+			/* Clear filter and add the addresses in the list.
+			 */
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			OETH_REGSAVE(regs->hash_addr0 , 0x00000000);
+			//regs->hash_addr0 = 0x00000000;
+			//regs->hash_addr0 = 0x00000000;
+
+			dmi = dev->mc_list;
+
+			for (i = 0; i < dev->mc_count; i++) {
+				
+				int hash_b;
+
+				/* Only support group multicast for now.
+				 */
+				if (!(dmi->dmi_addr[0] & 1))
+					continue;
+
+				hash_b = calc_crc(dmi->dmi_addr); 
+				if(hash_b >= 32)
+					OETH_REGORIN(regs->hash_addr1 , 1 << (hash_b - 32));
+				        //regs->hash_addr1 |= 1 << (hash_b - 32);
+				else
+					OETH_REGORIN(regs->hash_addr0 , 1 << hash_b);
+				        //regs->hash_addr0 |= 1 << hash_b;
+			}
+		}
+	}
+}
+
+static int oeth_set_mac_address(struct net_device *dev,void *p)
+{
+	struct sockaddr *addr=p;
+	volatile oeth_regs *regs;
+      
+	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+      
+	regs = (oeth_regs *)dev->base_addr;
+      
+    
+	    
+// old version: sa_data is of type char, will be expanded to int when ored
+// so negative values e.g 0xB5 will be expanded to 0xffffffB5 and ored
+/*
+	regs->mac_addr1 = 	addr->sa_data[0] << 8 	|
+            			addr->sa_data[1];
+        regs->mac_addr0 = 	addr->sa_data[2] << 24 	|
+            			addr->sa_data[3] << 16 	|
+            			addr->sa_data[4] << 8 	|
+            			addr->sa_data[5];
+
+*/
+
+// dev_addr is of type unsigned char and will be expanded to unsigned int which is ok
+	OETH_REGSAVE(regs->mac_addr1 , 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1]);
+        OETH_REGSAVE(regs->mac_addr0 , 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5]);
+
+	/*	    
+	regs->mac_addr1 = 	dev->dev_addr[0] << 8 	|
+            			dev->dev_addr[1];
+        regs->mac_addr0 = 	dev->dev_addr[2] << 24 	|
+            			dev->dev_addr[3] << 16 	|
+            			dev->dev_addr[4] << 8 	|
+            			dev->dev_addr[5];
+	*/  
+	    
+	    
+	return 0;
+}
+
+/* Initialize the Open Ethernet MAC.
+ */
+int do_oeth_probe(struct net_device *dev)
+{
+	struct oeth_private *cep;
+	volatile oeth_regs *regs;
+	volatile oeth_bd *tx_bd, *rx_bd;
+	int i, j, k, l;
+#ifdef SRAM_BUFF
+	unsigned long mem_addr = SRAM_BUFF_BASE;
+#else
+	unsigned long mem_addr;
+#endif
+	unsigned long base;
+
+	amba_ahb_device adev[1];
+	l = amba_get_free_ahbslv_devices (VENDOR_GAISLER, GAISLER_ETHAHB, adev, 1);
+	if (l == 0) {
+	  return 1;
+	}
+	
+	base = adev[0].start[0];
+
+	//printk("Probing Open Ethernet Core at 0x%x (irq:%i,n:%s)\n",adev[0].start[0], adev[0].irq, dev ->name);
+
+	cep = (struct oeth_private *)dev->priv;
+
+	/* Allocate a new 'dev' if needed. 
+	 */
+	if (dev == NULL) {
+		/*
+		 * Don't allocate the private data here, it is done later
+		 * This makes it easier to free the memory when this driver
+		 * is used as a module.
+		 */
+//		dev = init_etherdev(0, 0);
+                dev=alloc_etherdev(0);		
+//		dev = alloc_netdev(0, "eth0", setup_ether);
+		if (dev == NULL)
+			return -ENOMEM;
+	}
+
+
+
+
+	/* Initialize the device structure. 
+	 */
+	if (dev->priv == NULL) {
+		cep = (struct oeth_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+		dev->priv = cep;
+		if (dev->priv == NULL)
+			return -ENOMEM;
+	}
+	
+	__clear_user(cep,sizeof(*cep));
+
+	/* Get pointer ethernet controller configuration registers.
+	 */
+	cep->regs = (oeth_regs *)(OETH_REG_BASE(base));
+	regs = (oeth_regs *)(OETH_REG_BASE(base));
+	cep->irq = adev[0].irq;
+
+	/* Reset the controller.
+	 */
+	OETH_REGSAVE(regs->moder , OETH_MODER_RST);	/* Reset ON */
+	OETH_REGANDIN(regs->moder , ~OETH_MODER_RST);	/* Reset OFF */
+	//regs->moder = OETH_MODER_RST;	/* Reset ON */
+	//regs->moder &= ~OETH_MODER_RST;	/* Reset OFF */
+
+	/* Setting TXBD base to OETH_TXBD_NUM.
+	 */
+	OETH_REGSAVE(regs->tx_bd_num , OETH_TXBD_NUM);
+	//regs->tx_bd_num = OETH_TXBD_NUM;
+	
+	/* Initialize TXBD pointer
+	 */
+	cep->tx_bd_base = (oeth_bd *)OETH_BD_BASE(base);
+	tx_bd = (volatile oeth_bd *)OETH_BD_BASE(base);
+
+	/* Initialize RXBD pointer
+	 */
+	cep->rx_bd_base = ((oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+	rx_bd = ((volatile oeth_bd *)OETH_BD_BASE(base)) + OETH_TXBD_NUM;
+
+	/* Initialize transmit pointers.
+	 */
+	cep->rx_cur = 0;
+	cep->tx_next = 0;
+	cep->tx_last = 0;
+	cep->tx_full = 0;
+
+	/* Set min/max packet length 
+	 */
+	OETH_REGSAVE(regs->packet_len , 0x00400600);
+	//regs->packet_len = 0x00400600;
+
+	/* Set IPGT register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgt , 0x00000012);
+	//regs->ipgt = 0x00000012;
+
+	/* Set IPGR1 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr1 , 0x0000000c);
+	//regs->ipgr1 = 0x0000000c;
+
+	/* Set IPGR2 register to recomended value 
+	 */
+	OETH_REGSAVE(regs->ipgr2 , 0x00000012);
+	//regs->ipgr2 = 0x00000012;
+
+	/* Set COLLCONF register to recomended value 
+	 */
+	OETH_REGSAVE(regs->collconf , 0x000f003f);
+	//regs->collconf = 0x000f003f;
+
+	/* Set control module mode 
+	 */
+#if 0
+	OETH_REGSAVE(regs->ctrlmoder , OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW);
+	//regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW;
+#else
+	OETH_REGSAVE(regs->ctrlmoder , 0);
+	//regs->ctrlmoder = 0;
+#endif
+
+  /* Set PHY to show Tx status, Rx status and Link status */
+  /*regs->miiaddress = 20<<8;
+  regs->miitx_data = 0x1422;
+  regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;*/
+ 
+  // switch to 10 mbit ethernet
+  OETH_REGSAVE(regs->miiaddress , 0);
+  OETH_REGSAVE(regs->miitx_data , 0);
+  OETH_REGSAVE(regs->miicommand , OETH_MIICOMMAND_WCTRLDATA);
+  //regs->miiaddress = 0;
+  //regs->miitx_data = 0;
+  //regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
+  
+#ifdef TXBUFF_PREALLOC
+
+	/* Initialize TXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(tx_bd[k].len_status , OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(tx_bd[k].addr , __pa(mem_addr));
+			//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+			//tx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_TX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#else
+
+ 	/* Initialize TXBDs.
+	 */
+	for(i = 0; i < OETH_TXBD_NUM; i++) {
+
+		cep->tx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(tx_bd[i].len_status , (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ);
+		OETH_REGSAVE(tx_bd[i].addr , 0);
+		//tx_bd[i].len_status = (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
+		//tx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(tx_bd[OETH_TXBD_NUM - 1].len_status , OETH_TX_BD_WRAP);
+	//tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+#endif
+
+#ifdef RXBUFF_PREALLOC
+
+	/* Initialize RXBDs.
+	 */
+	for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) {
+
+#ifndef SRAM_BUFF
+		mem_addr = __get_free_page(GFP_KERNEL);
+#endif
+
+		for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) {
+			OETH_REGSAVE(rx_bd[k].len_status , OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ);
+			OETH_REGSAVE(rx_bd[k].addr , __pa(mem_addr));
+			//rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+			//rx_bd[k].addr = __pa(mem_addr);
+			mem_addr += OETH_RX_BUFF_SIZE;
+		}
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#else
+	/* Initialize RXBDs.
+	 */
+	for(i = 0; i < OETH_RXBD_NUM; i++) {
+
+
+		OETH_REGSAVE(rx_bd[i].len_status , (0 << 16) | OETH_RX_BD_IRQ);
+		//rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
+
+		cep->rx_skbuff[i] = NULL;
+
+		OETH_REGSAVE(rx_bd[i].addr , 0);
+		//rx_bd[i].addr = 0;
+	}
+	OETH_REGORIN(rx_bd[OETH_RXBD_NUM - 1].len_status , OETH_RX_BD_WRAP);
+	//rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+#endif
+	
+	/* Set default ethernet station address.
+	 */
+	dev->dev_addr[0] = MACADDR0;
+	dev->dev_addr[1] = MACADDR1;
+	dev->dev_addr[2] = MACADDR2;
+	dev->dev_addr[3] = MACADDR3;
+	dev->dev_addr[4] = MACADDR4;
+	dev->dev_addr[5] = MACADDR5;
+
+	OETH_REGSAVE(regs->mac_addr1 , MACADDR0 << 8 | MACADDR1);
+	OETH_REGSAVE(regs->mac_addr0 , MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5);
+	//regs->mac_addr1 = MACADDR0 << 8 | MACADDR1;
+	//regs->mac_addr0 = MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5;
+	
+	/* Clear all pending interrupts 
+	 */
+	OETH_REGSAVE(regs->int_src , 0xffffffff);
+	//regs->int_src = 0xffffffff;
+
+	/* Promisc, IFG, CRCEn
+	 */
+	OETH_REGORIN(regs->moder , OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN);
+	//regs->moder |= OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN;
+
+	/* Enable interrupt sources.
+	 */
+	OETH_REGSAVE(regs->int_mask , OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC);
+	/*	regs->int_mask = OETH_INT_MASK_TXB 	| 
+			OETH_INT_MASK_TXE 	| 
+			OETH_INT_MASK_RXF 	| 
+			OETH_INT_MASK_RXE 	|
+			OETH_INT_MASK_BUSY 	|
+			OETH_INT_MASK_TXC	|
+			OETH_INT_MASK_RXC;
+	*/
+	/* Fill in the fields of the device structure with ethernet values. 
+	 */
+	ether_setup(dev);
+
+	dev->base_addr = (unsigned long)OETH_REG_BASE(base);
+
+	/* The Open Ethernet specific entries in the device structure. 
+	 */
+	dev->open = oeth_open;
+	dev->hard_start_xmit = oeth_start_xmit;
+	dev->stop = oeth_close;
+	dev->get_stats = oeth_get_stats;
+	dev->set_multicast_list = oeth_set_multicast_list;
+	dev->set_mac_address = oeth_set_mac_address;
+
+	if (register_netdev(dev)) {
+	  kfree(dev->priv);
+	  printk(KERN_ERR "open_eth: netdevice registration failed.\n");
+	  return -ENOMEM;
+        }
+
+	printk("%s: Open Ethernet Core Version 1.0 at [0x%x] irq %i\n", dev->name,(unsigned int)(cep->regs),(unsigned int)(cep->irq));
+
+	return 0;
+}
+	
+struct net_device *grlib_oeth_probe(int unit) {
+  
+  struct net_device *dev = alloc_etherdev(0);
+  int err;
+  
+  if (!dev)
+    return ERR_PTR(-ENOMEM);
+  if (unit >= 0)
+    sprintf(dev->name, "eth%d", unit);
+  SET_MODULE_OWNER(dev);
+  err = do_oeth_probe(dev);
+  if (err) {
+    free_netdev(dev);
+    return ERR_PTR(err);
+  }
+  return dev;
+
+  //      printk("Init: Open Ethernet probe\n");
+  //    oeth_dev=alloc_etherdev(sizeof(struct oeth_private));
+  //    return do_oeth_probe(oeth_dev);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef MODULE
+static struct net_device		*oeth_dev;		/* netdevice struct */
+
+int
+init_module(void)
+{
+  oeth_dev = grlib_oeth_probe(-1);
+  if (IS_ERR(oeth_dev)) {
+    printk(KERN_WARNING "Grlib Oeth: No core found\n");
+    return PTR_ERR(oeth_dev);
+  }
+  return 0;
+}
+
+void cleanup_module(void) {
+	
+  printk("Open Ethernet Core cleanup\n");
+  if (oeth_dev) {
+    unregister_netdev(oeth_dev);
+    kfree(oeth_dev);
+  }
+}
+
+//module_init(grlib_oeth_probe);
+//module_exit(oeth_cleanup);
+MODULE_LICENSE("GPL");
+
+#endif
+
diff -Naur ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h
--- ../linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/drivers/amba/opencores/ethermac/open_eth.h	2005-01-03 11:36:33.000000000 +0100
@@ -0,0 +1,143 @@
+/* Ethernet configuration registers */
+typedef struct _oeth_regs {
+        uint    moder;          /* Mode Register */
+        uint    int_src;        /* Interrupt Source Register */
+        uint    int_mask;       /* Interrupt Mask Register */
+        uint    ipgt;           /* Back to Bak Inter Packet Gap Register */
+        uint    ipgr1;          /* Non Back to Back Inter Packet Gap Register 1 */
+        uint    ipgr2;          /* Non Back to Back Inter Packet Gap Register 2 */
+        uint    packet_len;     /* Packet Length Register (min. and max.) */
+        uint    collconf;       /* Collision and Retry Configuration Register */
+        uint    tx_bd_num;      /* Transmit Buffer Descriptor Number Register */
+        uint    ctrlmoder;      /* Control Module Mode Register */
+        uint    miimoder;       /* MII Mode Register */
+        uint    miicommand;     /* MII Command Register */
+        uint    miiaddress;     /* MII Address Register */
+        uint    miitx_data;     /* MII Transmit Data Register */
+        uint    miirx_data;     /* MII Receive Data Register */
+        uint    miistatus;      /* MII Status Register */
+        uint    mac_addr0;      /* MAC Individual Address Register 0 */
+        uint    mac_addr1;      /* MAC Individual Address Register 1 */
+        uint    hash_addr0;     /* Hash Register 0 */
+        uint    hash_addr1;     /* Hash Register 1 */                           
+} oeth_regs;
+
+/* Ethernet buffer descriptor */
+typedef struct _oeth_bd {
+#if 0
+        ushort  len;            /* Buffer length */
+        ushort  status;         /* Buffer status */
+#else
+        uint    len_status;
+#endif
+        uint    addr;           /* Buffer address */
+} oeth_bd;
+
+#define OETH_REG_BASE(b)        (b)
+#define OETH_BD_BASE(b)         ((b) + 0x400)
+#define OETH_TOTAL_BD           128
+#define OETH_MAXBUF_LEN         0x600
+                                
+/* Tx BD */                     
+#define OETH_TX_BD_READY        0x8000 /* Tx BD Ready */
+#define OETH_TX_BD_IRQ          0x4000 /* Tx BD IRQ Enable */
+#define OETH_TX_BD_WRAP         0x2000 /* Tx BD Wrap (last BD) */
+#define OETH_TX_BD_PAD          0x1000 /* Tx BD Pad Enable */
+#define OETH_TX_BD_CRC          0x0800 /* Tx BD CRC Enable */
+                                
+#define OETH_TX_BD_UNDERRUN     0x0100 /* Tx BD Underrun Status */
+#define OETH_TX_BD_RETRY        0x00F0 /* Tx BD Retry Status */
+#define OETH_TX_BD_RETLIM       0x0008 /* Tx BD Retransmission Limit Status */
+#define OETH_TX_BD_LATECOL      0x0004 /* Tx BD Late Collision Status */
+#define OETH_TX_BD_DEFER        0x0002 /* Tx BD Defer Status */
+#define OETH_TX_BD_CARRIER      0x0001 /* Tx BD Carrier Sense Lost Status */
+#define OETH_TX_BD_STATS        (OETH_TX_BD_UNDERRUN            | \
+                                OETH_TX_BD_RETRY                | \
+                                OETH_TX_BD_RETLIM               | \
+                                OETH_TX_BD_LATECOL              | \
+                                OETH_TX_BD_DEFER                | \
+                                OETH_TX_BD_CARRIER)
+                                
+/* Rx BD */                     
+#define OETH_RX_BD_EMPTY        0x8000 /* Rx BD Empty */
+#define OETH_RX_BD_IRQ          0x4000 /* Rx BD IRQ Enable */
+#define OETH_RX_BD_WRAP         0x2000 /* Rx BD Wrap (last BD) */
+                                
+#define OETH_RX_BD_MISS         0x0080 /* Rx BD Miss Status */
+#define OETH_RX_BD_OVERRUN      0x0040 /* Rx BD Overrun Status */
+#define OETH_RX_BD_INVSIMB      0x0020 /* Rx BD Invalid Symbol Status */
+#define OETH_RX_BD_DRIBBLE      0x0010 /* Rx BD Dribble Nibble Status */
+#define OETH_RX_BD_TOOLONG      0x0008 /* Rx BD Too Long Status */
+#define OETH_RX_BD_SHORT        0x0004 /* Rx BD Too Short Frame Status */
+#define OETH_RX_BD_CRCERR       0x0002 /* Rx BD CRC Error Status */
+#define OETH_RX_BD_LATECOL      0x0001 /* Rx BD Late Collision Status */
+#define OETH_RX_BD_STATS        (OETH_RX_BD_MISS                | \
+                                OETH_RX_BD_OVERRUN              | \
+                                OETH_RX_BD_INVSIMB              | \
+                                OETH_RX_BD_DRIBBLE              | \
+                                OETH_RX_BD_TOOLONG              | \
+                                OETH_RX_BD_SHORT                | \
+                                OETH_RX_BD_CRCERR               | \
+                                OETH_RX_BD_LATECOL)
+
+/* MODER Register */
+#define OETH_MODER_RXEN         0x00000001 /* Receive Enable  */
+#define OETH_MODER_TXEN         0x00000002 /* Transmit Enable */
+#define OETH_MODER_NOPRE        0x00000004 /* No Preamble  */
+#define OETH_MODER_BRO          0x00000008 /* Reject Broadcast */
+#define OETH_MODER_IAM          0x00000010 /* Use Individual Hash */
+#define OETH_MODER_PRO          0x00000020 /* Promiscuous (receive all) */
+#define OETH_MODER_IFG          0x00000040 /* Min. IFG not required */
+#define OETH_MODER_LOOPBCK      0x00000080 /* Loop Back */
+#define OETH_MODER_NOBCKOF      0x00000100 /* No Backoff */
+#define OETH_MODER_EXDFREN      0x00000200 /* Excess Defer */
+#define OETH_MODER_FULLD        0x00000400 /* Full Duplex */
+#define OETH_MODER_RST          0x00000800 /* Reset MAC */
+#define OETH_MODER_DLYCRCEN     0x00001000 /* Delayed CRC Enable */
+#define OETH_MODER_CRCEN        0x00002000 /* CRC Enable */
+#define OETH_MODER_HUGEN        0x00004000 /* Huge Enable */
+#define OETH_MODER_PAD          0x00008000 /* Pad Enable */
+#define OETH_MODER_RECSMALL     0x00010000 /* Receive Small */
+ 
+/* Interrupt Source Register */
+#define OETH_INT_TXB            0x00000001 /* Transmit Buffer IRQ */
+#define OETH_INT_TXE            0x00000002 /* Transmit Error IRQ */
+#define OETH_INT_RXF            0x00000004 /* Receive Frame IRQ */
+#define OETH_INT_RXE            0x00000008 /* Receive Error IRQ */
+#define OETH_INT_BUSY           0x00000010 /* Busy IRQ */
+#define OETH_INT_TXC            0x00000020 /* Transmit Control Frame IRQ */
+#define OETH_INT_RXC            0x00000040 /* Received Control Frame IRQ */
+
+/* Interrupt Mask Register */
+#define OETH_INT_MASK_TXB       0x00000001 /* Transmit Buffer IRQ Mask */
+#define OETH_INT_MASK_TXE       0x00000002 /* Transmit Error IRQ Mask */
+#define OETH_INT_MASK_RXF       0x00000004 /* Receive Frame IRQ Mask */
+#define OETH_INT_MASK_RXE       0x00000008 /* Receive Error IRQ Mask */
+#define OETH_INT_MASK_BUSY      0x00000010 /* Busy IRQ Mask */
+#define OETH_INT_MASK_TXC       0x00000020 /* Transmit Control Frame IRQ Mask */
+#define OETH_INT_MASK_RXC       0x00000040 /* Received Control Frame IRQ Mask */
+ 
+/* Control Module Mode Register */
+#define OETH_CTRLMODER_PASSALL  0x00000001 /* Pass Control Frames */
+#define OETH_CTRLMODER_RXFLOW   0x00000002 /* Receive Control Flow Enable */
+#define OETH_CTRLMODER_TXFLOW   0x00000004 /* Transmit Control Flow Enable */
+                               
+/* MII Mode Register */        
+#define OETH_MIIMODER_CLKDIV    0x000000FF /* Clock Divider */
+#define OETH_MIIMODER_NOPRE     0x00000100 /* No Preamble */
+#define OETH_MIIMODER_RST       0x00000200 /* MIIM Reset */
+ 
+/* MII Command Register */
+#define OETH_MIICOMMAND_SCANSTAT  0x00000001 /* Scan Status */
+#define OETH_MIICOMMAND_RSTAT     0x00000002 /* Read Status */
+#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */
+ 
+/* MII Address Register */
+#define OETH_MIIADDRESS_FIAD    0x0000001F /* PHY Address */
+#define OETH_MIIADDRESS_RGAD    0x00001F00 /* RGAD Address */
+ 
+/* MII Status Register */
+#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */
+#define OETH_MIISTATUS_BUSY     0x00000002 /* MII Busy */
+#define OETH_MIISTATUS_NVALID   0x00000004 /* Data in MII Status Register is invalid */
+
diff -Naur ../linux-2.6.10/drivers/net/Space.c linux-2.6.10/drivers/net/Space.c
--- ../linux-2.6.10/drivers/net/Space.c	2004-12-24 22:33:59.000000000 +0100
+++ linux-2.6.10/drivers/net/Space.c	2005-01-03 11:36:33.000000000 +0100
@@ -93,6 +93,7 @@
 extern struct net_device *mc32_probe(int unit);
 extern struct net_device *cops_probe(int unit);
 extern struct net_device *ltpc_probe(void);
+extern struct net_device *grlib_oeth_probe(int unit);
   
 /* Detachable devices ("pocket adaptors") */
 extern struct net_device *de620_probe(int unit);
@@ -312,6 +313,13 @@
 	{NULL, 0},
 };
 
+static struct devprobe2 sparc_probes[] __initdata = {
+#ifdef CONFIG_GRLIB_OPENCORES_ETHERMAC
+	{grlib_oeth_probe, 0},
+#endif
+	{NULL, 0},
+};
+
 /*
  * Unified ethernet device probe, segmented per architecture and
  * per bus interface. This drives the legacy devices only for now.
@@ -326,6 +334,7 @@
 
 	(void)(	probe_list2(unit, m68k_probes, base_addr == 0) &&
 		probe_list2(unit, mips_probes, base_addr == 0) &&
+		probe_list2(unit, sparc_probes, base_addr == 0) &&
 		probe_list2(unit, eisa_probes, base_addr == 0) &&
 		probe_list2(unit, mca_probes, base_addr == 0) &&
 		probe_list2(unit, isa_probes, base_addr == 0) &&

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-01-05 15:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-04 19:04 [4/7] LEON SPARC V8 processor support for linux-2.6.10 Jiri Gaisler
2005-01-04 19:04 ` Jiri Gaisler
2005-01-05 15:18 ` Jiri Gaisler
2005-01-05 15:18   ` Jiri Gaisler

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.