Index: c/src/lib/libbsp/powerpc/gen5200/ChangeLog
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/ChangeLog	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/ChangeLog	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -1,2 +1,23 @@
+2011-06-17	Sebastian Huber <sebastian.huber@embedded-brains.de>
+
+	* Makefile.am: Added custom memcpy().  Update for network sources.
+	* configure.ac: Enable interrupt driven Termios for all BSPs.
+	* ide/pcmcia_ide.c: Disable broken DMA support.
+	* include/bsp.h: Fixed NEED_LOW_LEVEL_INIT define.  Set default
+	console baud to 115200.
+	* include/irq.h, irq/irq.c: Fixed interrupt handling to avoid the
+	following problems: 1. multiple invokation of peripheral interrupt
+	handlers, 2. missing synchronization after mask write and enabling of
+	external exceptions, and 3. logic overhead.
+	* network_5200/network.c: Added MII interface.  Fixed controller
+	restart after FIFO errors.  Performance improvements.
+	* start/start.S: Fixed ROM startup.  Initialize XLB arbiter for all
+	BSPs.
+	* startup/bspstart.c: Special intialization for MPC5200B (B variant).
+	Install standard alignment handler.
+	* startup/cpuinit.c, startup/linkcmds.brs5l, startup/linkcmds.dp2,
+	startup/linkcmds.icecube, startup/linkcmds.pm520_cr825,
+	startup/linkcmds.pm520_ze30: Avoid accesses outside the RAM area.
+
 2011-06-07	Sebastian Huber <sebastian.huber@embedded-brains.de>
 
Index: c/src/lib/libbsp/powerpc/gen5200/Makefile.am
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/Makefile.am	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/Makefile.am	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -143,4 +143,5 @@
 	../../shared/bspgetworkarea.c \
 	../shared/startup/bspidle.c \
+	../shared/src/memcpy.c \
 	startup/bspstart.c \
 	startup/cpuinit.c  \
@@ -148,10 +149,5 @@
 
 if HAS_NETWORKING
-network_CPPFLAGS = -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
-network_CPPFLAGS += -D__BSD_VISIBLE
-noinst_PROGRAMS += network.rel
-network_rel_SOURCES = network_5200/network.c
-network_rel_CPPFLAGS = $(AM_CPPFLAGS) $(network_CPPFLAGS)
-network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+libbsp_a_SOURCES += network_5200/network.c
 endif
 
@@ -164,8 +160,4 @@
 	../../../libcpu/@RTEMS_CPU@/mpc6xx/timer.rel
 
-if HAS_NETWORKING
-libbsp_a_LIBADD += network.rel
-endif
-
 include $(srcdir)/preinstall.am
 include $(top_srcdir)/../../../../automake/local.am
Index: c/src/lib/libbsp/powerpc/gen5200/configure.ac
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/configure.ac	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/configure.ac	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -83,9 +83,8 @@
 RTEMS_BSPOPTS_HELP([MPC5200_PSC_INDEX_FOR_GPS_MODULE],[PSC index for GPS module, if defined results in '/dev/gps'])
 
-RTEMS_BSPOPTS_SET([SINGLE_CHAR_MODE],[dp2],[])
-RTEMS_BSPOPTS_SET([SINGLE_CHAR_MODE],[*],[1])
+RTEMS_BSPOPTS_SET([SINGLE_CHAR_MODE],[*],[])
 RTEMS_BSPOPTS_HELP([SINGLE_CHAR_MODE],[enable single character mode for the PSC console driver])
 
-RTEMS_BSPOPTS_SET([UARTS_USE_TERMIOS_INT],[dp2],[1])
+RTEMS_BSPOPTS_SET([UARTS_USE_TERMIOS_INT],[*],[1])
 RTEMS_BSPOPTS_HELP([UARTS_USE_TERMIOS_INT],[enable interrupt support for the PSC console driver])
 
Index: c/src/lib/libbsp/powerpc/gen5200/ide/pcmcia_ide.c
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/ide/pcmcia_ide.c	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/ide/pcmcia_ide.c	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -93,13 +93,5 @@
 #define IDE_DMA_TEST            FALSE
 
-#ifdef BRS5L
-#define IDE_USE_INT             TRUE
-#define IDE_READ_USE_DMA        TRUE
-#define IDE_USE_READ_PIO_OPT    FALSE
-#define IDE_WRITE_USE_DMA       TRUE
-#define IDE_USE_WRITE_PIO_OPT   TRUE
-/* #define IDE_USE_DMA (IDE_READ_USE_DMA||IDE_WRITE_USE_DMA) */
-#define IDE_USE_DMA             TRUE
-#else
+/* DMA supported PIO mode is broken */
 #define IDE_USE_INT             TRUE
 #define IDE_READ_USE_DMA        FALSE
@@ -107,7 +99,5 @@
 #define IDE_WRITE_USE_DMA       FALSE
 #define IDE_USE_WRITE_PIO_OPT   FALSE
-/* #define IDE_USE_DMA (IDE_READ_USE_DMA||IDE_WRITE_USE_DMA) */
-#define IDE_USE_DMA             FALSE
-#endif
+#define IDE_USE_DMA (IDE_READ_USE_DMA || IDE_WRITE_USE_DMA)
 
 #define IDE_USE_STATISTICS      TRUE
@@ -465,4 +455,5 @@
         (*pos) += bufs[bufs_from_dma].length;
         bufs_from_dma++;
+        bds_free++;
 	  }
     } while ((nxt_bd_idx != TASK_ERR_BD_RING_EMPTY) &&
Index: c/src/lib/libbsp/powerpc/gen5200/include/bsp.h
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/include/bsp.h	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/include/bsp.h	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -80,4 +80,9 @@
 #endif
 
+#if !defined(HAS_UBOOT)
+  /* we need the low level initialization in start.S*/
+  #define NEED_LOW_LEVEL_INIT
+#endif
+
 #if defined(BRS5L)
 /*
@@ -118,9 +123,4 @@
 #include <bsp/vectors.h>
 #include <bsp/u-boot.h>
-
-#if !defined(HAS_UBOOT)
-  /* we need the low level initialization in start.S*/
-  #define NEED_LOW_LEVEL_INIT
-#endif
 
 /*
@@ -180,5 +180,5 @@
 #define GEN5200_CONSOLE_BAUD (bsp_uboot_board_info.bi_baudrate)
 #else
-#define GEN5200_CONSOLE_BAUD 9600
+#define GEN5200_CONSOLE_BAUD 115200
 #endif
 
Index: c/src/lib/libbsp/powerpc/gen5200/include/irq.h
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/include/irq.h	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/include/irq.h	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -88,14 +88,11 @@
 #define LIBBSP_POWERPC_GEN5200_IRQ_H
 
-#define CHK_CE_SHADOW(_pmce)	((_pmce) & 0x00000001)
-#define CHK_CSE_STICKY(_pmce)	(((_pmce) >> 10) & 0x00000001)
-#define CHK_MSE_STICKY(_pmce)	(((_pmce) >> 21) & 0x00000001)
-#define CHK_PSE_STICKY(_pmce)	(((_pmce) >> 29) & 0x00000001)
-#define CLR_CSE_STICKY(_pmce)	((_pmce) |= (1 << 29 ))
-#define CLR_MSE_STICKY(_pmce)	((_pmce) |= (1 << 21 ))
-#define CLR_PSE_STICKY(_pmce)	((_pmce) |= (1 << 10 ))
-#define CSE_SOURCE(_source)	(((_source) >> 8) & 0x00000003)
-#define MSE_SOURCE(_source)	(((_source) >> 16) & 0x0000001F)
-#define PSE_SOURCE(_source)	(((_source) >> 24) & 0x0000001F)
+#define PMCE_CE_SHADOW (1U << (31 - 31))
+#define PMCE_CSE_STICKY (1U << (31 - 21))
+#define PMCE_MSE_STICKY (1U << (31 - 10))
+#define PMCE_PSE_STICKY (1U << (31 - 2))
+#define PMCE_CSE_SOURCE(_pmce) (((_pmce) >> 8) & 0x3U)
+#define PMCE_MSE_SOURCE(_pmce) (((_pmce) >> 16) & 0x1fU)
+#define PMCE_PSE_SOURCE(_pmce) (((_pmce) >> 24) & 0x1fU)
 
 /*
Index: c/src/lib/libbsp/powerpc/gen5200/irq/irq.c
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/irq/irq.c	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/irq/irq.c	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -172,8 +172,4 @@
     prio_index_offset;
   uint32_t *reg;
-  volatile uint32_t per_pri_1,
-    main_pri_1,
-    crit_pri_main_mask,
-    per_mask;
 
   /* calculate the index offset of priority value bit field */
@@ -224,9 +220,9 @@
   mpc5200.per_mask &= ~(0x80000000 >> SIU_MaskBit [irqLine]);
 
-  main_pri_1 = mpc5200.main_pri_1;
-  crit_pri_main_mask = mpc5200.crit_pri_main_mask;
-  per_pri_1 = mpc5200.per_pri_1;
-  per_mask = mpc5200.per_mask;
-
+  /* FIXME: Why? */
+  mpc5200.main_pri_1;
+  mpc5200.crit_pri_main_mask;
+  mpc5200.per_pri_1;
+  mpc5200.per_mask;
 }
 
@@ -485,13 +481,13 @@
   #if (ALLOW_IRQ_NESTING == 1)
     uint32_t msr;
+    uint32_t mask = *maskreg;
   #endif
 
-  uint32_t mask = *maskreg;
-
   irq += offset;
 
-  *maskreg = mask | irqMaskTable [irq];
-
   #if (ALLOW_IRQ_NESTING == 1)
+    *maskreg = mask | irqMaskTable [irq];
+    /* Make sure that the write operation completed (cache inhibited area) */
+    *maskreg;
     msr = ppc_external_exceptions_enable();
   #endif
@@ -501,7 +497,6 @@
   #if (ALLOW_IRQ_NESTING == 1)
     ppc_external_exceptions_disable(msr);
+    *maskreg = mask;
   #endif
-
-  *maskreg = mask;
 }
 
@@ -527,149 +522,90 @@
 #endif
 
-  switch (excNum) {
-      /*
-       * Handle decrementer interrupt
-       */
-    case ASM_DEC_VECTOR:
-
-      /* Dispatch interrupt handlers */
-      bsp_interrupt_handler_dispatch( BSP_DECREMENTER);
-
-      break;
-
-    case ASM_EXT_VECTOR:
-    case ASM_60X_SYSMGMT_VECTOR:
-      /* get the content of main interrupt status register */
-      pmce = mpc5200.pmce;
-
-      /* critical interrupts may be routed to the core_int
-       * dependent on premature initialization, see bit 31 (CEbsH)
-       */
-      while ((CHK_CE_SHADOW( pmce) && CHK_CSE_STICKY( pmce))
-             || CHK_MSE_STICKY( pmce) || CHK_PSE_STICKY( pmce)) {
-
-        /* first: check for critical interrupt sources (hierarchical order)
-         * -> HI_int indicates peripheral sources
-         */
-        if (CHK_CE_SHADOW( pmce) && CHK_CSE_STICKY( pmce)) {
-          /* get source of critical interrupt */
-          irq = CSE_SOURCE( pmce);
-          switch (irq) {
-              /* irq0, slice timer 1 or ccs wakeup detected */
-            case 0:
-            case 1:
-            case 3:
-
-              /* add proper offset for critical interrupts in the siu
-               * handler array */
-              irq += BSP_CRIT_IRQ_LOWEST_OFFSET;
-
-              /* Dispatch interrupt handlers */
-              bsp_interrupt_handler_dispatch( irq);
-
-              break;
-
-              /* peripheral HI_int interrupt source detected */
-            case 2:
-              /* check for valid peripheral interrupt source */
-              if (CHK_PSE_STICKY( pmce)) {
-                /* get source of peripheral interrupt */
-                irq = PSE_SOURCE( pmce);
-
-                dispatch(irq, BSP_PER_IRQ_LOWEST_OFFSET, &mpc5200.per_mask);
-
-                /* force re-evaluation of peripheral interrupts */
-                CLR_PSE_STICKY( mpc5200.pmce);
-              } else {
-                /* this case may not occur: no valid peripheral
-                 * interrupt source */
-                printk( "No valid peripheral HI_int interrupt source\n");
-              }
-              break;
-            default:
-              /* error: unknown interrupt source */
-              printk( "Unknown HI_int interrupt source\n");
-              break;
+  /* get the content of main interrupt status register */
+  pmce = mpc5200.pmce;
+
+  /* critical interrupts are routed to the core_int, see premature
+   * initialization
+   */
+  while ((pmce & (PMCE_CSE_STICKY | PMCE_MSE_STICKY)) != 0) {
+    /* first: check for critical interrupt sources (hierarchical order)
+     * -> HI_int indicates peripheral sources
+     */
+    if ((pmce & PMCE_CSE_STICKY) != 0) {
+      /* get source of critical interrupt */
+      irq = PMCE_CSE_SOURCE(pmce);
+
+      switch (irq) {
+          /* peripheral HI_int interrupt source detected */
+        case 2:
+          /* check for valid peripheral interrupt source */
+          if ((pmce & PMCE_PSE_STICKY) != 0) {
+            /* get source of peripheral interrupt */
+            irq = PMCE_PSE_SOURCE(pmce);
+
+            dispatch(irq, BSP_PER_IRQ_LOWEST_OFFSET, &mpc5200.per_mask);
+          } else {
+            /* this case may not occur: no valid peripheral
+             * interrupt source */
+            printk( "No valid peripheral HI_int interrupt source\n");
           }
-          /* force re-evaluation of critical interrupts */
-          CLR_CSE_STICKY( mpc5200.pmce);
-        }
-
-        /* second: check for main interrupt sources (hierarchical order)
-         * -> LO_int indicates peripheral sources */
-        if (CHK_MSE_STICKY( pmce)) {
-          /* get source of main interrupt */
-          irq = MSE_SOURCE( pmce);
-
-          switch (irq) {
-
-              /* irq1-3, RTC, GPIO, TMR0-7 detected (attention: slice timer
-               * 2 is always routed to SMI) */
-            case 0:
-            case 1:
-            case 2:
-            case 3:
-            case 5:
-            case 6:
-            case 7:
-            case 8:
-            case 9:
-            case 10:
-            case 11:
-            case 12:
-            case 13:
-            case 14:
-            case 15:
-            case 16:
-              dispatch(irq, BSP_MAIN_IRQ_LOWEST_OFFSET, &mpc5200.crit_pri_main_mask);
-              break;
-
-              /* peripheral LO_int interrupt source detected */
-            case 4:
-              /* check for valid peripheral interrupt source */
-              if (CHK_PSE_STICKY( pmce)) {
-                /* get source of peripheral interrupt */
-                irq = PSE_SOURCE( pmce);
-
-                dispatch(irq, BSP_PER_IRQ_LOWEST_OFFSET, &mpc5200.per_mask);
-
-                /* force re-evaluation of peripheral interrupts */
-                CLR_PSE_STICKY( mpc5200.pmce);
-              } else {
-                /* this case may not occur: no valid peripheral
-                 * interrupt source */
-                printk( "No valid peripheral LO_int interrupt source\n");
-              }
-              break;
-
-              /* error: unknown interrupt source */
-            default:
-              printk( "Unknown peripheral LO_int interrupt source\n");
-              break;
+          break;
+
+          /* irq0, slice timer 1 or ccs wakeup detected */
+        case 0:
+        case 1:
+        case 3:
+
+          /* add proper offset for critical interrupts in the siu
+           * handler array */
+          irq += BSP_CRIT_IRQ_LOWEST_OFFSET;
+
+          /* Dispatch interrupt handlers */
+          bsp_interrupt_handler_dispatch( irq);
+
+          break;
+
+        default:
+          /* error: unknown interrupt source */
+          printk( "Unknown HI_int interrupt source\n");
+          break;
+      }
+    }
+
+    /* second: check for main interrupt sources (hierarchical order)
+     * -> LO_int indicates peripheral sources */
+    if ((pmce & PMCE_MSE_STICKY) != 0) {
+      /* get source of main interrupt */
+      irq = PMCE_MSE_SOURCE(pmce);
+
+      if (irq == 4) {
+          /* peripheral LO_int interrupt source detected */
+          /* check for valid peripheral interrupt source */
+          if ((pmce & PMCE_PSE_STICKY) != 0) {
+            /* get source of peripheral interrupt */
+            irq = PMCE_PSE_SOURCE(pmce);
+
+            dispatch(irq, BSP_PER_IRQ_LOWEST_OFFSET, &mpc5200.per_mask);
+          } else {
+            /* this case may not occur: no valid peripheral
+             * interrupt source */
+            printk( "No valid peripheral LO_int interrupt source\n");
           }
-          /* force re-evaluation of main interrupts */
-          CLR_MSE_STICKY( mpc5200.pmce);
-        }
-
-        if (CHK_PSE_STICKY( pmce)) {
-          /* get source of peripheral interrupt */
-          irq = PSE_SOURCE( pmce);
-
-          dispatch(irq, BSP_PER_IRQ_LOWEST_OFFSET, &mpc5200.per_mask);
-
-          /* force re-evaluation of peripheral interrupts */
-          CLR_PSE_STICKY( mpc5200.pmce);
-        }
-
-        /* get the content of main interrupt status register */
-        pmce = mpc5200.pmce;
+      } else if (irq <= 16) {
+          /* irq1-3, RTC, GPIO, TMR0-7 detected (attention: slice timer
+           * 2 is always routed to SMI) */
+          dispatch(irq, BSP_MAIN_IRQ_LOWEST_OFFSET, &mpc5200.crit_pri_main_mask);
+      } else {
+          /* error: unknown interrupt source */
+          printk( "Unknown peripheral LO_int interrupt source\n");
       }
-      break;
-
-    default:
-      printk( "Unknown processor exception\n");
-      break;
-
-  }                             /* end of switch( excNum) */
+    }
+
+    /* force re-evaluation of interrupts */
+    mpc5200.pmce = PMCE_CSE_STICKY | PMCE_MSE_STICKY | PMCE_PSE_STICKY;
+
+    /* get the content of main interrupt status register */
+    pmce = mpc5200.pmce;
+  }
 
 #if (BENCHMARK_IRQ_PROCESSING == 1)
@@ -772,7 +708,4 @@
     return RTEMS_IO_ERROR;
   }
-  if (ppc_exc_set_handler( ASM_DEC_VECTOR, C_dispatch_irq_handler)) {
-    return RTEMS_IO_ERROR;
-  }
   if (ppc_exc_set_handler( ASM_E300_SYSMGMT_VECTOR, C_dispatch_irq_handler)) {
     return RTEMS_IO_ERROR;
Index: c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -54,8 +54,14 @@
  *
  */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1
+#define __BSD_VISIBLE 1
+
 #include <rtems.h>
 #include <rtems/error.h>
 #include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_mii_ioctl.h>
 #include <stdio.h>
+#include <inttypes.h>
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -67,40 +73,20 @@
 #include <bsp.h>
 #include <bsp/irq.h>
-#include "../include/mpc5200.h"
+#include <bsp/mpc5200.h>
 #include <net/if_var.h>
 #include <errno.h>
 
-/* motorola-capi-specifics... */
-#include "../bestcomm/include/ppctypes.h"	/* uint32, et. al.			*/
-#include "../bestcomm/dma_image.h"
-#include "../bestcomm/bestcomm_glue.h"
-
-
-#define SDMA_BD_TFD	0x08000000	/*< Transmit Frame Done		*/
-#define SDMA_BD_INT	0x04000000	/*< Interrupt on frame done	*/
-#define SDMA_BD_RX_NUM	64 /* Number of receive buffer descriptors	*/
-#define SDMA_BD_TX_NUM	64 /* Number of transmit buffer descriptors	*/
-
-#define SET_BD_STATUS(bd, stat)	{		\
-	(bd)->Status &= 0x0000ffff;			\
-	(bd)->Status |= 0xffff0000 & stat;	\
-}
-#define SET_BD_LENGTH(bd, len) {		\
-	(bd)->Status &= 0xffff0000;			\
-	(bd)->Status |= 0x0000ffff & len;	\
-}
-#define GET_BD_STATUS(bd)		((bd)->Status & 0xffff0000)
-#define GET_BD_LENGTH(bd)		((bd)->Status & 0x0000ffff)
-#define GET_SDMA_PENDINGBIT(Bit)   \
-   (mpc5200.sdma.IntPend & (uint32)(1<<Bit))
-
-#include "../bestcomm/bestcomm_api.h"
-#include "../bestcomm/task_api/bestcomm_cntrl.h"
-#include "../bestcomm/task_api/tasksetup_bdtable.h"
-
-static TaskId rxTaskId;	/* SDMA RX task ID */
-static TaskId txTaskId;	/* SDMA TX task ID */
+#include <bsp/bestcomm/include/ppctypes.h>
+#include <bsp/bestcomm/dma_image.h>
+#include <bsp/bestcomm/bestcomm_glue.h>
+#include <bsp/bestcomm/bestcomm_api.h>
+#include <bsp/bestcomm/task_api/bestcomm_cntrl.h>
+#include <bsp/bestcomm/task_api/tasksetup_bdtable.h>
 
 /* #define ETH_DEBUG */
+
+#define FEC_BD_LAST TASK_BD_TFD
+#define FEC_BD_INT TASK_BD_INT
+#define FEC_BD_READY SDMA_BD_MASK_READY
 
 /*
@@ -114,23 +100,10 @@
  * since a single frame often uses four or more buffer descriptors.
  */
-#define RX_BUF_COUNT     SDMA_BD_RX_NUM
-#define TX_BUF_COUNT     SDMA_BD_TX_NUM
-#define TX_BD_PER_BUF    1
+#define RX_BUF_COUNT     64
+#define TX_BUF_COUNT     64
 
 #define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
 
-
-/*
- * RTEMS event used by interrupt handler to signal daemons.
- * This must *not* be the same event used by the TCP/IP task synchronization.
- */
-#define INTERRUPT_EVENT RTEMS_EVENT_1
-#define FATAL_INT_EVENT RTEMS_EVENT_3
-
-/*
- * RTEMS event used to start transmit daemon.
- * This must not be the same as INTERRUPT_EVENT.
- */
-#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+#define FEC_EVENT RTEMS_EVENT_0
 
 /* Task number assignment */
@@ -187,29 +160,22 @@
 #define MPC5200_FEC_MII_DATA_PA_SHIFT 0x17	/* MII PHY address bits */
 
-
-/* Receive & Transmit Buffer Descriptor definitions */
-typedef struct mpc5200_buffer_desc_
-  {
-  volatile uint16_t status;
-  volatile uint16_t length;
-  volatile void             *buffer;
-  } mpc5200_buffer_desc_t;
-
-
 #define FEC_INTR_MASK_USED \
 (FEC_INTR_LCEN  |FEC_INTR_CRLEN	|\
  FEC_INTR_XFUNEN|FEC_INTR_XFERREN|FEC_INTR_RFERREN)
 
+typedef enum {
+  FEC_STATE_RESTART_0,
+  FEC_STATE_RESTART_1,
+  FEC_STATE_NORMAL,
+} mpc5200_fec_state;
+
 /*
  * Device data
  */
-struct mpc5200_enet_struct {
-#if 0
-  struct ifnet            ac_if;
-#else
+typedef struct {
   struct arpcom           arpcom;
-#endif
   struct mbuf             **rxMbuf;
   struct mbuf             **txMbuf;
+  mpc5200_fec_state       state;
   int                     acceptBroadcast;
   int                     rxBdCount;
@@ -227,5 +193,5 @@
   unsigned long           rxNonOctet;
   unsigned long           rxBadCRC;
-  unsigned long           rxOverrun;
+  unsigned long           rxFIFOError;
   unsigned long           rxCollision;
 
@@ -234,74 +200,51 @@
   unsigned long           txLateCollision;
   unsigned long           txUnderrun;
+  unsigned long           txFIFOError;
   unsigned long           txMisaligned;
   unsigned long           rxNotFirst;
   unsigned long           txRetryLimit;
-  };
-
-static struct mpc5200_enet_struct enet_driver[NIFACES];
-
-extern int taskTable;
-static void mpc5200_fec_restart(struct mpc5200_enet_struct *sc);
-
-
-
-/*
- * Function:	mpc5200_fec_rx_bd_init
- *
- * Description:	Initialize the receive buffer descriptor ring.
- *
- * Returns:		void
- *
- * Notes:       Space for the buffers of rx BDs is allocated by the rx deamon
- *
- */
-static void mpc5200_fec_rx_bd_init(struct mpc5200_enet_struct *sc) {
-  int rxBdIndex;
-  struct mbuf *m;
-  struct ifnet *ifp = &sc->arpcom.ac_if;
-  BDIdx bdi;
-
-  /*
-   * Fill RX buffer descriptor ring.
-   */
-  for( rxBdIndex = 0; rxBdIndex < sc->rxBdCount; rxBdIndex++ ) {
-    MGETHDR (m, M_WAIT, MT_DATA);
-    MCLGET (m, M_WAIT);
-
-    m->m_pkthdr.rcvif = ifp;
-    sc->rxMbuf[rxBdIndex] = m;
-    bdi = TaskBDAssign( rxTaskId,
-			mtod(m, void *),
-			NULL,
-			ETHER_MAX_LEN,
-			0 );
-    if (bdi != rxBdIndex) {
-      rtems_panic("network rx buffer indices out of sync");
-    }
-  }
-}
-
-/*
- * Function:	mpc5200_fec_rx_bd_cleanup
- *
- * Description:	put all mbufs pending in rx BDs back to buffer pool
- *
- * Returns:		void
- *
- */
-static void mpc5200_fec_rx_bd_cleanup(struct mpc5200_enet_struct *sc) {
-  int rxBdIndex;
-  struct mbuf *m,*n;
-
-  /*
-   * Drain RX buffer descriptor ring.
-   */
-  for( rxBdIndex = 0; rxBdIndex < sc->rxBdCount; rxBdIndex++ ) {
-    n = sc->rxMbuf[rxBdIndex];
-    while (n != NULL) {
-      m = n;
-      MFREE(m,n);
-    }
-  }
+
+  struct rtems_mdio_info  mdio;
+  int                     phyAddr;
+  bool                    phyInitialized;
+} mpc5200_fec_context;
+
+static mpc5200_fec_context enet_driver[NIFACES];
+
+static void mpc5200_fec_send_event(rtems_id task)
+{
+  rtems_event_send(task, FEC_EVENT);
+}
+
+static void mpc5200_fec_wait_for_event(void)
+{
+  rtems_event_set out;
+  rtems_bsdnet_event_receive(
+    FEC_EVENT,
+    RTEMS_EVENT_ANY | RTEMS_WAIT,
+    RTEMS_NO_TIMEOUT,
+    &out
+  );
+}
+
+static void mpc5200_fec_stop_dma(void)
+{
+  TaskStop(FEC_RECV_TASK_NO);
+  TaskStop(FEC_XMIT_TASK_NO);
+}
+
+static void mpc5200_fec_request_restart(mpc5200_fec_context *self)
+{
+  self->state = FEC_STATE_RESTART_0;
+  mpc5200_fec_send_event(self->txDaemonTid);
+  mpc5200_fec_send_event(self->rxDaemonTid);
+}
+
+static void mpc5200_fec_start_dma_and_controller(void)
+{
+  TaskStart(FEC_RECV_TASK_NO, 1, FEC_RECV_TASK_NO, 1);
+  TaskStart(FEC_XMIT_TASK_NO, 1, FEC_XMIT_TASK_NO, 1);
+
+  mpc5200.ecntrl |= FEC_ECNTRL_OE | FEC_ECNTRL_EN;
 }
 
@@ -317,5 +260,5 @@
  *
  */
-static void mpc5200_eth_addr_filter_set(struct mpc5200_enet_struct *sc)  {
+static void mpc5200_eth_addr_filter_set(mpc5200_fec_context *self)  {
   unsigned char *mac;
   unsigned char currByte;				/* byte for which to compute the CRC */
@@ -327,5 +270,5 @@
   * Get the mac address of ethernet controller
   */
-  mac = (unsigned char *)(&sc->arpcom.ac_enaddr);
+  mac = (unsigned char *)(&self->arpcom.ac_enaddr);
 
  /*
@@ -400,123 +343,66 @@
    }
 
+static int mpc5200_eth_mii_transfer(
+  int phyAddr,
+  unsigned regAddr,
+  uint32_t data
+)
+{
+  int timeout = 0xffff;
+
+  mpc5200.ievent = FEC_INTR_MII;
+
+  mpc5200.mii_data = MPC5200_FEC_MII_DATA_ST
+    | MPC5200_FEC_MII_DATA_TA
+    | (phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT)
+    | (regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT)
+    | data;
+
+  while (timeout > 0 && (mpc5200.ievent & FEC_INTR_MII) == 0) {
+    --timeout;
+  }
+
+  return timeout > 0 ? 0 : -1;
+}
+
+/* FIXME: Make this static, this needs a fix in an application */
+int mpc5200_eth_mii_read(
+  int phyAddr,
+  void *arg,
+  unsigned regAddr,
+  uint32_t *retVal
+)
+{
+  int rv = mpc5200_eth_mii_transfer(
+    phyAddr,
+    regAddr,
+    MPC5200_FEC_MII_DATA_OP_RD
+  );
+
+  *retVal = mpc5200.mii_data & 0xffff;
+
+  return rv;
+}
+
+static int mpc5200_eth_mii_write(
+  int phyAddr,
+  void *arg,
+  unsigned regAddr,
+  uint32_t data
+)
+{
+  return mpc5200_eth_mii_transfer(
+    phyAddr,
+    regAddr,
+    MPC5200_FEC_MII_DATA_OP_WR | data
+  );
+}
+
 
 /*
- * Function:	mpc5200_eth_mii_read
- *
- * Description:	Read a media independent interface (MII) register on an
- *				18-wire ethernet tranceiver (PHY). Please see your PHY
- *				documentation for the register map.
- *
- * Returns:		32-bit register value
- *
- * Notes:
- *
+ * Reset a running ethernet driver including the hardware FIFOs and the FEC.
  */
-int mpc5200_eth_mii_read(struct mpc5200_enet_struct *sc, unsigned char phyAddr, unsigned char regAddr, unsigned short * retVal)
-  {
-  unsigned long reg;		/* convenient holder for the PHY register */
-  unsigned long phy;		/* convenient holder for the PHY */
-  int timeout = 0xffff;
-
- /*
-  * reading from any PHY's register is done by properly
-  * programming the FEC's MII data register.
-  */
-  reg = regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT;
-  phy = phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT;
-
-  mpc5200.mii_data = (MPC5200_FEC_MII_DATA_ST | MPC5200_FEC_MII_DATA_OP_RD | MPC5200_FEC_MII_DATA_TA | phy | reg);
-
- /*
-  * wait for the related interrupt
-  */
-  while ((timeout--) && (!(mpc5200.ievent & 0x00800000)));
-
-  if(timeout == 0)
-    {
-
-#ifdef ETH_DEBUG
-    printf ("Read MDIO failed..." "\r\n");
-#endif
-
-	return false;
-
-	}
-
- /*
-  * clear mii interrupt bit
-  */
-  mpc5200.ievent = 0x00800000;
-
- /*
-  * it's now safe to read the PHY's register
-  */
-  *retVal = (unsigned short)mpc5200.mii_data;
-
-  return true;
-
-  }
-
-/*
- * Function:	mpc5200_eth_mii_write
- *
- * Description:	Write a media independent interface (MII) register on an
- *				18-wire ethernet tranceiver (PHY). Please see your PHY
- *				documentation for the register map.
- *
- * Returns:		Success (boolean)
- *
- * Notes:
- *
- */
-static int mpc5200_eth_mii_write(struct mpc5200_enet_struct *sc, unsigned char phyAddr, unsigned char regAddr, unsigned short data)
-  {
-  unsigned long reg;					/* convenient holder for the PHY register */
-  unsigned long phy;					/* convenient holder for the PHY */
-  int timeout = 0xffff;
-
-  reg = regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT;
-  phy = phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT;
-
-  mpc5200.mii_data = (MPC5200_FEC_MII_DATA_ST | MPC5200_FEC_MII_DATA_OP_WR | MPC5200_FEC_MII_DATA_TA | phy | reg | data);
-
- /*
-  * wait for the MII interrupt
-  */
-  while ((timeout--) && (!(mpc5200.ievent & 0x00800000)));
-
-  if(timeout == 0)
-    {
-
-#ifdef ETH_DEBUG
-    printf ("Write MDIO failed..." "\r\n");
-#endif
-
-    return false;
-
-    }
-
- /*
-  * clear MII interrupt bit
-  */
-  mpc5200.ievent = 0x00800000;
-
-  return true;
-
-  }
-
-
-/*
- * Function:	mpc5200_fec_reset
- *
- * Description:	Reset a running ethernet driver including the hardware
- *				FIFOs and the FEC.
- *
- * Returns:		Success (boolean)
- *
- * Notes:
- *
- */
-static int mpc5200_fec_reset(struct mpc5200_enet_struct *sc) {
+static void mpc5200_fec_reset(mpc5200_fec_context *self)
+{
   volatile int delay;
   /*
@@ -544,6 +430,4 @@
    */
   for (delay = 0;delay < 16*4;delay++) {};
-
-  return true;
 }
 
@@ -560,5 +444,5 @@
  *
  */
-void mpc5200_fec_off(struct mpc5200_enet_struct *sc)
+void mpc5200_fec_off(mpc5200_fec_context *self)
   {
   int            counter = 0xffff;
@@ -566,12 +450,12 @@
 
 #if defined(ETH_DEBUG)
-  unsigned short phyStatus, i;
-  unsigned char  phyAddr = 0;
+  uint32_t phyStatus;
+  int i;
 
   for(i = 0; i < 9; i++)
     {
 
-    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
-    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+    mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+    printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
 
     }
@@ -580,6 +464,6 @@
     {
 
-    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
-    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+    mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+    printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
 
     }
@@ -602,9 +486,6 @@
   while((counter--) && (!(mpc5200.ievent & FEC_INTR_GRA)));
 
-  /*
-   * Disable the SmartDMA transmit and receive tasks.
-   */
-  TaskStop( rxTaskId );
-  TaskStop( txTaskId );
+  mpc5200_fec_stop_dma();
+
  /*
   * Disable transmit / receive interrupts
@@ -617,11 +498,5 @@
   */
   mpc5200.ecntrl &= ~(FEC_ECNTRL_OE | FEC_ECNTRL_EN);
-
-  /*
-   * cleanup all buffers
-   */
-  mpc5200_fec_rx_bd_cleanup(sc);
-
-  }
+}
 
 /*
@@ -630,5 +505,5 @@
 void mpc5200_fec_irq_handler(rtems_irq_hdl_param handle)
 {
-  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *) handle;
+  mpc5200_fec_context *self = (mpc5200_fec_context *) handle;
   volatile uint32_t ievent;
 
@@ -640,17 +515,17 @@
    */
   if (ievent & FEC_INTR_LATE_COL) {
-    sc->txLateCollision++;
+    self->txLateCollision++;
   }
   if (ievent & FEC_INTR_COL_RETRY) {
-    sc->txRetryLimit++;
+    self->txRetryLimit++;
   }
   if (ievent & FEC_INTR_XFIFO_UN) {
-    sc->txUnderrun++;
+    self->txUnderrun++;
   }
   if (ievent & FEC_INTR_XFIFO_ERR) {
-    sc->txUnderrun++;
+    self->txFIFOError++;
   }
   if (ievent & FEC_INTR_RFIFO_ERR) {
-    sc->rxOverrun++;
+    self->rxFIFOError++;
   }
   /*
@@ -659,402 +534,33 @@
   if (ievent & (FEC_INTR_XFIFO_ERR | FEC_INTR_RFIFO_ERR)) {
     mpc5200.imask &= ~(FEC_INTR_XFERREN | FEC_INTR_RFERREN);
-    rtems_event_send(enet_driver[0].rxDaemonTid, FATAL_INT_EVENT);
-  }
-}
-
-/*
- * MPC5200 SmartComm ethernet interrupt handler
- */
-void mpc5200_smartcomm_rx_irq_handler(rtems_irq_hdl_param unused)
-  {
- /* Frame received? */
-  if(GET_SDMA_PENDINGBIT(FEC_RECV_TASK_NO))
-    {
-
-      SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_RECV_TASK_NO);
-
-      bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);/*Disable receive ints*/
-
-      enet_driver[0].rxInterrupts++; 		/* Rx int has occurred */
-
-      rtems_event_send(enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
-
-    }
-  }
-
-/*
- * MPC5200 SmartComm ethernet interrupt handler
- */
-void mpc5200_smartcomm_tx_irq_handler(rtems_irq_hdl_param unused)
-  {
- /* Buffer transmitted or transmitter error? */
-  if(GET_SDMA_PENDINGBIT(FEC_XMIT_TASK_NO))
-    {
-
-      SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_XMIT_TASK_NO);
-
-      bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);/*Disable tx ints*/
-
-      enet_driver[0].txInterrupts++; /* Tx int has occurred */
-
-      rtems_event_send(enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
-
-    }
-
-  }
-
-
-
-
-
- /*
-  * Function:	    mpc5200_fec_retire_tbd
-  *
-  * Description:	Soak up buffer descriptors that have been sent.
-  *
-  * Returns:		void
-  *
-  * Notes:
-  *
-  */
-static void mpc5200_fec_retire_tbd(struct mpc5200_enet_struct *sc,
-				   bool force)
-{
-  struct mbuf *n;
-  TaskBD1_t   *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );;
-  /*
-   * Clear already transmitted BDs first. Will not work calling same
-   * from fecExceptionHandler(TFINT).
-   */
-
-  while ((sc->txBdActiveCount > 0) &&
-	 (force || (bdRing[sc->txBdTail].Status == 0x0))) {
-    if (sc->txMbuf[sc->txBdTail] != NULL) {
-      /*
-       * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
-       */
-      MFREE (sc->txMbuf[sc->txBdTail],n);
-      sc->txMbuf[sc->txBdTail] = NULL;
-    }
-    sc->txBdActiveCount--;
-    if(++sc->txBdTail >= sc->txBdCount) {
-      sc->txBdTail = 0;
-    }
-  }
-}
-
-#if 0
- /*
-  * Function:	     mpc5200_fec_tx_bd_requeue
-  *
-  * Description:	put buffers back to interface output queue
-  *
-  * Returns:		void
-  *
-  * Notes:
-  *
-  */
-static void mpc5200_fec_tx_bd_requeue(struct mpc5200_enet_struct *sc)
-{
-  /*
-   * Clear already transmitted BDs first. Will not work calling same
-   * from fecExceptionHandler(TFINT).
-   */
-
-  while (sc->txBdActiveCount > 0) {
-    if (sc->txMbuf[sc->txBdHead] != NULL) {
-      /*
-       * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
-       */
-      IF_PREPEND(&(sc->arpcom.ac_if.if_snd),sc->txMbuf[sc->txBdHead]);
-      sc->txMbuf[sc->txBdHead] = NULL;
-    }
-    sc->txBdActiveCount--;
-    if(--sc->txBdHead < 0) {
-      sc->txBdHead = sc->txBdCount-1;
-    }
-  }
-}
-#endif
-
-static void mpc5200_fec_sendpacket(struct ifnet *ifp,struct mbuf *m) {
-  struct mpc5200_enet_struct *sc = ifp->if_softc;
-  struct mbuf *l = NULL;
-  int nAdded;
-  uint32_t status;
-  rtems_event_set events;
-  TaskBD1_t *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );
-  TaskBD1_t *thisBd;
-  TaskBD1_t *firstBd = NULL;
-  void *data_ptr;
-  size_t data_len;
-
- /*
-  * Free up buffer descriptors
-  */
-  mpc5200_fec_retire_tbd(sc,false);
-
- /*
-  * Set up the transmit buffer descriptors.
-  * No need to pad out short packets since the
-  * hardware takes care of that automatically.
-  * No need to copy the packet to a contiguous buffer
-  * since the hardware is capable of scatter/gather DMA.
-  */
-  nAdded = 0;
-
-  for(;;) {
-
-   /*
-    * Wait for buffer descriptor to become available.
-    */
-    if((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
-
-      /*
-       * Clear old events
-       */
-      SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_XMIT_TASK_NO);
-
-      /*
-       * Wait for buffer descriptor to become available.
-       * Note that the buffer descriptors are checked
-       * *before* * entering the wait loop -- this catches
-       * the possibility that a buffer descriptor became
-       * available between the `if' above, and the clearing
-       * of the event register.
-       * This is to catch the case where the transmitter
-       * stops in the middle of a frame -- and only the
-       * last buffer descriptor in a frame can generate
-       * an interrupt.
-       */
-      mpc5200_fec_retire_tbd(sc,false);
-
-      while((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
-	bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
-	rtems_bsdnet_event_receive(INTERRUPT_EVENT,
-				   RTEMS_WAIT | RTEMS_EVENT_ANY,
-				   RTEMS_NO_TIMEOUT, &events);
-        mpc5200_fec_retire_tbd(sc,false);
-      }
-    }
-
-    if(m->m_len == 0) {
-      /*
-       * Just toss empty mbufs
-       */
-      struct mbuf *n;
-      MFREE(m, n);
-      m = n;
-      if(l != NULL) {
-        l->m_next = m;
-      }
-    }
-    else {
-      /*
-       * Flush the buffer for this descriptor
-       */
-      /*rtems_cache_flush_multiple_data_lines((const void *)mtod(m, void *), m->m_len);*/
-      /*
-       * Fill in the buffer descriptor,
-       * set "end of frame" bit in status,
-       * if last mbuf in chain
-       */
-      thisBd             = bdRing + sc->txBdHead;
-      /*
-       * FIXME: do not send interrupt after every frame
-       * doing this every quarter of BDs is much more efficent
-       */
-      status             = ((m->m_next == NULL)
-			    ? TASK_BD_TFD | TASK_BD_INT
-			    : 0);
-      /*
-       * Don't set the READY flag till the
-       * whole packet has been readied.
-       */
-      if (firstBd != NULL) {
-	status |= (uint32)SDMA_BD_MASK_READY;
-      }
-      else {
-	firstBd = thisBd;
-      }
-
-      data_ptr = mtod(m, void *);
-      data_len = (uint32)m->m_len;
-      sc->txMbuf[sc->txBdHead] = m;
-      /* go to next part in chain */
-      l = m;
-      m = m->m_next;
-
-      thisBd->DataPtr[0] = (uint32)data_ptr;
-      thisBd->Status     = (status
-			    |((uint32)SDMA_DRD_MASK_LENGTH & data_len));
-
-      nAdded++;
-      if(++(sc->txBdHead) == sc->txBdCount) {
-        sc->txBdHead = 0;
-      }
-    }
-    /*
-     * Set the transmit buffer status.
-     * Break out of the loop if this mbuf is the last in the frame.
-     */
-    if(m == NULL) {
-      if(nAdded) {
-        firstBd->Status     |= SDMA_BD_MASK_READY;
-	SDMA_TASK_ENABLE(SDMA_TCR, txTaskId);
-        sc->txBdActiveCount += nAdded;
-      }
-      break;
-    }
-  } /* end of for(;;) */
-}
-
-
-/*
- * Driver transmit daemon
- */
-void mpc5200_fec_txDaemon(void *arg)
-  {
-  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
-  struct ifnet *ifp = &sc->arpcom.ac_if;
-  struct mbuf *m;
-  rtems_event_set events;
-
-  for(;;) {
-   /*
-    * Wait for packet
-    */
-    bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
-    rtems_bsdnet_event_receive(START_TRANSMIT_EVENT|INTERRUPT_EVENT,
-			       RTEMS_EVENT_ANY | RTEMS_WAIT,
-			       RTEMS_NO_TIMEOUT,
-			       &events);
-
-    /*
-     * Send packets till queue is empty
-     */
-    for(;;)
-      {
-
-      /*
-       * Get the next mbuf chain to transmit.
-       */
-      IF_DEQUEUE(&ifp->if_snd, m);
-
-      if (!m)
-        break;
-
-      mpc5200_fec_sendpacket(ifp, m);
-
-      }
-
-    ifp->if_flags &= ~IFF_OACTIVE;
-
-    }
-
-  }
-
-
-/*
- * reader task
- */
-static void mpc5200_fec_rxDaemon(void *arg){
-  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
-  struct ifnet *ifp = &sc->arpcom.ac_if;
-  struct mbuf *m;
-  struct ether_header *eh;
-  int rxBdIndex;
-  uint32_t status;
-  size_t size;
-  rtems_event_set events;
-  uint16    len = 1;
-  TaskBD1_t *bd;
-  void	    *dptr;
-  TaskBD1_t   *bdRing = (TaskBD1_t *)TaskGetBDRing( rxTaskId );;
-
-  /*
-   * Input packet handling loop
-   */
-  rxBdIndex = 0;
-
-  for (;;) {
-    /*
-     * Clear old events
-     */
-    SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_RECV_TASK_NO);
-    /*
-     * Get the first BD pointer and its length.
-     */
-    bd     = bdRing + rxBdIndex;
-    status = bd->Status;
-    len    = (uint16)GET_BD_LENGTH( bd );
-
-    /*
-     * Loop through BDs until we find an empty one. This indicates that
-     * the SmartDMA is still using it.
-     */
-    while( !(status & SDMA_BD_MASK_READY) ) {
-
-      /*
-       * Remember the data pointer from this transfer.
-       */
-      dptr = (void *)bd->DataPtr[0];
-      m    = sc->rxMbuf[rxBdIndex];
-      m->m_len = m->m_pkthdr.len = (len
-				    - sizeof(uint32_t)
-				    - sizeof(struct ether_header));
-      eh = mtod(m, struct ether_header *);
-      m->m_data += sizeof(struct ether_header);
-      ether_input(ifp, eh, m);
-
-      /*
-       * Done w/ the BD. Clean it.
-       */
-      sc->rxMbuf[rxBdIndex] = NULL;
-
-      /*
-       * Add a new buffer to the ring.
-       */
-      MGETHDR (m, M_WAIT, MT_DATA);
-      MCLGET (m, M_WAIT);
-      m->m_pkthdr.rcvif = ifp;
-      size = ETHER_MAX_LEN;
-
-      sc->rxMbuf[rxBdIndex] = m;
-      bd->DataPtr[0] = (uint32)mtod(m, void *);
-      bd->Status = ( (  (uint32)SDMA_DRD_MASK_LENGTH & (uint32)size)
-		     | ((uint32)SDMA_BD_MASK_READY));
-
-      /*
-       * advance to next BD
-       */
-      if (++rxBdIndex >= sc->rxBdCount) {
-	rxBdIndex = 0;
-      }
-      /*
-       * Get next BD pointer and its length.
-       */
-      bd     = bdRing + rxBdIndex;
-      status = bd->Status;
-      len    = (uint16)GET_BD_LENGTH( bd );
-    }
-    /*
-     * Unmask RXF (Full frame received) event
-     */
-    bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
-
-    rtems_bsdnet_event_receive (INTERRUPT_EVENT | FATAL_INT_EVENT,
-				RTEMS_WAIT | RTEMS_EVENT_ANY,
-				RTEMS_NO_TIMEOUT, &events);
-    if (events & FATAL_INT_EVENT) {
-      /*
-       * fatal interrupt ocurred, so reinit fec and restart bestcomm tasks
-       */
-      mpc5200_fec_restart(sc);
-      rxBdIndex = 0;
-    }
-  }
-}
-
+    mpc5200_fec_request_restart(self);
+  }
+}
+
+void mpc5200_smartcomm_rx_irq_handler(void *arg)
+{
+  mpc5200_fec_context *self = arg;
+
+  ++self->rxInterrupts;
+  mpc5200_fec_send_event(self->rxDaemonTid);
+  SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_RECV_TASK_NO);
+  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
+}
+
+void mpc5200_smartcomm_tx_irq_handler(void *arg)
+{
+  mpc5200_fec_context *self = arg;
+
+  ++self->txInterrupts;
+  mpc5200_fec_send_event(self->txDaemonTid);
+  SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_XMIT_TASK_NO);
+  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
+}
+
+static void mpc5200_fec_init_mib(mpc5200_fec_context *self)
+{
+  memset(&mpc5200.RES [0], 0, 0x2e4);
+  mpc5200.mib_control = 0x40000000;
+}
 
 /*
@@ -1069,11 +575,15 @@
  *
  */
-static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
-  {
+static void mpc5200_fec_initialize_hardware(mpc5200_fec_context *self)
+{
+  /* We want at most 2.5MHz */
+  uint32_t div = 2 * 2500000;
+  uint32_t mii_speed = (IPB_CLOCK + div - 1) / div;
 
  /*
   * Reset mpc5200 FEC
   */
-  mpc5200_fec_reset(sc);
+  mpc5200_fec_reset(self);
+  mpc5200_fec_init_mib(self);
 
  /*
@@ -1103,8 +613,8 @@
 
  /*
-  * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(33Mhz)
+  * Set MII_SPEED = IPB clock / (2 * mii_speed))
   * and do not drop the Preamble.
   */
-  mpc5200.mii_speed = (7 << 1); /* ipb_clk = 33 MHz */
+  mpc5200.mii_speed = mii_speed << 1;
 
  /*
@@ -1136,5 +646,5 @@
   * and set physical address registers.
   */
-  mpc5200_eth_addr_filter_set(sc);
+  mpc5200_eth_addr_filter_set(self);
 
  /*
@@ -1148,5 +658,5 @@
   */
   mpc5200.xmit_fsm = FEC_FSM_CRC | FEC_FSM_ENFSM;
-  }
+}
 
  /*
@@ -1175,14 +685,16 @@
   *
   */
-static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
-  {
-  int            timeout;
-  unsigned short phyAddr = 0;
-
+static void mpc5200_fec_initialize_phy(mpc5200_fec_context *self)
+{
+  if (self->phyInitialized) {
+    return;
+  } else {
+    self->phyInitialized = true;
+  }
 
  /*
   * Reset PHY, then delay 300ns
   */
-  mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x8000);
+  mpc5200_eth_mii_write(self->phyAddr, self, 0x0, 0x8000);
 
   rtems_task_wake_after(2);
@@ -1193,16 +705,17 @@
   * Set the auto-negotiation advertisement register bits
   */
-  mpc5200_eth_mii_write(sc, phyAddr, 0x4, 0x01e1);
+  mpc5200_eth_mii_write(self->phyAddr, self, 0x4, 0x01e1);
 
  /*
   * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
   */
-  mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x1200);
+  mpc5200_eth_mii_write(self->phyAddr, self, 0x0, 0x1200);
 
  /*
   * Wait for AN completion
   */
-  timeout = 0x100;
 #if 0
+  int timeout = 0x100;
+  uint32_t phyStatus;
   do
     {
@@ -1219,9 +732,9 @@
       }
 
-    if(mpc5200_eth_mii_read(sc, phyAddr, 0x1, &phyStatus) != true)
+    if(mpc5200_eth_mii_read(self->phyAddr, self, 0x1, &phyStatus) != true)
       {
 
 #if defined(ETH_DEBUG)
-      printf ("MPC5200FEC PHY auto neg failed: 0x%04x." "\r\n", phyStatus);
+      printf ("MPC5200FEC PHY auto neg failed: 0x%04" PRIx32 ".\r\n", phyStatus);
 #endif
 
@@ -1243,5 +756,5 @@
 #if defined(ETH_DEBUG)
   int i;
-  unsigned short phyStatus;
+  uint32_t phyStatus;
  /*
   * Print PHY registers after initialization.
@@ -1250,6 +763,6 @@
     {
 
-	mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
-	printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+	mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+	printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
 
 	}
@@ -1258,6 +771,6 @@
     {
 
-    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
-    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+    mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+    printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
 
     }
@@ -1266,4 +779,20 @@
   }
 
+static void mpc5200_fec_restart(mpc5200_fec_context *self, rtems_id otherDaemon)
+{
+  if (self->state == FEC_STATE_RESTART_1) {
+    mpc5200_fec_initialize_hardware(self);
+    mpc5200_fec_initialize_phy(self);
+    mpc5200_fec_start_dma_and_controller();
+    self->state = FEC_STATE_NORMAL;
+  } else {
+    self->state = FEC_STATE_RESTART_1;
+  }
+
+  mpc5200_fec_send_event(otherDaemon);
+  while (self->state != FEC_STATE_NORMAL) {
+    mpc5200_fec_wait_for_event();
+  }
+}
 
 /*
@@ -1273,68 +802,390 @@
   {
 
-  struct mpc5200_enet_struct *sc = ifp->if_softc;
+  mpc5200_fec_context *self = ifp->if_softc;
 
   ifp->if_flags |= IFF_OACTIVE;
 
-  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
-
-  }
-
-
-/*
- * set up sdma tasks for ethernet
- */
-static void mpc5200_sdma_task_setup(struct mpc5200_enet_struct *sc) {
-  TaskSetupParamSet_t	rxParam;	/* RX task setup parameters	*/
-  TaskSetupParamSet_t	txParam;	/* TX task setup parameters	*/
-
-  /*
-   * Setup the SDMA RX task.
-   */
-  rxParam.NumBD        = sc->rxBdCount;
-  rxParam.Size.MaxBuf  = ETHER_MAX_LEN;
-  rxParam.Initiator    = 0;
-  rxParam.StartAddrSrc = (uint32)&(mpc5200.rfifo_data);
-  rxParam.IncrSrc      = 0;
-  rxParam.SzSrc	       = sizeof(uint32_t);
-  rxParam.StartAddrDst = (uint32)NULL;
-  rxParam.IncrDst      = sizeof(uint32_t);
-  rxParam.SzDst	       = sizeof(uint32_t);
-  rxTaskId	       = TaskSetup(TASK_FEC_RX,&rxParam );
-
-  /*
-   * Setup the TX task.
-   */
-  txParam.NumBD        = sc->txBdCount;
-  txParam.Size.MaxBuf  = ETHER_MAX_LEN;
-  txParam.Initiator    = 0;
-  txParam.StartAddrSrc = (uint32)NULL;
-  txParam.IncrSrc      = sizeof(uint32_t);
-  txParam.SzSrc        = sizeof(uint32_t);
-  txParam.StartAddrDst = (uint32)&(mpc5200.tfifo_data);
-  txParam.IncrDst      = 0;
-  txParam.SzDst        = sizeof(uint32_t);
-
-  txTaskId             = TaskSetup( TASK_FEC_TX, &txParam );
-
-}
-
-void mpc5200_fec_irq_on(const rtems_irq_connect_data* ptr)
-{
-  mpc5200.imask = FEC_INTR_MASK_USED;
-}
-
-
-int mpc5200_fec_irq_isOn(const rtems_irq_connect_data* ptr)
-{
-  return mpc5200.imask != 0;
-}
-
-
-void mpc5200_fec_irq_off(const rtems_irq_connect_data* ptr)
-{
-  mpc5200.imask = 0;
-}
-
+  mpc5200_fec_send_event(self->txDaemonTid);
+
+  }
+
+static TaskBD1_t *mpc5200_fec_init_tx_dma(int bdCount, struct mbuf **mbufs)
+{
+  TaskSetupParamSet_t param = {
+    .NumBD = bdCount,
+    .Size = {
+      .MaxBuf = ETHER_MAX_LEN
+    },
+    .Initiator = 0,
+    .StartAddrSrc = 0,
+    .IncrSrc = sizeof(uint32_t),
+    .SzSrc = sizeof(uint32_t),
+    .StartAddrDst = (uint32) &mpc5200.tfifo_data,
+    .IncrDst = 0,
+    .SzDst = sizeof(uint32_t)
+  };
+  int bdIndex = 0;
+
+  TaskSetup(FEC_XMIT_TASK_NO, &param);
+
+  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+    mbufs [bdIndex] = NULL;
+  }
+
+  return (TaskBD1_t *) TaskGetBDRing(FEC_XMIT_TASK_NO);
+}
+
+#if 0
+static void mpc5200_fec_requeue_and_discard_tx_frames(
+  int bdIndex,
+  int bdCount,
+  TaskBD1_t *bdRing,
+  struct mbuf **mbufs
+)
+{
+  int bdStop = bdIndex;
+  struct mbuf *previous = NULL;
+
+  do {
+    struct mbuf *current = NULL;
+    uint32 status = 0;
+    TaskBD1_t *bd = NULL;
+
+    if (bdIndex > 1) {
+      --bdIndex;
+    } else {
+      bdIndex = bdCount - 1;
+    }
+
+    current = mbufs [bdIndex];
+    mbufs [bdIndex] = NULL;
+
+    status = bdRing [bdIndex].Status;
+    bdRing [bdIndex].Status = 0;
+
+    if (current != NULL) {
+      if ((status & FEC_BD_LAST) != 0) {
+        if (previous != NULL) {
+          IF_PREPEND(&ifp->if_snd, previous);
+        }
+      }
+    } else {
+      break;
+    }
+
+    previous = current;
+  } while (bdIndex != bdStop);
+}
+#endif
+
+static void mpc5200_fec_discard_tx_frames(
+  int bdCount,
+  struct mbuf **mbufs
+)
+{
+  int bdIndex = 0;
+
+  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+    struct mbuf *m = mbufs [bdIndex];
+
+    if (m != NULL) {
+      mbufs [bdIndex] = NULL;
+      m_free(m);
+    }
+  }
+}
+
+static void mpc5200_fec_reset_tx_dma(
+  int bdCount,
+  TaskBD1_t *bdRing,
+  struct mbuf **mbufs,
+  struct mbuf *m
+)
+{
+  TaskStop(FEC_XMIT_TASK_NO);
+  TaskBDReset(FEC_XMIT_TASK_NO);
+  mpc5200_fec_discard_tx_frames(bdCount, mbufs);
+  while (m != NULL) {
+    m = m_free(m);
+  }
+}
+
+static struct mbuf *mpc5200_fec_next_fragment(
+  struct ifnet *ifp,
+  struct mbuf *m,
+  bool *isFirst
+)
+{
+  struct mbuf *n = NULL;
+
+  *isFirst = false;
+
+  while (true) {
+    if (m == NULL) {
+      IF_DEQUEUE(&ifp->if_snd, m);
+
+      if (m != NULL) {
+        *isFirst = true;
+      } else {
+        ifp->if_flags &= ~IFF_OACTIVE;
+
+        return NULL;
+      }
+    }
+
+    if (m->m_len > 0) {
+      break;
+    } else {
+      m = m_free(m);
+    }
+  }
+
+  n = m->m_next;
+  while (n != NULL && n->m_len <= 0) {
+    n = m_free(n);
+  }
+  m->m_next = n;
+
+  return m;
+}
+
+static bool mpc5200_fec_transmit(
+  struct ifnet *ifp,
+  int bdCount,
+  TaskBD1_t *bdRing,
+  struct mbuf **mbufs,
+  int *bdIndexPtr,
+  struct mbuf **mPtr,
+  TaskBD1_t **firstPtr
+)
+{
+  bool bdShortage = false;
+  int bdIndex = *bdIndexPtr;
+  struct mbuf *m = *mPtr;
+  TaskBD1_t *first = *firstPtr;
+
+  while (true) {
+    TaskBD1_t *bd = &bdRing [bdIndex];
+
+    if (bd->Status == 0) {
+      struct mbuf *done = mbufs [bdIndex];
+      bool isFirst = false;
+
+      if (done != NULL) {
+        m_free(done);
+        mbufs [bdIndex] = NULL;
+      }
+
+      m = mpc5200_fec_next_fragment(ifp, m, &isFirst);
+      if (m != NULL) {
+        uint32 status = (uint32) m->m_len;
+
+        mbufs [bdIndex] = m;
+
+        rtems_cache_flush_multiple_data_lines(mtod(m, void *), m->m_len);
+
+        if (isFirst) {
+          first = bd;
+        } else {
+          status |= FEC_BD_READY;
+        }
+
+        bd->DataPtr [0] = mtod(m, uint32);
+
+        if (m->m_next != NULL) {
+          bd->Status = status;
+        } else {
+          bd->Status = status | FEC_BD_INT | FEC_BD_LAST;
+          first->Status |= FEC_BD_READY;
+          SDMA_TASK_ENABLE(SDMA_TCR, FEC_XMIT_TASK_NO);
+        }
+
+        m = m->m_next;
+      } else {
+        break;
+      }
+    } else {
+      bdShortage = true;
+      break;
+    }
+
+    if (bdIndex < bdCount - 1) {
+      ++bdIndex;
+    } else {
+      bdIndex = 0;
+    }
+  }
+
+  *bdIndexPtr = bdIndex;
+  *mPtr = m;
+  *firstPtr = first;
+
+  return bdShortage;
+}
+
+static void mpc5200_fec_tx_daemon(void *arg)
+{
+  mpc5200_fec_context *self = arg;
+  struct ifnet *ifp = &self->arpcom.ac_if;
+  int bdIndex = 0;
+  int bdCount = self->txBdCount;
+  struct mbuf **mbufs = &self->txMbuf [0];
+  struct mbuf *m = NULL;
+  TaskBD1_t *bdRing = mpc5200_fec_init_tx_dma(bdCount, mbufs);
+  TaskBD1_t *first = NULL;
+  bool bdShortage = false;
+
+  while (true) {
+    if (bdShortage) {
+      bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
+    }
+    mpc5200_fec_wait_for_event();
+
+    if (self->state != FEC_STATE_NORMAL) {
+      mpc5200_fec_reset_tx_dma(bdCount, bdRing, mbufs, m);
+      mpc5200_fec_restart(self, self->rxDaemonTid);
+      bdIndex = 0;
+      m = NULL;
+      first = NULL;
+    }
+
+    bdShortage = mpc5200_fec_transmit(
+      ifp,
+      bdCount,
+      bdRing,
+      mbufs,
+      &bdIndex,
+      &m,
+      &first
+    );
+  }
+}
+
+static struct mbuf *mpc5200_fec_add_mbuf(struct ifnet *ifp, TaskBD1_t *bd)
+{
+  struct mbuf *m = NULL;
+
+  MGETHDR (m, M_WAIT, MT_DATA);
+  MCLGET (m, M_WAIT);
+  m->m_pkthdr.rcvif = ifp;
+
+  /* XXX: The dcbi operation does not work properly */
+  rtems_cache_flush_multiple_data_lines(mtod(m, void *), ETHER_MAX_LEN);
+
+  bd->DataPtr [0] = mtod(m, uint32);
+  bd->Status = ETHER_MAX_LEN | FEC_BD_READY;
+
+  return m;
+}
+
+static TaskBD1_t *mpc5200_fec_init_rx_dma(
+  struct ifnet *ifp,
+  int bdCount,
+  struct mbuf **mbufs
+)
+{
+  TaskSetupParamSet_t param = {
+    .NumBD = bdCount,
+    .Size = {
+      .MaxBuf = ETHER_MAX_LEN
+    },
+    .Initiator = 0,
+    .StartAddrSrc = (uint32) &mpc5200.rfifo_data,
+    .IncrSrc = 0,
+    .SzSrc = sizeof(uint32_t),
+    .StartAddrDst = 0,
+    .IncrDst = sizeof(uint32_t),
+    .SzDst = sizeof(uint32_t)
+  };
+  TaskBD1_t *bdRing = NULL;
+  int bdIndex = 0;
+
+  TaskSetup(FEC_RECV_TASK_NO, &param);
+  bdRing = (TaskBD1_t *) TaskGetBDRing(FEC_RECV_TASK_NO);
+
+  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+    mbufs [bdIndex] = mpc5200_fec_add_mbuf(ifp, &bdRing [bdIndex]);
+  }
+
+  return bdRing;
+}
+
+static void mpc5200_fec_reset_rx_dma(int bdCount, TaskBD1_t *bdRing)
+{
+  int bdIndex = 0;
+
+  TaskStop(FEC_RECV_TASK_NO);
+  TaskBDReset(FEC_RECV_TASK_NO);
+
+  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+    bdRing [bdIndex].Status = ETHER_MAX_LEN | FEC_BD_READY;
+  }
+}
+
+static int mpc5200_fec_ether_input(
+  struct ifnet *ifp,
+  int bdIndex,
+  int bdCount,
+  TaskBD1_t *bdRing,
+  struct mbuf **mbufs
+)
+{
+  while (true) {
+    TaskBD1_t *bd = &bdRing [bdIndex];
+    struct mbuf *m = mbufs [bdIndex];
+    uint32 status = 0;
+    int len = 0;
+    struct ether_header *eh = NULL;
+
+    SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_RECV_TASK_NO);
+    status = bd->Status;
+
+    if ((status & FEC_BD_READY) != 0) {
+      break;
+    }
+
+    eh = mtod(m, struct ether_header *);
+
+    len = (status & 0xffff) - ETHER_HDR_LEN - ETHER_CRC_LEN;
+    m->m_len = len;
+    m->m_pkthdr.len = len;
+    m->m_data = mtod(m, char *) + ETHER_HDR_LEN;
+
+    ether_input(ifp, eh, m);
+
+    mbufs [bdIndex] = mpc5200_fec_add_mbuf(ifp, bd);
+
+    if (bdIndex < bdCount - 1) {
+      ++bdIndex;
+    } else {
+      bdIndex = 0;
+    }
+  }
+
+  return bdIndex;
+}
+
+static void mpc5200_fec_rx_daemon(void *arg)
+{
+  mpc5200_fec_context *self = arg;
+  struct ifnet *ifp = &self->arpcom.ac_if;
+  int bdIndex = 0;
+  int bdCount = self->rxBdCount;
+  struct mbuf **mbufs = &self->rxMbuf [0];
+  TaskBD1_t *bdRing = mpc5200_fec_init_rx_dma(ifp, bdCount, mbufs);
+
+  while (true) {
+    bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
+    mpc5200_fec_wait_for_event();
+
+    bdIndex = mpc5200_fec_ether_input(ifp, bdIndex, bdCount, bdRing, mbufs);
+
+    if (self->state != FEC_STATE_NORMAL) {
+      mpc5200_fec_reset_rx_dma(bdCount, bdRing);
+      mpc5200_fec_restart(self, self->txDaemonTid);
+      bdIndex = 0;
+    }
+  }
+}
 
 /*
@@ -1343,32 +1194,29 @@
 static void mpc5200_fec_init(void *arg)
 {
-  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
-  struct ifnet *ifp = &sc->arpcom.ac_if;
-  rtems_irq_connect_data fec_irq_data = {
-    BSP_SIU_IRQ_ETH,
-    mpc5200_fec_irq_handler, /* rtems_irq_hdl           */
-    (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param)   */
-    mpc5200_fec_irq_on,	     /* (rtems_irq_enable)      */
-    mpc5200_fec_irq_off,     /* (rtems_irq_disable)     */
-    mpc5200_fec_irq_isOn     /* (rtems_irq_is_enabled)  */
-  };
-
-
-  if(sc->txDaemonTid == 0)
+  rtems_status_code sc = RTEMS_SUCCESSFUL;
+  mpc5200_fec_context *self = (mpc5200_fec_context *)arg;
+  struct ifnet *ifp = &self->arpcom.ac_if;
+
+  if(self->txDaemonTid == 0)
     {
+      size_t rxMbufTableSize = self->rxBdCount * sizeof(*self->rxMbuf);
+      size_t txMbufTableSize = self->txBdCount * sizeof(*self->txMbuf);
+
       /*
        * Allocate a set of mbuf pointers
        */
-      sc->rxMbuf =
-	malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
-      sc->txMbuf =
-	malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
-
-      if(!sc->rxMbuf || !sc->txMbuf)
+      self->rxMbuf = malloc(rxMbufTableSize, M_MBUF, M_NOWAIT);
+      self->txMbuf = malloc(txMbufTableSize, M_MBUF, M_NOWAIT);
+
+      if(!self->rxMbuf || !self->txMbuf)
 	rtems_panic ("No memory for mbuf pointers");
 
+      /*
+       * DMA setup
+       */
       bestcomm_glue_init();
-
-      mpc5200_sdma_task_setup(sc);
+      mpc5200.sdma.ipr [0] = 4;	/* always initiator	*/
+      mpc5200.sdma.ipr [3] = 6;	/* eth rx initiator	*/
+      mpc5200.sdma.ipr [4] = 5;	/* eth tx initiator	*/
 
       /*
@@ -1377,52 +1225,27 @@
       bestcomm_glue_irq_install(FEC_RECV_TASK_NO,
 				mpc5200_smartcomm_rx_irq_handler,
-				NULL);
+				self);
       bestcomm_glue_irq_install(FEC_XMIT_TASK_NO,
 				mpc5200_smartcomm_tx_irq_handler,
-				NULL);
-      if(!BSP_install_rtems_irq_handler (&fec_irq_data)) {
+				self);
+      sc = rtems_interrupt_handler_install(
+        BSP_SIU_IRQ_ETH,
+        "FEC",
+        RTEMS_INTERRUPT_UNIQUE,
+        mpc5200_fec_irq_handler,
+        self
+      );
+      if(sc != RTEMS_SUCCESSFUL) {
 	rtems_panic ("Can't attach MPC5x00 FEX interrupt handler\n");
       }
-
-      /* mpc5200_fec_tx_bd_init(sc); */
-      mpc5200_fec_rx_bd_init(sc);
-
-      /*
-       * reset and Set up mpc5200 FEC hardware
-       */
-      mpc5200_fec_initialize_hardware(sc);
-      /*
-       * Set up the phy
-       */
-      mpc5200_fec_initialize_phy(sc);
-      /*
-       * Set priority of different initiators
-       */
-      mpc5200.sdma.ipr [0] = 7;	/* always initiator	*/
-      mpc5200.sdma.ipr [3] = 6;	/* eth rx initiator	*/
-      mpc5200.sdma.ipr [4] = 5;	/* eth tx initiator	*/
 
       /*
        * Start driver tasks
        */
-      sc->txDaemonTid = rtems_bsdnet_newproc("FEtx", 4096, mpc5200_fec_txDaemon, sc);
-      sc->rxDaemonTid = rtems_bsdnet_newproc("FErx", 4096, mpc5200_fec_rxDaemon, sc);
-      /*
-       * Clear SmartDMA task interrupt pending bits.
-       */
-      TaskIntClear( rxTaskId );
-
-      /*
-       * Enable the SmartDMA receive task.
-       */
-      TaskStart( rxTaskId, 1, rxTaskId, 1 );
-      TaskStart( txTaskId, 1, txTaskId, 1 );
-      /*
-       * Enable FEC-Lite controller
-       */
-      mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
-
-
-    }
+      self->txDaemonTid = rtems_bsdnet_newproc("FEtx", 4096, mpc5200_fec_tx_daemon, self);
+      self->rxDaemonTid = rtems_bsdnet_newproc("FErx", 4096, mpc5200_fec_rx_daemon, self);
+    }
+
+  mpc5200_fec_request_restart(self);
 
   /*
@@ -1440,121 +1263,39 @@
 }
 
-
-static void enet_stats (struct mpc5200_enet_struct *sc)
-{
-  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
-  printf ("       Not First:%-8lu", sc->rxNotFirst);
-  printf ("        Not Last:%-8lu\n", sc->rxNotLast);
-  printf ("              Giant:%-8lu", sc->rxGiant);
-  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
-  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
-  printf ("         Overrun:%-8lu", sc->rxOverrun);
-  printf ("       Collision:%-8lu\n", sc->rxCollision);
-
-  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
-  printf ("        Deferred:%-8lu", sc->txDeferred);
-  printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
-  printf ("   Retransmit Limit:%-8lu", sc->txRetryLimit);
-  printf ("        Underrun:%-8lu", sc->txUnderrun);
-  printf ("      Misaligned:%-8lu\n", sc->txMisaligned);
-
-}
-
-/*
- * restart the driver, reinit the fec
- * this function is responsible to reinitialize the FEC in case a fatal
- * error has ocurred. This is needed, wen a RxFIFO Overrun or a TxFIFO underrun
- * has ocurred. In these cases, the FEC is automatically disabled, and
- * both FIFOs must be reset and the BestComm tasks must be restarted
- *
- * Note: the daemon tasks will continue to run
- * (in fact this function will be called in the context of the rx daemon task)
- */
-#define NEW_SDMA_SETUP
-
-static void mpc5200_fec_restart(struct mpc5200_enet_struct *sc)
-{
-  /*
-   * FIXME: bring Tx Daemon into idle state
-   */
-#ifdef NEW_SDMA_SETUP
-  /*
-   * cleanup remaining receive mbufs
-   */
-  mpc5200_fec_rx_bd_cleanup(sc);
-#endif
-  /*
-   * Stop SDMA tasks
-   */
-  TaskStop( rxTaskId);
-  TaskStop( txTaskId);
-  /*
-   * FIXME: wait, until Tx Daemon is in idle state
-   */
-
-  /*
-   * Disable transmit / receive interrupts
-   */
-  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
-  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
-#ifdef NEW_SDMA_SETUP
-  /*
-   * recycle pending tx buffers
-   * FIXME: try to extract pending Tx buffers
-   */
-#if 0
-  mpc5200_fec_tx_bd_requeue(sc);
-#else
-  mpc5200_fec_retire_tbd(sc,true);
-#endif
-#endif
-  /*
-   * re-initialize the FEC hardware
-   */
-  mpc5200_fec_initialize_hardware(sc);
-
-#ifdef NEW_SDMA_SETUP
-  /*
-   * completely reinitialize Bestcomm tasks
-   */
-  mpc5200_sdma_task_setup(sc);
-
-  /*
-   * reinit receive mbufs
-   */
-  mpc5200_fec_rx_bd_init(sc);
-#endif
-  /*
-   * Clear SmartDMA task interrupt pending bits.
-   */
-  TaskIntClear( rxTaskId );
-
-  /*
-   * Enable the SmartDMA receive/transmit task.
-   */
-  TaskStart( rxTaskId, 1, rxTaskId, 1 );
-  TaskStart( txTaskId, 1, txTaskId, 1 );
-  /*
-   * reenable rx/tx interrupts
-   */
-  bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
-  bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
-  /*
-   * (re-)init fec hardware
-   */
-  mpc5200_fec_initialize_hardware(sc);
-  /*
-   * reenable fec FIFO error interrupts
-   */
-  mpc5200.imask = FEC_INTR_MASK_USED;
-  /*
-   * Enable FEC-Lite controller
-   */
-  mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
+static void enet_stats (mpc5200_fec_context *self)
+{
+  if (self->phyAddr >= 0) {
+    struct ifnet *ifp = &self->arpcom.ac_if;
+    int media = IFM_MAKEWORD(0, 0, 0, self->phyAddr);
+    int rv = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t) &media);
+
+    if (rv == 0) {
+      rtems_ifmedia2str(media, NULL, 0);
+      printf ("\n");
+    } else {
+      printf ("PHY communication error\n");
+    }
+  }
+  printf ("       Rx Interrupts:%-8lu", self->rxInterrupts);
+  printf ("        Rx Not First:%-8lu", self->rxNotFirst);
+  printf ("         Rx Not Last:%-8lu\n", self->rxNotLast);
+  printf ("            Rx Giant:%-8lu", self->rxGiant);
+  printf ("        Rx Non-octet:%-8lu", self->rxNonOctet);
+  printf ("          Rx Bad CRC:%-8lu\n", self->rxBadCRC);
+  printf ("       Rx FIFO Error:%-8lu", self->rxFIFOError);
+  printf ("        Rx Collision:%-8lu", self->rxCollision);
+
+  printf ("       Tx Interrupts:%-8lu\n", self->txInterrupts);
+  printf ("         Tx Deferred:%-8lu", self->txDeferred);
+  printf ("   Tx Late Collision:%-8lu", self->txLateCollision);
+  printf (" Tx Retransmit Limit:%-8lu\n", self->txRetryLimit);
+  printf ("         Tx Underrun:%-8lu", self->txUnderrun);
+  printf ("       Tx FIFO Error:%-8lu", self->txFIFOError);
+  printf ("       Tx Misaligned:%-8lu\n", self->txMisaligned);
 }
 
 int32_t mpc5200_fec_setMultiFilter(struct ifnet *ifp)
 {
-  /*struct mpc5200_enet_struct *sc = ifp->if_softc; */
+  /*mpc5200_fec_context *self = ifp->if_softc; */
   /* XXX anything to do? */
   return 0;
@@ -1567,5 +1308,5 @@
 static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
   {
-  struct mpc5200_enet_struct *sc = ifp->if_softc;
+  mpc5200_fec_context *self = ifp->if_softc;
   int error = 0;
 
@@ -1584,6 +1325,6 @@
       struct ifreq* ifr = (struct ifreq*) data;
       error = (command == SIOCADDMULTI)
-                  ? ether_addmulti(ifr, &sc->arpcom)
-                  : ether_delmulti(ifr, &sc->arpcom);
+                  ? ether_addmulti(ifr, &self->arpcom)
+                  : ether_delmulti(ifr, &self->arpcom);
 
        if (error == ENETRESET) {
@@ -1603,5 +1344,5 @@
         case IFF_RUNNING:
 
-          mpc5200_fec_off(sc);
+          mpc5200_fec_off(self);
 
           break;
@@ -1609,5 +1350,5 @@
         case IFF_UP:
 
-          mpc5200_fec_init(sc);
+          mpc5200_fec_init(self);
 
           break;
@@ -1615,6 +1356,6 @@
         case IFF_UP | IFF_RUNNING:
 
-          mpc5200_fec_off(sc);
-          mpc5200_fec_init(sc);
+          mpc5200_fec_off(self);
+          mpc5200_fec_init(self);
 
           break;
@@ -1627,7 +1368,12 @@
       break;
 
+    case SIOCGIFMEDIA:
+    case SIOCSIFMEDIA:
+      error = rtems_mii_ioctl(&self->mdio, self, command, (int *) data);
+      break;
+
     case SIO_RTEMS_SHOW_STATS:
 
-      enet_stats(sc);
+      enet_stats(self);
 
       break;
@@ -1654,5 +1400,5 @@
 int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
   {
-  struct mpc5200_enet_struct *sc;
+  mpc5200_fec_context *self;
   struct ifnet *ifp;
   int    mtu;
@@ -1677,6 +1423,6 @@
     }
 
-  sc = &enet_driver[unitNumber - 1];
-  ifp = &sc->arpcom.ac_if;
+  self = &enet_driver[unitNumber - 1];
+  ifp = &self->arpcom.ac_if;
 
   if(ifp->if_softc != NULL)
@@ -1687,4 +1433,7 @@
 
     }
+
+  self->mdio.mdio_r = mpc5200_eth_mii_read;
+  self->mdio.mdio_w = mpc5200_eth_mii_write;
 
   /*
@@ -1727,5 +1476,5 @@
 
     /* Anything in the first three bytes indicates a non-zero entry, copy value */
-  	memcpy((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
+  	memcpy((void *)self->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
 
     }
@@ -1735,5 +1484,5 @@
 
       /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
-      memcpy((void *)sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+      memcpy((void *)self->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
       }
     else
@@ -1750,5 +1499,5 @@
     {
 
-    memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+    memcpy(self->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
 
     }
@@ -1765,9 +1514,9 @@
 #endif /* NVRAM_CONFIGURE != 1 */
 #ifdef HAS_UBOOT
-  if ((sc->arpcom.ac_enaddr[0] == 0) &&
-      (sc->arpcom.ac_enaddr[1] == 0) &&
-      (sc->arpcom.ac_enaddr[2] == 0)) {
+  if ((self->arpcom.ac_enaddr[0] == 0) &&
+      (self->arpcom.ac_enaddr[1] == 0) &&
+      (self->arpcom.ac_enaddr[2] == 0)) {
       memcpy(
-        (void *)sc->arpcom.ac_enaddr,
+        (void *)self->arpcom.ac_enaddr,
         bsp_uboot_board_info.bi_enetaddr,
         ETHER_ADDR_LEN
@@ -1781,19 +1530,19 @@
 
   if(config->rbuf_count)
-    sc->rxBdCount = config->rbuf_count;
+    self->rxBdCount = config->rbuf_count;
   else
-    sc->rxBdCount = RX_BUF_COUNT;
+    self->rxBdCount = RX_BUF_COUNT;
 
   if(config->xbuf_count)
-    sc->txBdCount = config->xbuf_count;
+    self->txBdCount = config->xbuf_count;
   else
-    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
-
-  sc->acceptBroadcast = !config->ignore_broadcast;
+    self->txBdCount = TX_BUF_COUNT;
+
+  self->acceptBroadcast = !config->ignore_broadcast;
 
  /*
   * Set up network interface values
   */
-  ifp->if_softc   = sc;
+  ifp->if_softc   = self;
   ifp->if_unit    = unitNumber;
   ifp->if_name    = unitName;
Index: c/src/lib/libbsp/powerpc/gen5200/start/start.S
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/start/start.S	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/start/start.S	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -157,4 +157,66 @@
 .extern boot_card
 
+.section ".vectors", "ax"
+	bl	start
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec2:	b	__vec2
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec3:	b	__vec3
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec4:	b	__vec4
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec5:	b	__vec5
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec6:	b	__vec6
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec7:	b	__vec7
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec8:	b	__vec8
+	.rep 63
+	.long 0x04000400
+	.endr
+__vec9:	b	__vec9
+	.rep 63
+	.long 0x04000400
+	.endr
+__veca:	b	__veca
+	.rep 63
+	.long 0x04000400
+	.endr
+__vecb:	b	__vecb
+	.rep 63
+	.long 0x04000400
+	.endr
+__vecc:	b	__vecc
+	.rep 63
+	.long 0x04000400
+	.endr
+__vecd:	b	__vecd
+	.rep 63
+	.long 0x04000400
+	.endr
+__vece:	b	__vece
+	.rep 63
+	.long 0x04000400
+	.endr
+__vecf:	b	__vecf
+	.rep 63+1024
+	.long 0x04000400
+	.endr
+
 .section ".entry"
 PUBLIC_VAR (start)
@@ -244,5 +306,5 @@
 	stw	r30, CS0STR(r31) 		/* Set CS0STR */
 
-	LWI	r30, bsp_rom_end
+	LWI	r30, bsp_rom_end - 1
 
 	rlwinm	r30, r30,17,15,31
@@ -280,16 +342,5 @@
 	bl	SDRAM_init			/* Initialize SDRAM controller */
 
-/* init arbiter and stuff... */
-	LWI	r30, 0x8000a06e
-	stw	r30, ARBCFG(r31) 		/* Set ARBCFG */
-
-	LWI	r30, 0x000000ff
-	stw	r30, ARBMPREN(r31) 		/* Set ARBMPREN */
-
-	LWI	r30, 0x00001234
-	stw	r30, ARBMPRIO(r31) 		/* Set ARBPRIO */
-
-	LWI	r30, 0x0000001e
-	stw	r30, ARBSNOOP(r31) 		/* Set ARBSNOOP */
+	bl	XLB_init
 /* copy .text section from ROM to RAM location (unique for ROM startup) */
 	LA	r30, bsp_section_text_start	/* get start address of text section in RAM */
@@ -396,4 +447,6 @@
         bl      clr_mem				/* Clear onchip SRAM */
 
+#else /* defined(NEED_LOW_LEVEL_INIT) */
+	bl	XLB_init
 #endif /* defined(NEED_LOW_LEVEL_INIT) */
 /* clear .bss section (unique for ROM startup) */
@@ -844,4 +897,17 @@
         blr					/* return */
 
-
-
+XLB_init:
+/* init arbiter and stuff... */
+	LWI	r30, 0x8000a06e
+	stw	r30, ARBCFG(r31) 		/* Set ARBCFG */
+
+	LWI	r30, 0x000000ff
+	stw	r30, ARBMPREN(r31) 		/* Set ARBMPREN */
+
+	LWI	r30, 0x00001234
+	stw	r30, ARBMPRIO(r31) 		/* Set ARBPRIO */
+
+	LWI	r30, 0x0000001e
+	stw	r30, ARBSNOOP(r31) 		/* Set ARBSNOOP */
+
+	blr
Index: c/src/lib/libbsp/powerpc/gen5200/startup/bspstart.c
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/startup/bspstart.c	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/startup/bspstart.c	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -104,4 +104,5 @@
 #include <bsp/irq.h>
 #include <bsp/irq-generic.h>
+#include <bsp/mpc5200.h>
 
 /*
@@ -144,4 +145,16 @@
 
   cpu_init();
+
+  if(get_ppc_cpu_revision() >= 0x2014) {
+    /* Special settings for MPC5200B (B variant) */
+    uint32_t xlb_cfg = mpc5200.config;
+
+    /* XXX: The Freescale documentation for BSDIS seems to be wrong */
+    xlb_cfg |= XLB_CFG_BSDIS;
+
+    xlb_cfg &= ~XLB_CFG_PLDIS;
+
+    mpc5200.config = xlb_cfg;
+  }
 
   bsp_clicks_per_usec    = (XLB_CLOCK/4000000);
@@ -167,4 +180,5 @@
     BSP_panic("cannot initialize exceptions");
   }
+  ppc_exc_set_handler(ASM_ALIGN_VECTOR, ppc_exc_alignment_handler);
 
   /* Initalize interrupt support */
Index: c/src/lib/libbsp/powerpc/gen5200/startup/cpuinit.c
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/startup/cpuinit.c	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/startup/cpuinit.c	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -170,4 +170,12 @@
 
   /*
+   * Accesses (also speculative accesses) outside of the RAM area are a
+   * disaster especially in combination with the BestComm.  For safety reasons
+   * we make the available RAM a little bit smaller to have an unused area at
+   * the end.
+   */
+  bsp_uboot_board_info.bi_memsize -= 4 * 1024;
+
+  /*
    * Program BAT0 for RAM
    */
Index: c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.brs5l
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.brs5l	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.brs5l	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -6,5 +6,6 @@
 
 MEMORY {
-	RAM : ORIGIN = 0x0, LENGTH = 128M
+	/* For the 4k adjustment see cpuinit.c */
+	RAM : ORIGIN = 0x0, LENGTH = 128M - 4k
 	ROM : ORIGIN = 0xffe00000, LENGTH = 2M
 	DPRAM : ORIGIN = 0xff000000, LENGTH = 1k
Index: c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.dp2
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.dp2	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.dp2	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -6,8 +6,9 @@
 
 MEMORY {
-	RAM : ORIGIN = 0x0, LENGTH = 64M
+	/* For the 4k adjustment see cpuinit.c */
+	RAM : ORIGIN = 0x0, LENGTH = 64M - 4k
 	ROM : ORIGIN = 0xffe00000, LENGTH = 2M
-	DPRAM : ORIGIN = 0xff000000, LENGTH = 1k
 	REGS : ORIGIN = 0xf0000000, LENGTH = 64k
+	DPRAM : ORIGIN = 0x0, LENGTH = 0
 	NIRVANA : ORIGIN = 0x0, LENGTH = 0
 }
Index: c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.icecube
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.icecube	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.icecube	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -6,9 +6,10 @@
 
 MEMORY {
-	RAM : ORIGIN = 0x0, LENGTH = 128M
+	/* For the 4k adjustment see cpuinit.c */
+	RAM : ORIGIN = 0x0, LENGTH = 128M - 4k
 	ROM : ORIGIN = 0xffe00000, LENGTH = 2M
 	REGS : ORIGIN = 0xf0000000, LENGTH = 64k
+	DPRAM : ORIGIN = 0x0, LENGTH = 0
 	NIRVANA : ORIGIN = 0x0, LENGTH = 0
-	DPRAM : ORIGIN = 0x0, LENGTH = 0
 }
 
Index: c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.pm520_cr825
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.pm520_cr825	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.pm520_cr825	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -6,8 +6,9 @@
 
 MEMORY {
-	RAM : ORIGIN = 0x0, LENGTH = 64M
+	/* For the 4k adjustment see cpuinit.c */
+	RAM : ORIGIN = 0x0, LENGTH = 64M - 4k
 	ROM : ORIGIN = 0xffe00000, LENGTH = 2M
+	REGS : ORIGIN = 0xf0000000, LENGTH = 64k
 	DPRAM : ORIGIN = 0xff000000, LENGTH = 1k
-	REGS : ORIGIN = 0xf0000000, LENGTH = 64k
 	NIRVANA : ORIGIN = 0x0, LENGTH = 0
 }
Index: c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.pm520_ze30
===================================================================
--- c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.pm520_ze30	(revision 1dd95ccc1e99f0a5ff73a235614e37535be3edd7)
+++ c/src/lib/libbsp/powerpc/gen5200/startup/linkcmds.pm520_ze30	(revision 25ed11d08e98b9893a076c57f694c14892155c01)
@@ -6,8 +6,9 @@
 
 MEMORY {
-	RAM : ORIGIN = 0x0, LENGTH = 64M
+	/* For the 4k adjustment see cpuinit.c */
+	RAM : ORIGIN = 0x0, LENGTH = 64M - 4k
 	ROM : ORIGIN = 0xffe00000, LENGTH = 2M
+	REGS : ORIGIN = 0xf0000000, LENGTH = 64k
 	DPRAM : ORIGIN = 0xff000000, LENGTH = 1k
-	REGS : ORIGIN = 0xf0000000, LENGTH = 64k
 	NIRVANA : ORIGIN = 0x0, LENGTH = 0
 }
