Index: c/src/lib/libbsp/powerpc/gen405/opbintctrl/opbintctrl.c =================================================================== --- c/src/lib/libbsp/powerpc/gen405/opbintctrl/opbintctrl.c (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/opbintctrl/opbintctrl.c (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,178 @@ +/* opbintctrl.c + * + * This file contains definitions and declarations for the + * Xilinx Off Processor Bus (OPB) Interrupt Controller + * + * Author: Keith Robertson + * COPYRIGHT (c) 2005 Linn Products Ltd, Scotland. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include "opbintctrl.h" +#include +#include +#include + +/* + * ISR vector table to dispatch external interrupts + */ +rtems_isr_entry opb_intc_vector_table[OPB_INTC_IRQ_MAX]; + +/* + * Acknowledge/Clear a specific vector number + */ +RTEMS_INLINE_ROUTINE void +awk_vector(unsigned32 vector) +{ + *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_IAR) = 1 << vector; +} + +/* + * Enable a specific vector number + * vector is a number counting from 0 + */ +RTEMS_INLINE_ROUTINE void +enable_vector(unsigned32 vector) +{ + *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_IER) = 1 << vector; +} + +/* + * Disable a specific vector number + * vector is a number counting from 0 + */ +RTEMS_INLINE_ROUTINE void +disable_vector(unsigned32 vector) +{ + *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_CIE) = 1 << vector; +} + +/* + * Set IER state. Used to (dis)enable a mask of vectors. + * If you only have to do one, use enable/disable_vector. + */ +RTEMS_INLINE_ROUTINE void +set_ier(unsigned32 mask) +{ + *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_IER) = mask; +} + +/* + * Set ISR state. Used to awknowledge a mask of vectors. + * If you only have to do one, use awk_vector. + */ +RTEMS_INLINE_ROUTINE void +set_isr(unsigned32 mask) +{ + *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_ISR) = mask; +} + +/* + * Get Highest Priority Pending Vector (aka read IVR) + */ +RTEMS_INLINE_ROUTINE unsigned32 +get_vector() +{ + volatile unsigned32 vector = *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_IVR); + return vector; +} + +/* + * Enable Hardware Interrupt Enable + * This turns off support for software settable interrupts. + */ +RTEMS_INLINE_ROUTINE void +enable_hie() +{ + volatile unsigned32 value = *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_MER); + value |= OPB_INTC_MER_HIE; + *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_MER) = value; +} + +/* + * Master IRQ (Dis)Enable + */ +RTEMS_INLINE_ROUTINE void +set_master_enable(unsigned32 value) +{ + volatile unsigned32 v = *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_MER); + v |= value ? OPB_INTC_MER_ME : 0; + *(unsigned32*)(OPB_INTC_BASE+OPB_INTC_MER) = v; +} + +/* + * ISR Handler: this is called from the primary exception dispatcher + */ + +void +opb_intc_isr(rtems_vector_number vector,CPU_Interrupt_frame *cpu_frame) +{ + unsigned32 opb_vector; + rtems_isr_entry handler; + + opb_vector = get_vector(); + handler = opb_intc_vector_table[opb_vector]; + if(handler) { + (handler)(PPC_IRQ_EXTERNAL); + } else { + /*printk("Spurious interrupt vector: %x\n", opb_vector);*/ + } + awk_vector(opb_vector); +} + +/* + * install a user vector for one of the external interrupt sources + * vector is the number of the vector counting from 0. + */ +rtems_status_code +opb_intc_set_vector(rtems_isr_entry new_handler, unsigned32 vector, + rtems_isr_entry *old_handler) +{ + /* + * We put the actual user ISR address in 'opb_intc_vector_table'. This will + * be used by the _opb_intc_isr so the user gets control. + */ + + if(vector < OPB_INTC_IRQ_MAX) { + *old_handler = opb_intc_vector_table[vector]; + if(new_handler) { + opb_intc_vector_table[vector] = new_handler; + enable_vector(vector); + } else { + disable_vector(vector); + opb_intc_vector_table[vector] = 0; + } + return RTEMS_SUCCESSFUL; + } + return RTEMS_INVALID_NUMBER; +} + +/* + * activate the interrupt controller + */ +rtems_status_code +opb_intc_init(void) +{ + proc_ptr dummy; + /* install the external interrupt handler */ + _CPU_ISR_install_vector(PPC_IRQ_EXTERNAL, opb_intc_isr, &dummy); + + /* Clear any currently set interrupts */ + set_isr(0x0); + /* Disable all vectors */ + set_ier(0x0); + + /* Turn on normal hardware operation of interrupt controller */ + enable_hie(); + /* Enable master interrupt switch for the interrupt controller */ + set_master_enable(1); + + /* install exit handler to close opb_intc when program atexit called */ + /* atexit(opb_intc_exit);*/ + + return RTEMS_SUCCESSFUL; +} + Index: c/src/lib/libbsp/powerpc/gen405/opbintctrl/opbintctrl.h =================================================================== --- c/src/lib/libbsp/powerpc/gen405/opbintctrl/opbintctrl.h (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/opbintctrl/opbintctrl.h (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,66 @@ +/* opbintctrl.h + * + * This file contains definitions and declarations for the + * Xilinx Off Processor Bus (OPB) Interrupt Controller + * + * Author: Keith Robertson + * COPYRIGHT (c) 2005 by Linn Products Ltd, Scotland + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef _INCLUDE_OPBINTCTRL_H +#define _INCLUDE_OPBINTCTRL_H + +#include +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* Maximum number of IRQs. Defined in vhdl model */ +#define OPB_INTC_IRQ_MAX 5 + +/* Base Register address and register offsets */ +#define OPB_INTC_BASE 0x41200000 +/* Interrupt Status Register */ +#define OPB_INTC_ISR 0x0 +/* Interrupt Pending Register (ISR && IER) */ +#define OPB_INTC_IPR 0x4 +/* Interrupt Enable Register */ +#define OPB_INTC_IER 0x8 +/* Interrupt Acknowledge Register */ +#define OPB_INTC_IAR 0xC +/* Set Interrupt Enable (same as read/mask/write to IER) */ +#define OPB_INTC_SIE 0x10 +/* Clear Interrupt Enable (same as read/mask/write to IER) */ +#define OPB_INTC_CIE 0x14 +/* Interrupt Vector Address (highest priority vector number from IPR) */ +#define OPB_INTC_IVR 0x18 +/* Master Enable Register */ +#define OPB_INTC_MER 0x1C + +/* Master Enable Register: Hardware Interrupt Enable */ +#define OPB_INTC_MER_HIE 0x2 + +/* Master Enable Register: Master IRQ Enable */ +#define OPB_INTC_MER_ME 0x1 + +/* + * install a user vector for one of the external interrupt sources + */ +rtems_status_code opb_intc_set_vector(rtems_isr_entry new_handler, + unsigned32 vector, rtems_isr_entry *old_handler); +/* + * activate the interrupt controller + */ +rtems_status_code opb_intc_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _INCLUDE_OPBINTCTRL_H */ Index: c/src/lib/libbsp/powerpc/gen405/opbintctrl/Makefile.am =================================================================== --- c/src/lib/libbsp/powerpc/gen405/opbintctrl/Makefile.am (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/opbintctrl/Makefile.am (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,38 @@ +## +## Makefile.am,v 1.8 2002/12/19 05:03:12 ralf Exp +## + + +PGM = $(ARCH)/opbintctrl.rel + +C_FILES = opbintctrl.c + +include_HEADERS = opbintctrl.h + +opb_intc_rel_OBJECTS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) + +include $(top_srcdir)/../../../../../../automake/compile.am +include $(top_srcdir)/../../../../../../automake/lib.am + +# +# (OPTIONAL) Add local stuff here using += +# + +$(PGM): $(opb_intc_rel_OBJECTS) + $(make-rel) + +TMPINSTALL_FILES += $(PROJECT_INCLUDE) \ + $(include_HEADERS:%=$(PROJECT_INCLUDE)/%) + +$(PROJECT_INCLUDE): + $(mkinstalldirs) $@ +$(PROJECT_INCLUDE)/%.h: %.h + $(INSTALL_DATA) $< $@ + +all-local: $(ARCH) $(opb_intc_rel_OBJECTS) $(PGM) $(TMPINSTALL_FILES) + +.PRECIOUS: $(PGM) + +EXTRA_DIST = opbintctrl.c opbintctrl.h + +include $(top_srcdir)/../../../../../../automake/local.am Index: c/src/lib/libbsp/powerpc/gen405/bsp_specs =================================================================== --- c/src/lib/libbsp/powerpc/gen405/bsp_specs (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/lib/libbsp/powerpc/gen405/bsp_specs (.../volkano/rtems/rtems-src) (revision 1691) @@ -1,23 +1,20 @@ -%rename cpp old_cpp %rename lib old_lib %rename endfile old_endfile %rename startfile old_startfile %rename link old_link -*cpp: -%(old_cpp) %{qrtems: -D__embedded__} -Asystem(embedded) *lib: -%{!qrtems: %(old_lib)} %{!nostdlib: %{qrtems: ecrti%O%s --start-group \ +%{!qrtems: %(old_lib)} %{!nostdlib: %{qrtems: --start-group \ %{!qrtems_debug: -lrtemsbsp -lrtemscpu} %{qrtems_debug: -lrtemsbsp_g -lrtemscpu_g} \ --lc -lgcc --end-group \ +-lc -lgcc --end-group \ %{!qnolinkcmds: -T linkcmds%s}}} *startfile: -%{!qrtems: %(old_startfile)} %{!nostdlib: %{qrtems: \ -%{!qrtems_debug: } \ -%{qrtems_debug: }}} +%{!qrtems: %(old_startfile)} %{!nostdlib: %{qrtems: ecrti%O%s rtems_crti%O%s crtbegin.o%s }} *link: %{!qrtems: %(old_link)} %{qrtems: -dc -dp -u __vectors -u download_entry -N } +*endfile: +%{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s ecrtn.o%s} Index: c/src/lib/libbsp/powerpc/gen405/console/consolelite.c =================================================================== --- c/src/lib/libbsp/powerpc/gen405/console/consolelite.c (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/console/consolelite.c (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,287 @@ +/* + * This file contains the console driver for the xilinx uart lite. + * + * Author: Keith Robertson + * COPYRIGHT (c) 2005 by Linn Products Ltd, Scotland. + * + * Derived from libbsp/no_cpu/no_bsp/console.c and therefore also: + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + */ + +#include +#include +#include + +#define PORT 0x40600000 +#define RECV_REG 0 +#define TRAN_REG 4 +#define STAT_REG 8 +#define CTRL_REG 12 + +#define POLL_DRIVEN + +/* Uncomment this to enable uart interrupts */ +/* #define INTERRUPT_DRIVEN */ + +struct UartLiteState +{ + unsigned32 iPrevWriteLen; + void* iTty; +}; + +struct UartLiteState gUartLiteState; + +RTEMS_INLINE_ROUTINE unsigned32 uartLiteStatus() +{ + volatile unsigned32 s = *(unsigned32*)(PORT+STAT_REG); + return s; +} + +RTEMS_INLINE_ROUTINE unsigned32 uartLiteControl() +{ + volatile unsigned32 c = *(unsigned32*)(PORT+CTRL_REG); + return c; +} + +RTEMS_INLINE_ROUTINE signed32 uartLiteRead() +{ + volatile signed32 c = *(unsigned32*)(PORT+RECV_REG); + return c; +} + +RTEMS_INLINE_ROUTINE void uartLiteWrite(signed32 ch) +{ + *(unsigned32*)(PORT+TRAN_REG) = ch; +} + +/* Status Register Masks */ +#define PARITY_ERROR 0x80 /* Parity Error */ +#define FRAME_ERROR 0x40 /* Frame Error */ +#define OVERRUN_ERROR 0x20 /* Overrun Error */ +#define STATUS_REG_ERROR_MASK ( PARITY_ERROR | FRAME_ERROR | OVERRUN_ERROR ) + +#define INTR_ENABLED 0x10 /* Interrupts are enabled */ +#define TX_FIFO_FULL 0x08 /* Transmit FIFO is full */ +#define TX_FIFO_EMPTY 0x04 /* Transmit FIFO is empty */ +#define RX_FIFO_FULL 0x02 /* Receive FIFO is full */ +#define RX_FIFO_VALID_DATA 0x01 /* Receive FIFO has valid data */ +/* Control Register Masks*/ +#define ENABLE_INTR 0x10 /* Enable interrupts */ +#define RST_RX_FIFO 0x02 /* Reset and clear RX FIFO */ +#define RST_TX_FIFO 0x01 /* Reset and clear TX FIFO */ + +/* General Defines */ +#define TX_FIFO_SIZE 16 +#define RX_FIFO_SIZE 16 + +RTEMS_INLINE_ROUTINE void uartLiteEnableInterrupt() +{ + *(unsigned32*)(PORT+CTRL_REG) = uartLiteControl() | ENABLE_INTR; +} + +RTEMS_INLINE_ROUTINE void uartLiteReset() +{ + if(uartLiteStatus() & INTR_ENABLED) { + *(unsigned32*)(PORT+CTRL_REG) = ENABLE_INTR | RST_RX_FIFO | RST_TX_FIFO; + } + else { + *(unsigned32*)(PORT+CTRL_REG) = RST_RX_FIFO | RST_TX_FIFO; + } +} + +int uartLitePollWrite(int minor, const char* buf, int len) +{ + int i=0; + volatile unsigned int status = uartLiteStatus(); + for(i=0; i TX_FIFO_SIZE) { + len = TX_FIFO_SIZE; + } + unsigned32 i=0; + gUartLiteState.iPrevWriteLen = len; + for(; i < len; i++) { + uartLiteWrite(buf[i]); + } + } + return RTEMS_SUCCESSFUL; +} + +rtems_status_code uartLiteInit() +{ + uartLiteEnableInterrupt(); + uartLiteReset(); + +#if defined INTERRUPT_DRIVEN + rtems_status_code sc; + rtems_isr_entry oldHandler; + sc = opb_intc_set_vector(uartLiteIsr, 4, &oldHandler); + return sc; +#else + return RTEMS_SUCCESSFUL; +#endif +} + +rtems_device_driver console_initialize(rtems_device_major_number major, + rtems_device_minor_number minor, void* arg) +{ + rtems_status_code status; + + rtems_termios_initialize(); + + /* Initialise the uartlite */ + uartLiteInit(); + + status = rtems_io_register_name("/dev/console", major, 0); + + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + return RTEMS_SUCCESSFUL; +} + +#if defined INTERRUPT_DRIVEN +static rtems_termios_callbacks gInterruptCallbacks = { + 0, /* firstOpen */ + 0, /* lastClose */ + 0, /* pollRead */ + uartLiteInterruptWrite, /* write */ + uartLiteSetAttr, /* uartLiteSetAttr */ + 0, /* stopRemoteTx */ + 0, /* startRemoteTx */ + 1 /* outputUsesInterrupts */ +}; +#elif defined POLL_DRIVEN +static rtems_termios_callbacks gPollCallbacks = { + 0, /* firstOpen */ + 0, /* lastClose */ + uartLitePollRead, /* uartLitePollRead */ + uartLitePollWrite, /* write */ + uartLiteSetAttr, /* uartLiteSetAttr */ + 0, /* stopRemoteTx */ + 0, /* startRemoteTx */ + 0 /* outputUsesInterrupts */ +}; +#endif + +rtems_device_driver console_open(rtems_device_major_number major, + rtems_device_minor_number minor, void* arg) +{ + rtems_status_code sc; + + /* Initialize members of UartLiteState */ + gUartLiteState.iPrevWriteLen = 0; + rtems_libio_open_close_args_t* args = arg; + +#if defined INTERRUPT_DRIVEN + sc = rtems_termios_open (major, minor, arg, &gInterruptCallbacks); +#elif defined POLL_DRIVEN + sc = rtems_termios_open (major, minor, arg, &gPollCallbacks); +#else +#error Must select one of INTERRUPT_DRIVE or POLL_DRIVEN +#endif + + gUartLiteState.iTty = args->iop->data1; + + return sc; +} + +rtems_device_driver console_close(rtems_device_major_number major, + rtems_device_minor_number minor, void* arg) +{ + return rtems_termios_close(arg); +} + +rtems_device_driver console_read(rtems_device_major_number major, + rtems_device_minor_number minor, void* arg) +{ + return rtems_termios_read(arg); +} + +rtems_device_driver console_write(rtems_device_major_number major, + rtems_device_minor_number minor, void* arg) +{ + return rtems_termios_write(arg); +} + +rtems_device_driver console_control(rtems_device_major_number major, + rtems_device_minor_number minor, void* arg) +{ + rtems_libio_ioctl_args_t* args = arg; + if(args->command == RTEMS_IO_SET_ATTRIBUTES) + uartLiteSetAttr(minor, (struct termios*)args->buffer); + + return rtems_termios_ioctl(arg); +} + +#include + +void outputChar(char ch) +{ + uartLitePollWrite(0, &ch, 1); +} + +char inputChar() +{ + return uartLitePollRead(0); +} + +BSP_output_char_function_type BSP_output_char = outputChar; +BSP_polling_getchar_function_type BSP_poll_char = inputChar; + + Index: c/src/lib/libbsp/powerpc/gen405/console/Makefile.am =================================================================== --- c/src/lib/libbsp/powerpc/gen405/console/Makefile.am (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/console/Makefile.am (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,28 @@ +## +## Makefile.am,v 1.8 2002/12/19 05:03:12 ralf Exp +## + + +PGM = $(ARCH)/console.rel + +C_FILES = consolelite.c + +console_rel_OBJECTS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) + +include $(top_srcdir)/../../../../../../automake/compile.am +include $(top_srcdir)/../../../../../../automake/lib.am + +# +# (OPTIONAL) Add local stuff here using += +# + +$(PGM): $(console_rel_OBJECTS) + $(make-rel) + +all-local: $(ARCH) $(console_rel_OBJECTS) $(PGM) + +.PRECIOUS: $(PGM) + +EXTRA_DIST = consolelite.c + +include $(top_srcdir)/../../../../../../automake/local.am Index: c/src/lib/libbsp/powerpc/gen405/startup/bspstart.c =================================================================== --- c/src/lib/libbsp/powerpc/gen405/startup/bspstart.c (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/lib/libbsp/powerpc/gen405/startup/bspstart.c (.../volkano/rtems/rtems-src) (revision 1691) @@ -62,7 +62,7 @@ #include #include #include -#include +#include /* * The original table from the application and our copy of it with @@ -96,7 +96,7 @@ { rtems_status_code status; /* init the PPC405 external interrupt controller handler... */ - status = ictrl_init(); + status = opb_intc_init(); } /* @@ -181,7 +181,7 @@ Cpu_table.postdriver_hook = bsp_postdriver_hook; Cpu_table.interrupt_stack_size = CONFIGURE_INTERRUPT_STACK_MEMORY; - Cpu_table.clicks_per_usec = 300; + Cpu_table.clicks_per_usec = 100; Cpu_table.serial_per_sec = 14625000; /* = (CPU Clock / UART Internal Clock Divisor) */ Cpu_table.serial_external_clock = 0; Cpu_table.timer_internal_clock = 1; Index: c/src/lib/libbsp/powerpc/gen405/startup/linkcmds =================================================================== --- c/src/lib/libbsp/powerpc/gen405/startup/linkcmds (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/lib/libbsp/powerpc/gen405/startup/linkcmds (.../volkano/rtems/rtems-src) (revision 1691) @@ -17,8 +17,8 @@ MEMORY { - RAM : ORIGIN = 0, LENGTH = 64M - FLASH : ORIGIN = 0xFFE00000, LENGTH = 16M + RAM : ORIGIN = 0, LENGTH = 32M + /*FLASH : ORIGIN = 0xFFE00000, LENGTH = 16M*/ } SECTIONS { @@ -69,7 +69,7 @@ *(.lit) *(.shdata) - _init = .; __init = .; *(.init) + __init = .; *(.init) _fini = .; __fini = .; *(.fini) _endtext = ALIGN(0x10); text.end = .; @@ -128,6 +128,7 @@ .sbss2 : { *(.sbss2) *(.gnu.linkonce.sb2.*) } >RAM PROVIDE (__SBSS2_END__ = .); + .jcr : { KEEP (*(.jcr)) } > RAM __SBSS_START__ = .; .bss : { Index: c/src/lib/libbsp/powerpc/gen405/configure.ac =================================================================== --- c/src/lib/libbsp/powerpc/gen405/configure.ac (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/lib/libbsp/powerpc/gen405/configure.ac (.../volkano/rtems/rtems-src) (revision 1691) @@ -18,7 +18,7 @@ AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes") -RTEMS_BSPOPTS_SET([PPC_USE_SPRG],[*],[1]) +RTEMS_BSPOPTS_SET([PPC_USE_SPRG],[*],[]) RTEMS_BSPOPTS_HELP([PPC_USE_SPRG], [If defined, then the PowerPC specific code in RTEMS will use some of the special purpose registers to slightly optimize interrupt @@ -36,6 +36,10 @@ dlentry/Makefile include/Makefile startup/Makefile +console/Makefile +opbintctrl/Makefile +network/Makefile +start/Makefile wrapup/Makefile]) RTEMS_PPC_EXCEPTIONS([old]) Index: c/src/lib/libbsp/powerpc/gen405/include/bsp.h =================================================================== --- c/src/lib/libbsp/powerpc/gen405/include/bsp.h (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/lib/libbsp/powerpc/gen405/include/bsp.h (.../volkano/rtems/rtems-src) (revision 1691) @@ -98,7 +98,7 @@ /* Constants */ #define RAM_START 0 -#define RAM_END 0x00800000 +#define RAM_END 0x02000000 /* miscellaneous stuff assumed to exist */ @@ -106,6 +106,12 @@ extern rtems_configuration_table BSP_Configuration; /* owned by BSP */ extern rtems_cpu_table Cpu_table; /* owned by BSP */ +/* Network Defines */ + +#define RTEMS_BSP_NETWORK_DRIVER_NAME "xilEmac0" +extern signed32 xilEmacAttachWrapper(struct rtems_bsdnet_config*); +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH xilEmacAttachWrapper + /* * Device Driver Table Entries */ Index: c/src/lib/libbsp/powerpc/gen405/Makefile.am =================================================================== --- c/src/lib/libbsp/powerpc/gen405/Makefile.am (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/lib/libbsp/powerpc/gen405/Makefile.am (.../volkano/rtems/rtems-src) (revision 1691) @@ -6,7 +6,7 @@ # wrapup is the one that actually builds and installs the library # from the individual .rel files built in other directories -SUBDIRS = include dlentry startup @exceptions@ wrapup +SUBDIRS = include dlentry opbintctrl startup @exceptions@ console network start wrapup include $(top_srcdir)/../../bsp.am Index: c/src/lib/libbsp/powerpc/gen405/network/Makefile.am =================================================================== --- c/src/lib/libbsp/powerpc/gen405/network/Makefile.am (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/network/Makefile.am (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,28 @@ +## +## Makefile.am,v 1.8 2002/12/19 05:03:12 ralf Exp +## + + +PGM = $(ARCH)/network.rel + +C_FILES = network.c + +console_rel_OBJECTS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) + +include $(top_srcdir)/../../../../../../automake/compile.am +include $(top_srcdir)/../../../../../../automake/lib.am + +# +# (OPTIONAL) Add local stuff here using += +# + +$(PGM): $(console_rel_OBJECTS) + $(make-rel) + +all-local: $(ARCH) $(console_rel_OBJECTS) $(PGM) + +.PRECIOUS: $(PGM) + +EXTRA_DIST = network.c + +include $(top_srcdir)/../../../../../../automake/local.am Index: c/src/lib/libbsp/powerpc/gen405/network/network.c =================================================================== --- c/src/lib/libbsp/powerpc/gen405/network/network.c (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/network/network.c (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,47 @@ +/* + * BSP specific code for the Xilinx Open Processor Bus Ethernet Media + * Access Controller (OPB EMAC) version 1.02a + * + * Author: Keith Robertson + * Copyright (c) 2005 Linn Products Ltd, Scotland. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + */ + +#include +#include +#include + +struct XilEmac gXilEmac; + +rtems_isr xilEmacIsrWrapper(rtems_vector_number aVector) +{ + xilEmacIsr(aVector, &gXilEmac); +} + +signed32 xilEmacAttachWrapper(struct rtems_bsdnet_ifconfig* aBsdConfig, signed32 aNotUsed ) +{ + struct XilEmacConfig config; + + config.iAddr = 0x40C00000; + config.iBroadcast = 1; + config.iMulticast = 1; + + rtems_status_code sc = xilEmacAttach(aBsdConfig, &gXilEmac, &config); + /* Attach returns 1 for success! */ + if(sc != 1) { + printf("Failed to attach xilinx ethermac driver\n"); + return 0; + } + rtems_isr_entry oldHandler; + sc = opb_intc_set_vector(xilEmacIsrWrapper, 0, &oldHandler); + if(sc != RTEMS_SUCCESSFUL) { + printf("Could not set interrupt vector for ethernet\n"); + /* Attach returns 0 for failure! */ + return 0; + } +} + Index: c/src/lib/libbsp/powerpc/gen405/start/Makefile.am =================================================================== --- c/src/lib/libbsp/powerpc/gen405/start/Makefile.am (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/start/Makefile.am (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,24 @@ + +S_FILES = rtems_crti.S +S_O_FILES = $(S_FILES:%.S=$(ARCH)/%.$(OBJEXT)) +OBJS = $(S_O_FILES) + +include $(top_srcdir)/../../../../../../automake/compile.am +include $(top_srcdir)/../../../../../../automake/lib.am + +bsplib_DATA = $(PROJECT_RELEASE)/lib/rtems_crti.$(OBJEXT) + +$(PROJECT_RELEASE)/lib/rtems_crti.$(OBJEXT): $(ARCH)/rtems_crti.$(OBJEXT) + $(INSTALL_DATA) $< $@ + +TMPINSTALL_FILES += $(PROJECT_RELEASE)/lib/rtems_crti.$(OBJEXT) + +all-local: $(ARCH) $(OBJS) $(ARCH)/rtems_crti.$(OBJEXT) $(TMPINSTALL_FILES) + +$(OBJS): $(ARCH) + +.PRECIOUS: $(ARCH)/rtems_crti.$(OBJEXT) + + +include $(top_srcdir)/../../../../../../automake/local.am + Index: c/src/lib/libbsp/powerpc/gen405/start/rtems_crti.S =================================================================== --- c/src/lib/libbsp/powerpc/gen405/start/rtems_crti.S (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/lib/libbsp/powerpc/gen405/start/rtems_crti.S (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,33 @@ +/* rtems_crti.S */ +#include + + /* terminate the __init() function and create + * a new head '_init' for use by RTEMS to + * invoke C++ global constructors + * NOTE: it is essential that this snippet + * is hooked between ecrti and crtbegin + * + * ecrti has the following .init section: + * __init: + * stwu r1,-16(r1) + * mflr r0 + * stw r0,20(r1) + * + * The reason for this is that we want to call + * __eabi() at an early stage but prevent __eabi() + * from branching to __init (C++ exception init + * and global CTORs). Hence we make __init a no-op + * and create a new entry point: + */ + .section ".init","ax" + .align 2 + lwz r0,r20(r1) + mtlr r0 + addi r1,r1,16 + blr + .globl _init + .type _init,@function +_init: + stwu r1,-16(r1) + mflr r0 + stw r0,20(r1) Index: c/src/lib/libbsp/powerpc/gen405/wrapup/Makefile.am =================================================================== --- c/src/lib/libbsp/powerpc/gen405/wrapup/Makefile.am (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/lib/libbsp/powerpc/gen405/wrapup/Makefile.am (.../volkano/rtems/rtems-src) (revision 1691) @@ -2,9 +2,9 @@ ## $Id: Makefile.am,v 1.7 2002/12/11 09:06:35 ralf Exp $ ## -BSP_PIECES = startup dlentry +BSP_PIECES = startup console dlentry opbintctrl network # pieces to pick up out of libcpu/ppc -CPU_PIECES = clock timer console tty_drv vectors ictrl +CPU_PIECES = clock timer tty_drv vectors # bummer; have to use $foreach since % pattern subst rules only replace 1x OBJS = $(foreach piece, $(BSP_PIECES), $(wildcard ../$(piece)/$(ARCH)/*.$(OBJEXT))) \ Index: c/src/libchip/network/xilemac.c =================================================================== --- c/src/libchip/network/xilemac.c (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/libchip/network/xilemac.c (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,743 @@ +/* + * Reusable portion (libchip) of the Xilinx Open Processor Bus Ethernet Media + * Access Controller (OPB EMAC) version 1.02a + * + * Author: Keith Robertson + * Copyright (c) 2005 Linn Products Ltd, Scotland. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +/* Register Defines */ + +/* IPIF Interrupt Service Regisers */ +#define DISR 0x0000 /*< Device Interrupt Status Register */ +#define DIPR 0x0004 /*< Device Interrupt Pending Register */ +#define DIER 0x0008 /*< Device Interrupt Enable Register */ +#define DIID 0x0018 /*< Device Interrupt ID Register */ +#define DGIE 0x001C /*< Device Global Interrupt Enable */ +#define IPISR 0x0020 /*< IP Interrupt Status Register */ +#define IPIER 0x0028 /*< IP Interrupt Enable Register */ + +/* IPIF Software Reset/MIR Service Registers */ +#define DRST 0x0040 /*< Device Software Reset */ +#define DMIR 0x0040 /*< Module Ident Register */ + +/* IPIF Read FIFO Service Registers */ +#define RFRST 0x2010 /*< Read Fifo Reset */ +#define RFMIR 0x2010 /*< Read Fifo Module ID Register */ +#define RFSR 0x2014 /*< Read Fifo Status Register */ +#define RFDR 0x2200 /*< Read Fifo Data Register */ + +/* IPIF Write FIFO Service Registers */ +#define WFRST 0x2000 /*< Write Fifo Reset */ +#define WFMIR 0x2000 /*< Write Fifo Module ID Register */ +#define WFSR 0x2004 /*< Write Fifo Status Register */ +#define WFDR 0x2100 /*< Write Fifo Data Register */ +#define WFDRU 0x28FF /*< Write Fifo Upper Data Register */ + +/* EMAC Core Registers */ +#define EMIR 0x1100 /*< EMAC Module ID Register */ +#define ECR 0x1104 /*< EMAC Control Register */ +#define IFGP 0x1108 /*< Interframe Gap Register */ +#define SAH 0x110C /*< Station Address High */ +#define SAL 0x1110 /*< Station Address Low */ +#define MGTCR 0x1114 /*< MII Management Control Register */ +#define MGTDR 0x1118 /*< MII Management Data Register */ +#define RPLR 0x111C /*< Receive Packet Length Register */ +#define TPLR 0x1120 /*< Transmit Packet Length Register */ +#define TSR 0x1124 /*< Transmit Status Register */ +#define RMFC 0x1128 /*< Receive Missed Frame Count */ +#define RCC 0x112C /*< Receive Collision Count */ +#define RFCSEC 0x1130 /*< Receive FCS Error Count */ +#define RAEC 0x1134 /*< Receive Alignment Error Count */ +#define TEDC 0x1138 /*< Transmit Excess Deferral Count */ +#define RSR 0x113C /*< Receive Status Register */ +#define CAMH 0x1140 /*< Receive CAM Entry High Register */ +#define CAML 0x1144 /*< Receive CAM Entry Low Register */ + +/* Register Masks */ + +/* RFSR */ +#define RFSR_OCCUPANCY_MASK 0x00FFFFFF /*< Read Fifo Status Occupancy Mask */ + +/* WFSR */ +#define WFSR_VACANCY_MASK 0x00FFFFFF /*< Write Fifo Status Vacancy Mask */ + +/* WFRST */ +#define WFRST_VALUE 0x0000000A /*< Value required to reset fifo */ + +/* RFRST */ +#define RFRST_VALUE 0x0000000A /*< Value required to reset fifo */ + +/* DRST */ +#define DRST_VALUE 0x0000000A /*< Value required to reset device */ + +/* DGIE */ +#define DGIE_GIE_OFF 0x00000000 /*< Turn off master interrupt switch */ +#define DGIE_GIE_ON 0x80000000 /*< Turn on master interrupt switch */ + +/* ECR */ +#define ECR_RSTTX 0x40000000 /*< Reset transmitter */ +#define ECR_ENTX 0x20000000 /*< Enable transmitter */ +#define ECR_RSTRX 0x10000000 /*< Reset receiver */ +#define ECR_ENRX 0x08000000 /*< Enable receiver */ +#define ECR_MA 0x00010000 /*< Enable Multicast Reception */ + +/* DISR and DIER and DIPR (all have same offsets */ + +#define DISR_TERR 0x00000001 /*< Transaction Error */ +#define DISR_IPIR 0x00000004 /*< IP (ie EMAC) interrupt request */ +#define DISR_RFDL 0x00000020 /*< Receive FIFO Deadlock */ +#define DISR_WFDL 0x00000040 /*< Xmit FIFO Deadloack */ +#define DISR_INTR_MASK (DISR_IPIR) +/*| DISR_RFDL \ + | DISR_WFDL)*/ + +/* TSR */ + +#define TSR_TXED 0x80000000 /*< Transmit Excess Deferral Error */ +#define TSR_PFIFOU 0x40000000 /*< Packet Fifo Underrun */ +#define TSR_TXLC 0x01000000 /*< Transmit Late Collision Error */ + +/* IPISR and IPIER (they both have the same offsets */ +#define IPISR_TXCP 0x00000001 /*< Transmit Complete */ +#define IPISR_RXCP 0x00000002 /*< Receive Complete */ +#define IPISR_TERR 0x00000004 /*< Transmit Error */ +#define IPISR_RERR 0x00000008 /*< Receive Error */ +#define IPISR_TSFE 0x00000010 /*< Transmit Status Fifo Empty */ +#define IPISR_RLFE 0x00000020 /*< Receive Length Fifo Empty */ +#define IPISR_TLFF 0x00000040 /*< Transmit Length Fifo Full */ +#define IPISR_TSFO 0x00000200 /*< Transmit Status Fifo Overrun */ +#define IPISR_TSFU 0x00000400 /*< Transmit Status Fifo Underrun */ +#define IPISR_TLFO 0x00000800 /*< Transmit Length Fifo Overrun */ +#define IPISR_TLFU 0x00001000 /*< Transmit Length Fifo Underrun */ +#define IPISR_TPPR 0x00002000 /*< Transmit Pause Packet Received */ +#define IPISR_RDFO 0x00004000 /*< Receive Data Fifo Overrun */ +#define IPISR_RMFE 0x00008000 /*< Receive Missed Frame Error */ +#define IPISR_RCE 0x00010000 /*< Receive Collison Error */ +#define IPISR_RFCS 0x00020000 /*< Receive FCS Error Interrupt */ +#define IPISR_RLER 0x00040000 /*< Receive Length Field Error */ +#define IPISR_RSE 0x00080000 /*< Receive Short Error */ +#define IPISR_RLE 0x00100000 /*< Receive Long Frame Error */ +#define IPISR_RAE 0x00200000 /*< Receive Alignment Error */ + +#define IPISR_INTR_RX_MASK ( IPISR_RERR | \ + IPISR_RDFO | \ + IPISR_RMFE | \ + IPISR_RCE | \ + IPISR_RFCS | \ + IPISR_RLER | \ + IPISR_RSE | \ + IPISR_RLE | \ + IPISR_RAE | \ + IPISR_RXCP ) + +#define IPISR_INTR_TX_MASK ( IPISR_TSFO | \ + IPISR_TSFU | \ + IPISR_TLFO | \ + IPISR_TLFU | \ + IPISR_TPPR | \ + IPISR_TXCP ) + +#define IPISR_INTR_MASK (IPISR_INTR_RX_MASK | IPISR_INTR_TX_MASK) + +#define INTERRUPT_EVENT RTEMS_EVENT_1 +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +/* Reading/Writing memory mapped i/o */ +#define IN32(aPtr) (*(volatile unsigned32 *)(aPtr)) +#define OUT32(aPtr, aValue) { (*(volatile unsigned32 *)(aPtr) = aValue); } + +void xilEmacInit(void* aXilEmac); +void xilEmacReset(struct XilEmac* aXilEmac); +void xilEmacStop(struct XilEmac* aXilEmac); +void xilEmacSend(struct ifnet* aIfnet); +void xilEmacStart(struct XilEmac* aIfnet); +void xilEmacMacAddress(struct XilEmac* aXilEmac, unsigned8* aBuf); +void xilEmacSetMacAddress(struct XilEmac* aXilEmac, + unsigned8* aAddr); +void xilEmacPrintStats(struct XilEmacStats* aStats); +signed32 xilEmacIoctl(struct ifnet* aIfnet, signed32 aCommand, caddr_t aData); + +void xilEmacRxThread(void* aXilEmac); +void xilEmacTxThread(void* aXilEmac); + + +/* Read/Write Register Functions */ +void +xilFifoRead(unsigned32 aBaseAddr, unsigned32* aBuf, unsigned32 aBytes) +{ + unsigned32 words = aBytes >> 2; + unsigned32 i; + + for(i = 0; i < words; i++) { + aBuf[i] = IN32(aBaseAddr + RFDR); + } + + /* If there was a non word sized read */ + if(aBytes & 3) { + unsigned32 value; + unsigned8* byteBuf = (unsigned8*)aBuf; + value = IN32(aBaseAddr + RFDR); + unsigned32 bytes = words<<2; + switch(aBytes & 3) { + case 1: + byteBuf[bytes] = value >> 24; + break; + case 2: + byteBuf[bytes] = value >> 24; + byteBuf[bytes+1] = value >> 16 & 0xff; + break; + case 3: + byteBuf[bytes] = value >> 24; + byteBuf[bytes+1] = value >> 16 & 0xff; + byteBuf[bytes+2] = value >> 8 & 0xff; + break; + } + } +} + +void +xilFifoWrite(unsigned32 aBaseAddr, unsigned32* aBuf, unsigned32 aBytes) +{ + + /* Ensure there's enough space in fifo */ + volatile unsigned32 space = IN32(aBaseAddr + WFSR) & WFSR_VACANCY_MASK; + unsigned32 words = aBytes >> 2; + + /* Fifo reports space in words, therefore we need to count all the words + * we'll write into, even if their partial */ + if(aBytes & 3) { + words++; + } + + /* If not enough space, spin until previous packet empties out */ + if(space < words) { + /*printf("Tx Fifo waiting for space. Space: %x. Len: %x.\n",space, words);*/ + while( (space = IN32(aBaseAddr + WFSR) & WFSR_VACANCY_MASK) < words ); + /*printf("Space now available: Space: %x, Len: %x.\n",space, words);*/ + } + + /* Bring words back to number of full words */ + if(aBytes & 3) { + words--; + } + + /* Write out all full words in buffer */ + unsigned32 i; + for(i = 0; i < words; i++) { + OUT32(aBaseAddr + WFDR, aBuf[i]); + } + + /* If there's a non word multiple write output the remaining bytes */ + if(aBytes & 3) { + unsigned32 value = 0; + unsigned8* ptr = (unsigned8*)&value; + unsigned8* byteBuf = (unsigned8*)aBuf; + unsigned32 lastByte = words << 2; + switch(aBytes & 3) { + case 1: + ptr[0] = byteBuf[lastByte]; + break; + case 2: + ptr[0] = byteBuf[lastByte]; + ptr[1] = byteBuf[lastByte+1]; + break; + case 3: + ptr[0] = byteBuf[lastByte]; + ptr[1] = byteBuf[lastByte+1]; + ptr[2] = byteBuf[lastByte+2]; + break; + } + OUT32(aBaseAddr + WFDR, value); + } +} + +void xilEmacInit(void* aXilEmac) +{ + struct XilEmac* xilEmac = aXilEmac; + + if(xilEmac->iRxThread == 0 && xilEmac->iTxThread == 0) { + xilEmac->iRxThread = rtems_bsdnet_newproc("xerx", 4096, xilEmacRxThread, + xilEmac); + xilEmac->iTxThread = rtems_bsdnet_newproc("xetx", 4096, xilEmacTxThread, + xilEmac); + } + + xilEmac->iArpcom.ac_if.if_flags |= IFF_RUNNING; +} + +void xilEmacReset(struct XilEmac* aXilEmac) +{ + xilEmacStop(aXilEmac); + xilEmacStart(aXilEmac); +} + +void xilEmacStop(struct XilEmac* aXilEmac) +{ + /* Disable receiver and transmitter */ + unsigned32 ecr = IN32(aXilEmac->iAddr + ECR); + ecr &= ~(ECR_ENTX | ECR_ENRX | ECR_MA); + OUT32(aXilEmac->iAddr + ECR, ecr); + + /* Disable global interrupt enable */ + OUT32(aXilEmac->iAddr + DGIE, DGIE_GIE_OFF); + + aXilEmac->iStarted = 0; +} + +void xilEmacStart(struct XilEmac* aXilEmac) +{ + if( !(aXilEmac->iStarted) ) { + + /* Reset EMAC device */ + OUT32(aXilEmac->iAddr + DRST, DRST_VALUE); + /* Reset Read and Write Fifos */ + OUT32(aXilEmac->iAddr + RFRST, RFRST_VALUE); + OUT32(aXilEmac->iAddr + WFRST, WFRST_VALUE); + + /* Set the hardware address, writing DRST, resets this */ + xilEmacSetMacAddress(aXilEmac, aXilEmac->iArpcom.ac_enaddr); + + /* Enable appropriate interrupts in the device interrupt enable register */ + OUT32(aXilEmac->iAddr + DIER, DISR_INTR_MASK); + + /* Enable appropriate interrupts in the IP interrupt enable register */ + OUT32(aXilEmac->iAddr + IPIER, IPISR_INTR_MASK); + + /* Turn on global interrupt enable */ + OUT32(aXilEmac->iAddr + DGIE, DGIE_GIE_ON); + + /* Enable transmitter and receiver and enable multicast reception */ + unsigned32 ecr = IN32(aXilEmac->iAddr + ECR); + ecr |= (ECR_ENTX | ECR_ENRX | ECR_MA); + /* Take Tx and Rx out of reset */ + ecr &= ~(ECR_RSTTX | ECR_RSTRX); + OUT32(aXilEmac->iAddr + ECR, ecr); + + /* Device is started */ + aXilEmac->iStarted = 1; + } +} + +void xilEmacMacAddress(struct XilEmac* aXilEmac, unsigned8* aBuf) +{ + unsigned32 macHi; + unsigned32 macLo; + + macHi = IN32(aXilEmac->iAddr + SAH); + macLo = IN32(aXilEmac->iAddr + SAL); + + aBuf[0] = (unsigned8)(macHi >> 8); + aBuf[1] = (unsigned8)(macHi); + aBuf[2] = (unsigned8)(macLo >> 24); + aBuf[3] = (unsigned8)(macLo >> 16); + aBuf[4] = (unsigned8)(macLo >> 8); + aBuf[5] = (unsigned8)(macLo); +} + +void xilEmacSetMacAddress(struct XilEmac* aXilEmac, + unsigned8* aAddr) +{ + /* You can't change the mac address while the card is in operation */ + assert(aXilEmac->iStarted == 0); + + /* Create and output high half word */ + unsigned32 addr = (aAddr[0] << 8) | aAddr[1]; + OUT32(aXilEmac->iAddr + SAH, addr); + + /* Create and output low word */ + addr = (aAddr[2] << 24) | (aAddr[3] << 16) | + (aAddr[4] << 8) | (aAddr[5]); + OUT32(aXilEmac->iAddr + SAL, addr); +} + +void xilEmacPrintStats(struct XilEmacStats* aStats) +{ + printf("Interrupts: %u\n", aStats->iInterrupts); + printf("Rx Interrupts: %u", aStats->iRxInterrupts); + printf("Errors: %u", aStats->iRxError); + printf("Data Overrun: %u\n", aStats->iRxDataOverrun); + printf("Missed: %u", aStats->iRxMissed); + printf("Collision: %u", aStats->iRxCollision); + printf("Bad CRC: %u\n", aStats->iRxFcs); + printf("Bad Length Field: %u", aStats->iRxLengthField); + printf("Short: %u", aStats->iRxShort); + printf("Long: %u\n", aStats->iRxLong); + printf("Bad Alignment: %u\n", aStats->iRxAlignment); + + printf("Tx Interrupts: %u", aStats->iTxInterrupts); + printf("Status Overrun: %u", aStats->iTxStatusOverrun); + printf("Status Underrun: %u\n", aStats->iTxStatusUnderrun); + printf("Length Overrun: %u", aStats->iTxLengthOverrun); + printf("Length Underrun: %u", aStats->iTxLengthUnderrun); + printf("Pause Packet: %u\n", aStats->iTxPausePacket); + printf("Deferred: %u", aStats->iTxDeferred); + printf("Late Collision: %u", aStats->iTxLateCollision); + printf("Data Underrun: %u\n", aStats->iTxDataUnderrun); + + printf("Transaction Bus Errors: %u\n", aStats->iTerr); + printf("Write Fifo Deadlocks: %u", aStats->iWfdl); + printf("Read Fifo Deadlocks: %u", aStats->iRfdl); +} + +rtems_isr xilEmacIsr(rtems_vector_number aVector, struct XilEmac* aXilEmac) +{ + aXilEmac->iStats.iInterrupts++; + + /* We received an interrupt, check which one */ + volatile unsigned32 status = IN32(aXilEmac->iAddr + DIPR); + if(status & DISR_IPIR) { + + /* Normal case, emac caused interrupt of general interrupt architecture + * Figure out which one of the EMAC interrupts it was */ + volatile unsigned32 ipisr = IN32(aXilEmac->iAddr + IPISR); + + /* Clear the interrupts straight away. This ensures latched interrupts + * are up to date with the actual state of the device. + */ + OUT32(aXilEmac->iAddr + IPISR, ipisr); + + /* Receive Complete ? + * 1) inc counter, 2) disable interrupt, 3) notify rxThread + */ + if(ipisr & IPISR_RXCP) { + aXilEmac->iStats.iRxInterrupts++; + + /* The Receive Complete (IPISR_RXCP) and Xmit Complete + * (IPISR_TXCP) interrupts are latached and only cleared by reading the + * fifo. As we do this in a different thread, we need to disable the + * interrupt here, notify the thread, and ensure we renable the interrupt + * when that thread is done emptying the fifo. + */ + volatile unsigned32 ier = IN32(aXilEmac->iAddr + IPIER); + ier &= ~IPISR_RXCP; + OUT32(aXilEmac->iAddr + IPIER, ier); + + rtems_event_send(aXilEmac->iRxThread, INTERRUPT_EVENT); + } + + /* Transmit Complete ? + * inc counter, check tsr, bump stats as appropriate + */ + if(ipisr & IPISR_TXCP) { + aXilEmac->iStats.iTxInterrupts++; + volatile unsigned32 tsr = IN32(aXilEmac->iAddr + TSR); + if(tsr & TSR_TXED) { + aXilEmac->iStats.iTxDeferred++; + } + if(tsr & TSR_TXLC) { + aXilEmac->iStats.iTxLateCollision++; + } + if(tsr & TSR_PFIFOU) { + aXilEmac->iStats.iTxDataUnderrun++; + } + + /* Clear the interrupt. This will actually clear the interrupt as we + * have read the TSR fifo and therefore removed the source of the + * interrupt + */ + OUT32(aXilEmac->iAddr + IPISR, IPISR_TXCP); + } + if(ipisr & IPISR_RAE) { + aXilEmac->iStats.iRxAlignment = IN32(aXilEmac->iAddr + RAEC); + } + if(ipisr & IPISR_RLE) { + aXilEmac->iStats.iRxLong++; + } + if(ipisr & IPISR_RSE) { + aXilEmac->iStats.iRxShort++; + } + if(ipisr & IPISR_RLFE) { + aXilEmac->iStats.iRxLengthField++; + } + if(ipisr & IPISR_RFCS) { + aXilEmac->iStats.iRxFcs = IN32(aXilEmac->iAddr + RFCSEC); + } + if(ipisr & IPISR_RCE) { + aXilEmac->iStats.iRxCollision = IN32(aXilEmac->iAddr + RCC); + } + if(ipisr & IPISR_RMFE) { + aXilEmac->iStats.iRxMissed = IN32(aXilEmac->iAddr + RMFC); + } + if(ipisr & IPISR_RDFO) { + aXilEmac->iStats.iRxDataOverrun++; + } + if(ipisr & IPISR_RERR) { + aXilEmac->iStats.iRxError++; + } + if(ipisr & IPISR_TSFO) { + aXilEmac->iStats.iTxStatusOverrun++; + } + if(ipisr & IPISR_TSFU) { + aXilEmac->iStats.iTxStatusUnderrun++; + } + if(ipisr & IPISR_TLFO) { + aXilEmac->iStats.iTxLengthOverrun++; + } + if(ipisr & IPISR_TLFU) { + aXilEmac->iStats.iTxLengthUnderrun++; + } + } + if(status & DISR_TERR) { + aXilEmac->iStats.iTerr++; + } + if(status & DISR_WFDL) { + aXilEmac->iStats.iWfdl++; + } + if(status & DISR_RFDL) { + aXilEmac->iStats.iRfdl++; + } +} + +signed32 xilEmacAttach(struct rtems_bsdnet_ifconfig* aBsdConfig, + struct XilEmac* aXilEmac, struct XilEmacConfig* aConfig) +{ + struct ifnet* ifp; + signed32 mtu; + signed32 unit; + char* unitName; + + unit = rtems_bsdnet_parse_driver_name(aBsdConfig, &unitName); + if(unit < 0 ) { + return 0; + } + + ifp = &(aXilEmac->iArpcom.ac_if); + memset(aXilEmac, 0, sizeof(struct XilEmac)); + + if(aBsdConfig->hardware_address) { + memcpy(aXilEmac->iArpcom.ac_enaddr, aBsdConfig->hardware_address, + ETHER_ADDR_LEN); + } else { + printf("No hardware address given in rtems_bsdnet_ifconfig\n"); + return 0; + } + + aXilEmac->iConfig.iBroadcast = aConfig->iBroadcast; + aXilEmac->iConfig.iAddr = aConfig->iAddr; + aXilEmac->iConfig.iMulticast = aConfig->iMulticast; + + /* This next one is just a shortcut copy of the previous */ + aXilEmac->iAddr = aConfig->iAddr; + + if(aBsdConfig->mtu) { + mtu = aBsdConfig->mtu; + } else { + mtu = ETHERMTU; + } + + ifp->if_softc = aXilEmac; + ifp->if_unit = unit; + ifp->if_name = unitName; + ifp->if_mtu = mtu; + ifp->if_init = xilEmacInit; + ifp->if_ioctl = xilEmacIoctl; + ifp->if_start = xilEmacSend; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + + if(ifp->if_snd.ifq_maxlen == 0) { + ifp->if_snd.ifq_maxlen = ifqmaxlen; + } + + if_attach(ifp); + ether_ifattach(ifp); + + return 1; +} + +signed32 xilEmacSetMulticastFilter(struct XilEmac* aXilEmac) +{ + return 0; +} + +signed32 xilEmacIoctl(struct ifnet* aIfnet, signed32 aCommand, caddr_t aData) +{ + struct XilEmac* xilEmac = aIfnet->if_softc; + signed32 error = 0; + + switch(aCommand) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl(aIfnet, aCommand, aData); + break; + case SIOCSIFFLAGS: + switch(aIfnet->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + xilEmacStop(xilEmac); + break; + case IFF_UP: + xilEmacStart(xilEmac); + break; + case IFF_UP | IFF_RUNNING: + xilEmacReset(xilEmac); + break; + default: + assert(0); + break; + } + break; + case SIOCADDMULTI: + case SIOCDELMULTI: { + struct ifreq* ifr = (struct ifreq*) aData; + error = (aCommand == SIOCADDMULTI ? + ether_addmulti(ifr, &(xilEmac->iArpcom)) : + ether_delmulti(ifr, &(xilEmac->iArpcom)) ); + /*ENETRESET indicates that driver should update its multicast filters */ + if(error == ENETRESET) { + error = xilEmacSetMulticastFilter(xilEmac); + } + break; + } + + case SIO_RTEMS_SHOW_STATS: + xilEmacPrintStats(&(xilEmac->iStats)); + break; + + default: + error = EINVAL; + break; + } + return error; +} + +void xilEmacSend(struct ifnet* aIfnet) +{ + struct XilEmac* xilEmac = aIfnet->if_softc; + + rtems_event_send(xilEmac->iTxThread, START_TRANSMIT_EVENT); + aIfnet->if_flags |= IFF_OACTIVE; +} + +unsigned8 gTxBuf[2048]; + +void xilEmacSendPacket(struct XilEmac* aXilEmac, struct mbuf* aMbuf) +{ + struct mbuf* n = aMbuf; + unsigned32 len = 0; + +#ifdef DEBUG + printf("SendPacket\n"); + printf("TXD: 0x%08x\n", (signed32) n->m_data); +#endif + + for(;;) { +#ifdef DEBUG + unsigned32 i = 0; + printf("MBUF: 0x%08x : ", (signed32) n->m_data); + for (i=0;im_len;i+=2) { + printf("%02x%02x ", mtod(n, unsigned8*)[i], mtod(n, unsigned8*)[i+1]); + } + printf("\n"); +#endif + + memcpy(gTxBuf+len, mtod(n, unsigned8*), n->m_len); + len += n->m_len; + + if( (n = n->m_next) == 0) { + break; + } + } + m_freem(aMbuf); + xilFifoWrite(aXilEmac->iAddr, (unsigned32*)gTxBuf, len); + /* Set the Transmit Packet Length Register which tells the xmit to start + * sending */ + OUT32(aXilEmac->iAddr + TPLR, len); + +#ifdef DEBUG + memset(gTxBuf, 0, len); +#endif +} + +void xilEmacTxThread(void* aXilEmac) +{ + struct XilEmac* xilEmac = aXilEmac; + rtems_event_set events; + struct mbuf* m; + + for(;;) { + /* Wait for a packet to send */ + rtems_bsdnet_event_receive(START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events); + + /* Send packets till queue empty */ + for(;;) { + IF_DEQUEUE(&(xilEmac->iArpcom.ac_if.if_snd), m); + if(!m) { + /* End of mbuf queue */ + break; + } + xilEmacSendPacket(xilEmac, m); + } + ifnet->if_flags &= ~IFF_OACTIVE; + } +} + +void xilEmacRxThread(void* aXilEmac) +{ + struct XilEmac* xilEmac = aXilEmac; + rtems_event_set events; + + for(;;) { + rtems_bsdnet_event_receive(INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, &events); + + volatile unsigned32 status = IN32(xilEmac->iAddr + IPISR); + + /* Receive Complete? */ + if(status & IPISR_RXCP) { + + /* Whilst there's still packets available (RXCP stays active as long as + * one length value has not been read from RPLR) */ + while( (status = IN32(xilEmac->iAddr + IPISR)) & IPISR_RXCP ) { + + /* read length of received packet */ + unsigned32 len = IN32(xilEmac->iAddr + RPLR); + + struct mbuf* m; + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + + struct ifnet* ifp = &(xilEmac->iArpcom.ac_if); + m->m_pkthdr.rcvif = ifp; + + xilFifoRead(xilEmac->iAddr, mtod(m, unsigned32*), len); + m->m_len = len - sizeof(struct ether_header); + m->m_pkthdr.len = len - sizeof(struct ether_header); + struct ether_header* eh; + eh = mtod(m, struct ether_header*); + m->m_data += sizeof(struct ether_header); + + ether_input(ifp, eh, m); + + /* Try and turn off RXCP bit. If there's still more packets, then this + * will reassert immediately. If there's no more packets, this will + * turn it off. + */ + OUT32(xilEmac->iAddr + IPISR, IPISR_RXCP); + } + } + else { + printf("unhandled status: %x\n", status); + } + /* Re-enable receive complete interrupt */ + OUT32(xilEmac->iAddr + IPIER, IPISR_RXCP); + } +} + Index: c/src/libchip/network/xilemac.h =================================================================== --- c/src/libchip/network/xilemac.h (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/libchip/network/xilemac.h (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,82 @@ +/* + * Reusable portion (libchip) of the Xilinx Open Processor Bus Ethernet Media + * Access Controller (OPB EMAC) version 1.02a + * + * Author: Keith Robertson + * Copyright (c) 2005 Linn Products Ltd, Scotland. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + */ + +#ifndef _XILINX_EMAC_ +#define _XILINX_EMAC_ + + +#include +#include +#include + +/* This doesn't get defined automatically for header files. It is needed + * for ether_ioctl to be visible in the freebsd networking stack. */ +#define KERNEL +#include + +#include +#include +#include + +struct XilEmacStats { + unsigned32 iInterrupts; + + unsigned32 iRxInterrupts; + unsigned32 iRxError; + unsigned32 iRxDataOverrun; + unsigned32 iRxMissed; + unsigned32 iRxCollision; + unsigned32 iRxFcs; + unsigned32 iRxLengthField; + unsigned32 iRxShort; + unsigned32 iRxLong; + unsigned32 iRxAlignment; + + unsigned32 iTxInterrupts; + unsigned32 iTxStatusOverrun; + unsigned32 iTxStatusUnderrun; + unsigned32 iTxLengthOverrun; + unsigned32 iTxLengthUnderrun; + unsigned32 iTxPausePacket; + + unsigned32 iTxDeferred; + unsigned32 iTxLateCollision; + unsigned32 iTxDataUnderrun; + + unsigned32 iTerr; + unsigned32 iWfdl; + unsigned32 iRfdl; +}; + +struct XilEmacConfig { + unsigned32 iAddr; + unsigned8 iBroadcast; + unsigned8 iMulticast; +}; + +struct XilEmac { + struct arpcom iArpcom; + struct XilEmacConfig iConfig; + struct XilEmacStats iStats; + unsigned32 iStarted; + unsigned32 iAddr; + + rtems_id iRxThread; + rtems_id iTxThread; +}; + +rtems_isr xilEmacIsr(rtems_vector_number aVector, struct XilEmac* aXilEmac); +signed32 xilEmacAttach(struct rtems_bsdnet_ifconfig* aBsdConfig, + struct XilEmac* aXilEmac, struct XilEmacConfig* aConfig); + +#endif /* _XILINX_EMAC_*/ Index: c/src/libchip/network/README.xilemac =================================================================== --- c/src/libchip/network/README.xilemac (.../rtems/rtems-4.6.5) (revision 0) +++ c/src/libchip/network/README.xilemac (.../volkano/rtems/rtems-src) (revision 1691) @@ -0,0 +1,22 @@ +Driver for xilinx opb ethernet MAC - README +------------------------------------------- + +This is a driver for the xilinx opb ethernet mac 1.02a + +The vhdl ip core was compiled with the default settings plus the following +overrides: + +C_DMA_PRESENT 3 +C_IPIF_RDFIFO_DEPTH 32768 +C_IPIF_WRFIFO_DEPTH 32768 +C_OPB_CLK_PERIOD_PS 10000 + +Although DMA is present in the ip core described above, this version of the +driver does not utilise it and functions through coping to and from the tx and +rx fifos. + +For an example of how to connect this driver into a bsp see: +c/src/lib/libbsp/powerpc/gen405/include/bsp.h and +c/src/lib/libbsp/powerpc/gen405/network/network.c + + Index: c/src/libchip/network/Makefile.am =================================================================== --- c/src/libchip/network/Makefile.am (.../rtems/rtems-4.6.5) (revision 1691) +++ c/src/libchip/network/Makefile.am (.../volkano/rtems/rtems-src) (revision 1691) @@ -9,11 +9,11 @@ LIB = $(ARCH)/$(LIBNAME).a C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c elnk.c open_eth.c \ - smc91111.c + smc91111.c xilemac.c OBJS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h if_media.h \ - mii.h open_eth.h smc91111.h smc91111exp.h + mii.h open_eth.h smc91111.h smc91111exp.h xilemac.h include $(top_srcdir)/../../../automake/compile.am include $(top_srcdir)/../../../automake/lib.am @@ -51,6 +51,6 @@ EXTRA_DIST = README README.cs8900 README.dec21140 README.i82586 \ README.open_eth README.sonic cs8900.c cs8900.c.bsp dec21140.c \ i82586.c if_fxp.c open_eth.c sonic.c \ - smc91111.c + smc91111.c xilemac.c include $(top_srcdir)/../../../automake/local.am