From df49c60c9671e4a28e636964d744c1f59fb6cb68 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Mon, 12 Jun 2000 15:00:15 +0000 Subject: Merged from 4.5.0-beta3a --- c/src/lib/libbsp/m68k/mvme167/Makefile.am | 7 +- c/src/lib/libbsp/m68k/mvme167/README | 106 +- c/src/lib/libbsp/m68k/mvme167/bsp_specs | 8 +- c/src/lib/libbsp/m68k/mvme167/clock/Makefile.am | 4 +- c/src/lib/libbsp/m68k/mvme167/configure.in | 4 + c/src/lib/libbsp/m68k/mvme167/console/Makefile.am | 4 +- .../m68k/mvme167/console/console-recording.c | 591 +++ c/src/lib/libbsp/m68k/mvme167/console/console.c | 522 ++- c/src/lib/libbsp/m68k/mvme167/fatal/Makefile.am | 4 +- c/src/lib/libbsp/m68k/mvme167/include/Makefile.am | 6 +- c/src/lib/libbsp/m68k/mvme167/include/bsp.h | 40 +- c/src/lib/libbsp/m68k/mvme167/network/Makefile.am | 6 +- c/src/lib/libbsp/m68k/mvme167/network/network.c | 4659 ++++++++++---------- c/src/lib/libbsp/m68k/mvme167/network/uti596.h | 297 +- c/src/lib/libbsp/m68k/mvme167/start/Makefile.am | 4 +- c/src/lib/libbsp/m68k/mvme167/startup/Makefile.am | 13 +- c/src/lib/libbsp/m68k/mvme167/startup/bspstart.c | 29 +- c/src/lib/libbsp/m68k/mvme167/startup/linkcmds | 227 +- c/src/lib/libbsp/m68k/mvme167/startup/page_table.c | 2 +- c/src/lib/libbsp/m68k/mvme167/timer/Makefile.am | 4 +- c/src/lib/libbsp/m68k/mvme167/wrapup/Makefile.am | 14 +- 21 files changed, 3859 insertions(+), 2692 deletions(-) (limited to 'c/src/lib/libbsp/m68k/mvme167') diff --git a/c/src/lib/libbsp/m68k/mvme167/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/Makefile.am index 070a8cafeb..5e3a858d5c 100644 --- a/c/src/lib/libbsp/m68k/mvme167/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/Makefile.am @@ -1,13 +1,14 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 ACLOCAL_AMFLAGS = -I $(RTEMS_TOPdir)/aclocal # wrapup is the one that actually builds and installs the library # from the individual .rel files built in other directories -SUBDIRS = . include start startup clock console fatal timer wrapup + +SUBDIRS = . include start startup clock console fatal timer network wrapup include $(top_srcdir)/../../bsp.am diff --git a/c/src/lib/libbsp/m68k/mvme167/README b/c/src/lib/libbsp/m68k/mvme167/README index aa7e4291ae..dc72a6fc48 100644 --- a/c/src/lib/libbsp/m68k/mvme167/README +++ b/c/src/lib/libbsp/m68k/mvme167/README @@ -2,18 +2,35 @@ # $Id$ # -This is a README file for the MVME167 port of RTEMS 4.0.0. +This is a README file for the MVME167 port of RTEMS 4.5.0. Please send any comments, improvements, or bug reports to: Charles-Antoine Gauthier +charles.gauthier@nrc.ca +or + +Darlene Stewart +Darlene.Stewart@nrc.ca + Software Engineering Group Institute for Information Technology National Research Council of Canada Ottawa, ON, K1A 0R6 Canada -charles.gauthier@iit.nrc.ca + +WARNING: +-------- + +The network driver is currently being worked on. It is somewhat functional, +but it does run out of buffers under certain conditions. The code is +also undergoing a substantial reorganization. Before making any changes, +you should check with us for the availability of updates. + +Note from Joel: The ttcp performance reported is very nice even if the +driver is still early in its life. :) + Disclaimer @@ -43,15 +60,15 @@ Installation Nothing unique to the MVME167. It uses the standard build process for m68k targets. You will need to edit linkcmds to put in the start address of your board. We do TFTP transfers to our target. The mvme167.cfg file -builds only the coff images, which we download to the target, skipping over -the first 0xA8 bytes; Motorola S-records are not generated. Edit this file -if you want S-records. +builds only the ELF images, which we download to the target, skipping +over the first 0x54 bytes; Motorola S-records are not generated. Edit +this file if you want S-records. Port Description Console driver ----------------- +--------------- This BSP includes an termios-capable console driver that supports all four serial ports on the MVME167 model. The RTEMS console, /dev/console, @@ -60,27 +77,30 @@ corresponds to channel 1 in the CD2401. This corresponds to Serial Port do not open /dev/tty00 if you are debugging using 167Bug. The console is initialized with whatever parameters are set up in termios -before it calls the firtOpen driver callback, EXCEPT THAT HARDWARE HANDSHAKING -IS TURNED OFF, i.e. CLOCAL is set in the struct termios c_cflag field. We use -3-wire cables for I/O, and find hardware handshaking a pain. If you enable -hardware handshaking, you must drive CTS* low on the CD2401 for output to -occur. If the port is in the DTE configuration, you must drive the RS-232 CTS -line to space; if the port is in the DCE configuration, you must drive the -RS-232 RTS line to space. - -Limited support is provided for polled terminal I/O. This is used when running -the timing tests. Set the CD2401_POLLED_IO manifest constant to 1 in -rtems/c/src/lib/libbsp/m68k/mvme167/console/console.c to enable polled I/O. -In this case, I/O is done through 167Bug, usually to the Serial Port 1/Console +before it calls the firtOpen driver callback, EXCEPT THAT HARDWARE +HANDSHAKING IS TURNED OFF, i.e. CLOCAL is set in the struct termios +c_cflag field. We use 3-wire cables for I/O, and find hardware handshaking +a pain. If you enable hardware handshaking, you must drive CTS* low on the +CD2401 for output to occur. If the port is in the DTE configuration, you +must drive the RS-232 CTS line to space; if the port is in the DCE +configuration, you must drive the RS-232 RTS line to space. + +Limited support is provided for polled terminal I/O. This is used when +running the timing tests. Set the CD2401_POLLED_IO manifest constant to 1 +in rtems/c/src/lib/libbsp/m68k/mvme167/console/console.c to enable polled +I/O. In this case, I/O is done through 167Bug, usually to the Serial Port +1/Console port. Interrupt-driven and polled I/O cannot be mixed in the +MVME167. + Floating-point The MC68040 has a built-in FPU. This FPU does not implement all the -instruction of the MC68881/MC68882 floating-point coprocessors in hardware. -The -m68040 compilation options instructs gcc to not generate the missing -instructions. All of the RTEMS code is built this way. Some of the missing -functionality must be supplied by external libraries. The required functions -are part of libgcc.a. +instruction of the MC68881/MC68882 floating-point coprocessors in +hardware. The -m68040 compilation options instructs gcc to not generate +the missing instructions. All of the RTEMS code is built this way. Some +of the missing functionality must be supplied by external libraries. The +required functions are part of libgcc.a. The issue gets complicated because libc, libm and libgcc do not come as m68040-specific variants. The default variants of these libraries are for the @@ -127,9 +147,22 @@ mvme167.cfg that redefine which variants of libc, libm and libgcc to link against. -Miscellaneous +Cache Control and Memory Mapping + +If Jumper J1-7 is installed, the data cache will be turned on. If Jumper +J1-6 is installed, the instruction cache will be turned on. Removing the +jumper causes the corresponding cache to be left disabled. + +If Jumper J1-5 is installed, the data cache will be placed in copyback +mode. If it is removed, it will be placed in writethrough mode. + +Currently, block address translation is set up to map the virtual +0x00000000--0x7FFFFFFF to the physical range 0x00000000--0x7FFFFFFF. The +port relies on the hardware to raise exceptions when addressing +non-existent memory. Caching is not controllable on a finer grain. + -port. Interrupt-driven and polled I/O cannot be mixed in the MVME167. +Miscellaneous The timer and clock drivers were patterned after the MVME162 and MVME152 ports. @@ -137,8 +170,6 @@ ports. At this time, we do not have an MPCI layer for the MVME167. We are planning to write one. -The port does not have a network driver. - This port supplies its own fatal_error_handler, which attempts to print some error message through 167Bug (on the Serial Port 1/Console on the MVME712M). @@ -153,17 +184,20 @@ tools were used: m68k-rtems target; - GNU binutils 2.9.1 configured for a powerpc-ibm-aix4.2.0.0 host and m68k-rtems target; + It was also tested on a Pentium II-based PC running Windows NT Workstation 4.0 -and the Cygnus Cygwin32 release b20.1 environment, witht he following tools: +and the Cygnus Cygwin32 release b20.1 environment, with the following tools: - EGCS 1.1.1 configured for a i586-cygwin32 host and m68k-rtems target; - GNU binutils 2.9.4 configured for a i586-cygwin32 host and m68k-rtems target; - - Cygnus newlib 1.8.0 with RTEMS 4.0.0 patches. With the latter environment, be patient; builds take a very looong time... - - Cygnus newlib 1.8.0 with RTEMS 4.0.0 patches. +Current development is done on a Pentium III PC running RedHat Linux 6.1. +At the time this README was composed, the latest working compiler that was +used successfully was gcc version 2.96 20000213 (experimental). Both the C +and C++ compilers were working. Binutils 2.9.1 are used. Known Problems @@ -202,6 +236,11 @@ blown. This is one case were overwritting the first or last 16 bytes of the stack does cause problems (but hey, an exception occurred, which is better than propagating the error). +In the stackchk test, an access fault exception is raised after the stack is +blown. This is one case were overwritting the first or last 16 bytes of the +stack does cause problems (but hey, an exception occurred, which is better +than propagating the error). + When using interrupt-driven I/O, psx08 produces all the expected output, but it does not return control to 167Bug. Is this test supposed to work with interrupt-driven console I/O? @@ -210,6 +249,8 @@ interrupt-driven console I/O? What's new ---------- +Support for Java is being actively worked on. + Thanks ------ @@ -460,8 +501,3 @@ Timing tests: rtems_rate_monotonic_period: obtain status 13 -Network tests: - Network driver is not implemented. - - - diff --git a/c/src/lib/libbsp/m68k/mvme167/bsp_specs b/c/src/lib/libbsp/m68k/mvme167/bsp_specs index 7ece396fb5..efee788065 100644 --- a/c/src/lib/libbsp/m68k/mvme167/bsp_specs +++ b/c/src/lib/libbsp/m68k/mvme167/bsp_specs @@ -7,15 +7,11 @@ *cpp: %(old_cpp) %{qrtems: -D__embedded__} -Asystem(embedded) -*endfile: -%{qelf: crtend.o%s crtn.o%s} - *lib: %{!qrtems: %(old_lib)} %{qrtems: --start-group \ %{!qrtems_debug: -lrtemsall} %{qrtems_debug: -lrtemsall_g} \ --lc -lgcc --end-group \ -%{!qelf: %{!qnolinkcmds: -T linkcmds%s}} %{qelf: %{!qnolinkcmd: -T -linkcmds%s}}} +%{qjava: -lffi -lzgcj -lgcj} %{qc++: -lstdc++} -lc -lgcc --end-group \ +%{!qnolinkcmds: -T linkcmds%s}} *startfile: %{!qrtems: %(old_startfile)} %{qrtems: \ diff --git a/c/src/lib/libbsp/m68k/mvme167/clock/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/clock/Makefile.am index 0b1ebe8a61..3e08045c00 100644 --- a/c/src/lib/libbsp/m68k/mvme167/clock/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/clock/Makefile.am @@ -1,6 +1,6 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 diff --git a/c/src/lib/libbsp/m68k/mvme167/configure.in b/c/src/lib/libbsp/m68k/mvme167/configure.in index 02052ba27e..3dd0750943 100644 --- a/c/src/lib/libbsp/m68k/mvme167/configure.in +++ b/c/src/lib/libbsp/m68k/mvme167/configure.in @@ -17,8 +17,11 @@ RTEMS_CANONICALIZE_TOOLS RTEMS_ENV_RTEMSBSP RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP) RTEMS_CHECK_BSP_CACHE(RTEMS_BSP) +RTEMS_CHECK_NETWORKING RTEMS_CANONICAL_HOST +AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes") + RTEMS_PROJECT_ROOT # Explicitly list all Makefiles here @@ -28,6 +31,7 @@ clock/Makefile console/Makefile fatal/Makefile include/Makefile +network/Makefile start/Makefile startup/Makefile timer/Makefile diff --git a/c/src/lib/libbsp/m68k/mvme167/console/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/console/Makefile.am index 82b58ef82e..d4e5619fac 100644 --- a/c/src/lib/libbsp/m68k/mvme167/console/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/console/Makefile.am @@ -1,6 +1,6 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 diff --git a/c/src/lib/libbsp/m68k/mvme167/console/console-recording.c b/c/src/lib/libbsp/m68k/mvme167/console/console-recording.c index e69de29bb2..1f216a07d5 100644 --- a/c/src/lib/libbsp/m68k/mvme167/console/console-recording.c +++ b/c/src/lib/libbsp/m68k/mvme167/console/console-recording.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2000, National Research Council of Canada + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + */ + +/* CD2401 CONSOLE DRIVER DEBUG INFO RECORDING */ + +#ifdef CD2401_RECORD_DEBUG_INFO + +/* Control individual recording here. That way, we don't clutter console.c */ +#define CD2401_RECORD_WRITE +#define CD2401_RECORD_TX_ISR +#define CD2401_RECORD_RX_ISR +#define CD2401_RECORD_RE_ISR +#define CD2401_RECORD_MODEM_ISR +#define CD2401_RECORD_SET_ATTRIBUTE +#define CD2401_RECORD_FIRST_OPEN +#define CD2401_RECORD_LAST_CLOSE +#define CD2401_RECORD_START_REMOTE_TX +#define CD2401_RECORD_STOP_REMOTE_TX +#define CD2401_RECORD_DRAIN_OUTPUT +#define CD2401_RECORD_DELAY + + +/* Call the data recording functions */ +#ifdef CD2401_RECORD_WRITE +#define CD2401_RECORD_WRITE_INFO( args ) cd2401_record_write_info args +#else +#define CD2401_RECORD_WRITE_INFO( args ) +#endif + +#ifdef CD2401_RECORD_TX_ISR +#define CD2401_RECORD_TX_ISR_INFO( args ) cd2401_record_tx_isr_info args +#define CD2401_RECORD_TX_ISR_SPURIOUS_INFO( args ) cd2401_record_tx_isr_spurious_info args +#define CD2401_RECORD_TX_ISR_BUSERR_INFO( args ) cd2401_record_tx_isr_buserr_info args +#else +#define CD2401_RECORD_TX_ISR_INFO( args ) +#define CD2401_RECORD_TX_ISR_SPURIOUS_INFO( args ) +#define CD2401_RECORD_TX_ISR_BUSERR_INFO( args ) +#endif + +#ifdef CD2401_RECORD_RX_ISR +#define CD2401_RECORD_RX_ISR_INFO( args ) cd2401_record_rx_isr_info args +#define CD2401_RECORD_RX_ISR_SPURIOUS_INFO( args ) cd2401_record_rx_isr_spurious_info args +#else +#define CD2401_RECORD_RX_ISR_INFO( args ) +#define CD2401_RECORD_RX_ISR_SPURIOUS_INFO( args ) +#endif + +#ifdef CD2401_RECORD_RE_ISR +#define CD2401_RECORD_RE_ISR_SPURIOUS_INFO( args ) cd2401_record_re_isr_spurious_info args +#else +#define CD2401_RECORD_RE_ISR_SPURIOUS_INFO( args ) +#endif + +#ifdef CD2401_RECORD_MODEM_ISR +#define CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO( args ) cd2401_record_modem_isr_spurious_info args +#else +#define CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO( args ) +#endif + +#ifdef CD2401_RECORD_SET_ATTRIBUTES +#define CD2401_RECORD_SET_ATTRIBUTES_INFO( args ) cd2401_record_set_attributes_info args +#else +#define CD2401_RECORD_SET_ATTRIBUTES_INFO( args ) +#endif + +#ifdef CD2401_RECORD_FIRST_OPEN +#define CD2401_RECORD_FIRST_OPEN_INFO( args ) cd2401_record_first_open_info args +#else +#define CD2401_RECORD_FIRST_OPEN_INFO( args ) +#endif + +#ifdef CD2401_RECORD_LAST_CLOSE +#define CD2401_RECORD_LAST_CLOSE_INFO( args ) cd2401_record_last_close_info args +#else +#define CD2401_RECORD_LAST_CLOSE_INFO( args ) +#endif + +#ifdef CD2401_RECORD_START_REMOTE_TX +#define CD2401_RECORD_START_REMOTE_TX_INFO( args ) cd2401_record_start_remote_tx_info args +#else +#define CD2401_RECORD_START_REMOTE_TX_INFO( args ) +#endif + +#ifdef CD2401_RECORD_STOP_REMOTE_TX +#define CD2401_RECORD_STOP_REMOTE_TX_INFO( args ) cd2401_record_stop_remote_tx_info args +#else +#define CD2401_RECORD_STOP_REMOTE_TX_INFO( args ) +#endif + +#ifdef CD2401_RECORD_DRAIN_OUTPUT +#define CD2401_RECORD_DRAIN_OUTPUT_INFO( args ) cd2401_record_drain_output_info args +#else +#define CD2401_RECORD_DRAIN_OUTPUT_INFO( args ) +#endif + +#ifdef CD2401_RECORD_DELAY +#define CD2401_RECORD_DELAY_INFO( args ) cd2401_record_delay_info args +#else +#define CD2401_RECORD_DELAY_INFO( args ) +#endif + + +/* Define the data and the recording functions */ +#define CD2401_DEBUG_BUFFER_SIZE 256 +#define CD2401_DEBUG_CHAR_BUFSIZE 64 +#define CD2401_WRITE_INFO 1 +#define CD2401_TX_ISR_INFO 2 +#define CD2401_TX_ISR_SPURIOUS_INFO 3 +#define CD2401_TX_ISR_BUSERR_INFO 4 +#define CD2401_RX_ISR_INFO 5 +#define CD2401_RX_ISR_SPURIOUS_INFO 6 +#define CD2401_RE_ISR_SPURIOUS_INFO 7 +#define CD2401_MODEM_ISR_SPURIOUS_INFO 8 +#define CD2401_FIRST_OPEN_INFO 9 +#define CD2401_LAST_CLOSE_INFO 10 +#define CD2401_START_REMOTE_TX_INFO 11 +#define CD2401_STOP_REMOTE_TX_INFO 12 +#define CD2401_SET_ATTRIBUTE_INFO 13 +#define CD2401_DRAIN_OUTPUT_INFO 14 +#define CD2401_DELAY_INFO 15 + + +struct cd2401_debug_info { + short discriminant; + short record_size; + union { + struct cd2401_write_info { + int length; + char buffer[CD2401_DEBUG_CHAR_BUFSIZE]; + char dmabuf; + } write_info; + struct cd2401_tx_isr_info { + unsigned char channel; + unsigned char status; + unsigned char initial_ier; + unsigned char final_ier; + rtems_unsigned8 txEmpty; + } tx_isr_info; + struct cd2401_tx_isr_spurious_info { + unsigned char channel; + unsigned char status; + unsigned char initial_ier; + unsigned char final_ier; + unsigned long spurdev; + unsigned long spurcount; + } tx_isr_spurious_info; + struct cd2401_tx_isr_buserr_info { + unsigned char channel; + unsigned char status; + unsigned char initial_ier; + unsigned char buserr; + unsigned long type; + unsigned long addr; + } tx_isr_buserr_info; + struct cd2401_rx_isr_info { + unsigned char channel; + int length; + char buffer[CD2401_DEBUG_CHAR_BUFSIZE]; + } rx_isr_info; + struct cd2401_rx_isr_spurious_info { + unsigned char channel; + unsigned char status; + unsigned long spurdev; + unsigned long spurcount; + } rx_isr_spurious_info; + struct cd2401_re_isr_spurious_info { + unsigned char channel; + unsigned long spurdev; + unsigned long spurcount; + } re_isr_spurious_info; + struct cd2401_modem_isr_spurious_info { + unsigned char channel; + unsigned long spurdev; + unsigned long spurcount; + } modem_isr_spurious_info; + struct cd2401_first_open_info { + unsigned char channel; + rtems_unsigned8 init_count; + } first_open_info; + struct cd2401_last_close_info { + unsigned char channel; + rtems_unsigned8 init_count; + } last_close_info; + struct cd2401_start_remote_tx_info { + unsigned char channel; + } start_remote_tx_info; + struct cd2401_stop_remote_tx_info { + unsigned char channel; + } stop_remote_tx_info; + struct cd2401_set_attribute_info { + int minor; + rtems_unsigned8 need_reinit; + rtems_unsigned8 txEmpty; + rtems_unsigned8 csize; + rtems_unsigned8 cstopb; + rtems_unsigned8 parodd; + rtems_unsigned8 parenb; + rtems_unsigned8 ignpar; + rtems_unsigned8 inpck; + rtems_unsigned8 hw_flow_ctl; + rtems_unsigned8 sw_flow_ctl; + rtems_unsigned8 extra_flow_ctl; + rtems_unsigned8 icrnl; + rtems_unsigned8 igncr; + rtems_unsigned8 inlcr; + rtems_unsigned8 brkint; + rtems_unsigned8 ignbrk; + rtems_unsigned8 parmrk; + rtems_unsigned8 istrip; + rtems_unsigned16 tx_period; + rtems_unsigned16 rx_period; + rtems_unsigned32 out_baud; + rtems_unsigned32 in_baud; + } set_attribute_info; + struct cd2401_drain_output_info { + rtems_unsigned8 txEmpty; + rtems_unsigned8 own_buf_A; + rtems_unsigned8 own_buf_B; + } drain_output_info; + struct cd2401_delay_info { + rtems_interval start; + rtems_interval end; + rtems_interval current; + unsigned long loop_count; + } delay_info; + } u; +}; + +struct cd2401_debug_info cd2401_debug_buffer[CD2401_DEBUG_BUFFER_SIZE]; +int cd2401_debug_index = 0; + +#include + +int cd2401_get_record_size( + int size +) +{ + /* Not the best way to do this */ + return size + 4; +} + + +void cd2401_record_write_info( + int len, + const char * buf, + char dmabuf +) +{ + int max_length; + + max_length = (len < CD2401_DEBUG_CHAR_BUFSIZE ) ? len : CD2401_DEBUG_CHAR_BUFSIZE; + + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_WRITE_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_write_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.write_info.length = len; + memcpy ( &(cd2401_debug_buffer[cd2401_debug_index].u.write_info.buffer), buf, max_length ); + cd2401_debug_buffer[cd2401_debug_index].u.write_info.dmabuf = dmabuf; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_tx_isr_info( + unsigned char ch, + unsigned char status, + unsigned char initial_ier, + unsigned char final_ier, + rtems_unsigned8 txEmpty +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_TX_ISR_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_tx_isr_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.status = status; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.initial_ier = initial_ier; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.final_ier = final_ier; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.txEmpty = txEmpty; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_tx_isr_spurious_info( + unsigned char ch, + unsigned char status, + unsigned char initial_ier, + unsigned char final_ier, + unsigned char spur_dev, + unsigned char spur_cnt +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_TX_ISR_SPURIOUS_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_tx_isr_spurious_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.status = status; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.initial_ier = initial_ier; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.final_ier = final_ier; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.spurdev = spur_dev; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.spurcount = spur_cnt; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_tx_isr_buserr_info( + unsigned char ch, + unsigned char status, + unsigned char initial_ier, + unsigned char buserr, + unsigned long buserr_type, + unsigned long buserr_addr +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_TX_ISR_BUSERR_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_tx_isr_buserr_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.status = status; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.initial_ier = initial_ier; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.buserr = buserr; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.type = buserr_type; + cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.addr = buserr_addr; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_rx_isr_info( + unsigned char ch, + unsigned char total, + char * buffer +) +{ + int max_length; + + max_length = (total < CD2401_DEBUG_CHAR_BUFSIZE ) ? total : CD2401_DEBUG_CHAR_BUFSIZE; + + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_RX_ISR_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_rx_isr_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_info.length = max_length; + memcpy ( &(cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_info.buffer), buffer, max_length ); + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_rx_isr_spurious_info( + unsigned char ch, + unsigned char status, + rtems_unsigned32 spur_dev, + rtems_unsigned32 spur_cnt +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_RX_ISR_SPURIOUS_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_rx_isr_spurious_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.status = status; + cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.spurdev = spur_dev; + cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.spurcount = spur_cnt; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_re_isr_spurious_info( + unsigned char ch, + rtems_unsigned32 spur_dev, + rtems_unsigned32 spur_cnt +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_RE_ISR_SPURIOUS_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_re_isr_spurious_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.re_isr_spurious_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.re_isr_spurious_info.spurdev = spur_dev; + cd2401_debug_buffer[cd2401_debug_index].u.re_isr_spurious_info.spurcount = spur_cnt; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_modem_isr_spurious_info( + unsigned char ch, + rtems_unsigned32 spur_dev, + rtems_unsigned32 spur_cnt +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_MODEM_ISR_SPURIOUS_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_modem_isr_spurious_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.modem_isr_spurious_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.modem_isr_spurious_info.spurdev = spur_dev; + cd2401_debug_buffer[cd2401_debug_index].u.modem_isr_spurious_info.spurcount = spur_cnt; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_first_open_info( + unsigned char ch, + rtems_unsigned8 init_count +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_FIRST_OPEN_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_first_open_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.first_open_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.first_open_info.init_count = init_count; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_last_close_info( + unsigned char ch, + rtems_unsigned8 init_count +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_LAST_CLOSE_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_last_close_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.last_close_info.channel = ch; + cd2401_debug_buffer[cd2401_debug_index].u.last_close_info.init_count = init_count; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_start_remote_tx_info( + unsigned char ch +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_START_REMOTE_TX_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_start_remote_tx_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.start_remote_tx_info.channel = ch; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_stop_remote_tx_info( + unsigned char ch +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_STOP_REMOTE_TX_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_stop_remote_tx_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.stop_remote_tx_info.channel = ch; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_set_attributes_info( + int minor, + rtems_unsigned8 need_reinit, + rtems_unsigned8 csize, + rtems_unsigned8 cstopb, + rtems_unsigned8 parodd, + rtems_unsigned8 parenb, + rtems_unsigned8 ignpar, + rtems_unsigned8 inpck, + rtems_unsigned8 hw_flow_ctl, + rtems_unsigned8 sw_flow_ctl, + rtems_unsigned8 extra_flow_ctl, + rtems_unsigned8 icrnl, + rtems_unsigned8 igncr, + rtems_unsigned8 inlcr, + rtems_unsigned8 brkint, + rtems_unsigned8 ignbrk, + rtems_unsigned8 parmrk, + rtems_unsigned8 istrip, + rtems_unsigned16 tx_period, + rtems_unsigned16 rx_period, + rtems_unsigned32 out_baud, + rtems_unsigned32 in_baud +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_SET_ATTRIBUTE_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_set_attribute_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.minor = minor; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.need_reinit = need_reinit; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.txEmpty = CD2401_Channel_Info[minor].txEmpty; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.csize = csize; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.cstopb = cstopb; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.parodd = parodd; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.parenb = parenb; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.ignpar = ignpar; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.inpck = inpck; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.hw_flow_ctl = hw_flow_ctl; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.sw_flow_ctl = sw_flow_ctl; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.extra_flow_ctl = extra_flow_ctl; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.icrnl = icrnl; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.igncr = igncr; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.inlcr = inlcr; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.brkint = brkint; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.ignbrk = ignbrk; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.parmrk = parmrk; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.istrip = istrip; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.tx_period = tx_period; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.rx_period = rx_period; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.out_baud = out_baud; + cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.in_baud = in_baud; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_drain_output_info( + rtems_unsigned8 txEmpty, + rtems_unsigned8 own_buf_A, + rtems_unsigned8 own_buf_B +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_DRAIN_OUTPUT_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_drain_output_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.drain_output_info.txEmpty = txEmpty; + cd2401_debug_buffer[cd2401_debug_index].u.drain_output_info.own_buf_A = own_buf_A; + cd2401_debug_buffer[cd2401_debug_index].u.drain_output_info.own_buf_B = own_buf_B; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +void cd2401_record_delay_info( + rtems_interval start, + rtems_interval end, + rtems_interval current, + unsigned long loop_count +) +{ + memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) ); + cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_DELAY_INFO; + cd2401_debug_buffer[cd2401_debug_index].record_size = + cd2401_get_record_size( sizeof( struct cd2401_delay_info ) ); + cd2401_debug_buffer[cd2401_debug_index].u.delay_info.start = start; + cd2401_debug_buffer[cd2401_debug_index].u.delay_info.end = end; + cd2401_debug_buffer[cd2401_debug_index].u.delay_info.current = current; + cd2401_debug_buffer[cd2401_debug_index].u.delay_info.loop_count = loop_count; + + cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE; +} + + +#else + +/* Do not call the data recording functions */ +#define CD2401_RECORD_WRITE_INFO( args ) +#define CD2401_RECORD_TX_ISR_INFO( args ) +#define CD2401_RECORD_TX_ISR_SPURIOUS_INFO( args ) +#define CD2401_RECORD_TX_ISR_BUSERR_INFO( args ) +#define CD2401_RECORD_RX_ISR_INFO( args ) +#define CD2401_RECORD_RX_ISR_SPURIOUS_INFO( args ) +#define CD2401_RECORD_RE_ISR_SPURIOUS_INFO( args ) +#define CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO( args ) +#define CD2401_RECORD_FIRST_OPEN_INFO( args ) +#define CD2401_RECORD_LAST_CLOSE_INFO( args ) +#define CD2401_RECORD_START_REMOTE_TX_INFO( args ) +#define CD2401_RECORD_STOP_REMOTE_TX_INFO( args ) +#define CD2401_RECORD_SET_ATTRIBUTES_INFO( args ) +#define CD2401_RECORD_DRAIN_OUTPUT_INFO( args ) +#define CD2401_RECORD_DELAY_INFO( args ) + +#endif diff --git a/c/src/lib/libbsp/m68k/mvme167/console/console.c b/c/src/lib/libbsp/m68k/mvme167/console/console.c index b1377aef38..a77e001da1 100644 --- a/c/src/lib/libbsp/m68k/mvme167/console/console.c +++ b/c/src/lib/libbsp/m68k/mvme167/console/console.c @@ -2,22 +2,24 @@ * console.c * * This file contains the MVME167 termios console package. Only asynchronous - * I/O is supported. Normal I/O uses DMA for output, interrupts for input. - * Very limited support is provided for polled I/O. Polled I/O is intended - * only for running the RTEMS test suites, and uses the 167Bug console only. + * I/O is supported. * * /dev/tty0 is channel 0, Serial Port 1/Console on the MVME712M. * /dev/tty1 is channel 1, Serial Port 2/TTY01 on the MVME712M. * /dev/tty2 is channel 2, Serial Port 3 on the MVME712M. * /dev/tty3 is channel 3, Serial Port 4 on the MVME712M. * - * /dev/console is fixed to be /dev/tty01, Serial Port 2. 167Bug is given - * Serial Port 1/Console. Do not open /dev/tty00. + * Normal I/O uses DMA for output, interrupts for input. /dev/console is + * fixed to be /dev/tty01, Serial Port 2. Very limited support is provided + * for polled I/O. Polled I/O is intended only for running the RTEMS test + * suites. In all cases, Serial Port 1/Console is allocated to 167Bug and + * is the dedicated debugger port. We configure GDB to use 167Bug for + * debugging. When debugging with GDB or 167Bug, do not open /dev/tty00. * * Modern I/O chips often contain a number of I/O devices that can operate * almost independently of each other. Typically, in RTEMS, all devices in * an I/O chip are handled by a single device driver, but that need not be - * always the case. Each device driver must supply six entry points in the + * always the case. Each device driver must supply six entry points in the * Device Driver Table: a device initialization function, as well as an open, * close, read, write and a control function. RTEMS assigns a device major * number to each device driver. This major device number is the index of the @@ -59,7 +61,7 @@ * Worse, it requires that the sub-devices be initialized in some * configuration, and that configuration then changed through a series of * device driver control calls. There is no standard API in RTEMS to switch - * a serial line to some synchronous protocol. + * a serial line to some synchronous protocol. * * A better approach is to treat each channel as a separate device, each with * its own device device driver. The application then supplies its own device @@ -96,7 +98,7 @@ * THIS MODULE IS NOT RE-ENTRANT! Simultaneous access to a device from * multiple tasks is likely to cause significant problems! Concurrency * control is implemented in the termios package. -* + * * THE INTERRUPT LEVEL IS SET TO 1 FOR ALL CHANNELS. * If the CD2401 is to be used for high speed synchronous serial I/O, the * interrupt priority might need to be increased. @@ -125,27 +127,25 @@ #define M167_INIT +#include +#include #include #include /* Must be before libio.h */ #include -#define CD2401_INT_LEVEL 1 /* Interrupt level for the CD2401 */ -#define CD2401_POLLED_IO 0 /* 0 for interrupt-driven, 1 for polled I/O */ - /* Channel info */ -/* static */ struct { +/* static */ volatile struct { void *tty; /* Really a struct rtems_termios_tty * */ int len; /* Record nb of chars being TX'ed */ const char *buf; /* Record where DMA is coming from */ - rtems_unsigned16 used_buf_A; /* Nb of times we used output DMA channel A */ - rtems_unsigned16 used_buf_B; /* Nb of times we used output DMA channel B */ - rtems_unsigned16 wait_buf_A; /* Nb of times we waited for output DMA channel A */ - rtems_unsigned16 wait_buf_B; /* Nb of times we waited for output DMA channel B */ rtems_unsigned32 spur_cnt; /* Nb of spurious ints so far */ rtems_unsigned32 spur_dev; /* Indo on last spurious int */ rtems_unsigned32 buserr_addr; /* Faulting address */ rtems_unsigned32 buserr_type; /* Reason of bus error during DMA */ + rtems_unsigned8 own_buf_A; /* If true, buffer A belongs to the driver */ + rtems_unsigned8 own_buf_B; /* If true, buffer B belongs to the driver */ + rtems_unsigned8 txEmpty; /* If true, the output FIFO is supposed to be empty */ } CD2401_Channel_Info[4]; /* @@ -166,7 +166,14 @@ rtems_isr_entry Prev_rx_isr; /* Previous rx isr */ rtems_isr_entry Prev_tx_isr; /* Previous tx isr */ rtems_isr_entry Prev_modem_isr; /* Previous modem/timer isr */ + +/* Define the following symbol to trace the calls to this driver */ +/* #define CD2401_RECORD_DEBUG_INFO */ +#include "console-recording.c" + + /* Utility functions */ +void cd2401_udelay( unsigned long delay ); void cd2401_chan_cmd( rtems_unsigned8 channel, rtems_unsigned8 cmd, rtems_unsigned8 wait ); rtems_unsigned16 cd2401_bitrate_divisor( rtems_unsigned32 clkrate, rtems_unsigned32* bitrate ); void cd2401_initialize( void ); @@ -185,6 +192,7 @@ int cd2401_setAttributes( int minor, const struct termios *t ); int cd2401_startRemoteTx( int minor ); int cd2401_stopRemoteTx( int minor ); int cd2401_write( int minor, const char *buf, int len ); +int cd2401_drainOutput( int minor ); int _167Bug_pollRead( int minor ); int _167Bug_pollWrite( int minor, const char *buf, int len ); @@ -193,6 +201,38 @@ int _167Bug_pollWrite( int minor, const char *buf, int len ); * Utility functions. */ +/* + * Assumes that clock ticks 1 million times per second. + * + * MAXIMUM DELAY IS ABOUT 20 ms + * + * Input parameters: + * delay: Number of microseconds to delay. + * + * Output parameters: NONE + * + * Return values: NONE + */ + void cd2401_udelay +( + unsigned long delay +) +{ + unsigned long i = 20000; /* In case clock is off */ + rtems_interval ticks_per_second, start_ticks, end_ticks, current_ticks; + + rtems_clock_get( RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second ); + rtems_clock_get( RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks ); + end_ticks = start_ticks + delay; + + do { + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, ¤t_ticks); + } while ( --i && (current_ticks <= end_ticks) ); + + CD2401_RECORD_DELAY_INFO(( start_ticks, end_ticks, current_ticks, i )); +} + + /* * cd2401_chan_cmd * @@ -288,21 +328,16 @@ void cd2401_initialize( void ) int i; for ( i = 3; i >= 0; i-- ) { - /* - * Paranoia -- Should already be blank because array should be in bss - * section, which is explicitly zeroed at boot time. - */ CD2401_Channel_Info[i].tty = NULL; CD2401_Channel_Info[i].len = 0; CD2401_Channel_Info[i].buf = NULL; - CD2401_Channel_Info[i].used_buf_A = 0; - CD2401_Channel_Info[i].used_buf_B = 0; - CD2401_Channel_Info[i].wait_buf_A = 0; - CD2401_Channel_Info[i].wait_buf_B = 0; CD2401_Channel_Info[i].spur_cnt = 0; CD2401_Channel_Info[i].spur_dev = 0; CD2401_Channel_Info[i].buserr_type = 0; CD2401_Channel_Info[i].buserr_addr = 0; + CD2401_Channel_Info[i].own_buf_A = TRUE; + CD2401_Channel_Info[i].own_buf_B = TRUE; + CD2401_Channel_Info[i].txEmpty = TRUE; } /* @@ -437,6 +472,9 @@ rtems_isr cd2401_modem_isr( CD2401_Channel_Info[ch].spur_cnt++; cd2401->meoir = 0; /* EOI */ + CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO(( ch, + CD2401_Channel_Info[ch].spur_dev, + CD2401_Channel_Info[ch].spur_cnt )); } @@ -472,6 +510,9 @@ rtems_isr cd2401_re_isr( if ( cd2401->u5.b.risrl & 0x80 ) /* Timeout interrupt? */ cd2401->ier &= 0xDF; /* Disable rx timeout interrupt */ cd2401->reoir = 0x08; /* EOI; exception char not read */ + CD2401_RECORD_RE_ISR_SPURIOUS_INFO(( ch, + CD2401_Channel_Info[ch].spur_dev, + CD2401_Channel_Info[ch].spur_cnt )); } @@ -492,28 +533,33 @@ rtems_isr cd2401_rx_isr( ) { char c; - rtems_unsigned8 ch, nchars; + rtems_unsigned8 ch, status, nchars, i, total; + char buffer[256]; + status = cd2401->u5.b.risrl; ch = cd2401->licr >> 2; - /* Has this channel been initialized? */ - if (CD2401_Channel_Info[ch].tty) { - /* Yes, read chars, enqueue them, and issue EOI */ - nchars = cd2401->rfoc; /* Number of chars to retrieve from rx FIFO */ + /* Has this channel been initialized or is it a condition we ignore? */ + if ( CD2401_Channel_Info[ch].tty && !status ) { + /* Normal Rx Int, read chars, enqueue them, and issue EOI */ + total = nchars = cd2401->rfoc; /* Nb of chars to retrieve from rx FIFO */ + i = 0; while ( nchars-- > 0 ) { - c = (char)cd2401->dr; /* Next char in rx FIFO */ - rtems_termios_enqueue_raw_characters ( - CD2401_Channel_Info[ch].tty, - &c, - 1 ); + c = (char)cd2401->dr; /* Next char in rx FIFO */ + rtems_termios_enqueue_raw_characters( CD2401_Channel_Info[ch].tty ,&c, 1 ); + buffer[i++] = c; } - cd2401->reoir = 0; /* EOI */ + cd2401->reoir = 0; /* EOI */ + CD2401_RECORD_RX_ISR_INFO(( ch, total, buffer )); } else { /* No, record as spurious interrupt */ CD2401_Channel_Info[ch].spur_dev = (vector << 24) | (cd2401->stk << 16) | (cd2401->rir << 8) | cd2401->u5.b.risrl; CD2401_Channel_Info[ch].spur_cnt++; - cd2401->reoir = 0x04; /* EOI - character not read */ + cd2401->reoir = 0x04; /* EOI - character not read */ + CD2401_RECORD_RX_ISR_SPURIOUS_INFO(( ch, status, + CD2401_Channel_Info[ch].spur_dev, + CD2401_Channel_Info[ch].spur_cnt )); } } @@ -534,10 +580,11 @@ rtems_isr cd2401_tx_isr( rtems_vector_number vector ) { - rtems_unsigned8 ch, status, buserr; + rtems_unsigned8 ch, status, buserr, initial_ier, final_ier; status = cd2401->tisr; ch = cd2401->licr >> 2; + initial_ier = cd2401->ier; /* Has this channel been initialized? */ if ( !CD2401_Channel_Info[ch].tty ) { @@ -545,8 +592,11 @@ rtems_isr cd2401_tx_isr( CD2401_Channel_Info[ch].spur_dev = (vector << 24) | (cd2401->stk << 16) | (cd2401->tir << 8) | cd2401->tisr; CD2401_Channel_Info[ch].spur_cnt++; - cd2401->ier &= 0xFC; /* Shut up, whoever you are */ - cd2401->teoir = 0x88; /* EOI - Terminate buffer and no transfer */ + final_ier = cd2401->ier &= 0xFC;/* Shut up, whoever you are */ + cd2401->teoir = 0x88; /* EOI - Terminate buffer and no transfer */ + CD2401_RECORD_TX_ISR_SPURIOUS_INFO(( ch, status, initial_ier, final_ier, + CD2401_Channel_Info[ch].spur_dev, + CD2401_Channel_Info[ch].spur_cnt )); return; } @@ -562,26 +612,50 @@ rtems_isr cd2401_tx_isr( CD2401_Channel_Info[ch].buserr_addr = (((rtems_unsigned32)cd2401->tcbadru) << 16) | cd2401->tcbadrl; - cd2401->teoir = 0x80; /* EOI - terminate bad buffer */ + cd2401->teoir = 0x80; /* EOI - terminate bad buffer */ + CD2401_RECORD_TX_ISR_BUSERR_INFO(( ch, status, initial_ier, buserr, + CD2401_Channel_Info[ch].buserr_type, + CD2401_Channel_Info[ch].buserr_addr )); return; } if ( status & 0x20 ) { - /* DMA done */ - cd2401->ier &= 0xFC; /* Shut up the interrupts */ - + /* DMA done -- Turn off TxD int, turn on TxMpty */ + final_ier = cd2401->ier = (cd2401->ier & 0xFE) | 0x02; + if( status & 0x08 ) { + /* Transmit buffer B was released */ + CD2401_Channel_Info[ch].own_buf_B = TRUE; + } + else { + /* Transmit buffer A was released */ + CD2401_Channel_Info[ch].own_buf_A = TRUE; + } + CD2401_RECORD_TX_ISR_INFO(( ch, status, initial_ier, final_ier, + CD2401_Channel_Info[ch].txEmpty )); + /* This call can result in a call to cd2401_write() */ rtems_termios_dequeue_characters ( CD2401_Channel_Info[ch].tty, CD2401_Channel_Info[ch].len ); - cd2401->teoir = 0x08; /* EOI - no data transfered */ + cd2401->teoir = 0x08; /* EOI - no data transfered */ + } + else if ( status & 0x02 ) { + /* TxEmpty */ + CD2401_Channel_Info[ch].txEmpty = TRUE; + final_ier = cd2401->ier &= 0xFD;/* Shut up the interrupts */ + cd2401->teoir = 0x08; /* EOI - no data transfered */ + CD2401_RECORD_TX_ISR_INFO(( ch, status, initial_ier, final_ier, + CD2401_Channel_Info[ch].txEmpty )); } else { /* Why did we get a Tx interrupt? */ CD2401_Channel_Info[ch].spur_dev = (vector << 24) | (cd2401->stk << 16) | (cd2401->tir << 8) | cd2401->tisr; CD2401_Channel_Info[ch].spur_cnt++; - cd2401->teoir = 0x08; /* EOI - no data transfered */ + cd2401->teoir = 0x08; /* EOI - no data transfered */ + CD2401_RECORD_TX_ISR_SPURIOUS_INFO(( ch, status, initial_ier, 0xFF, + CD2401_Channel_Info[ch].spur_dev, + CD2401_Channel_Info[ch].spur_cnt )); } } @@ -615,6 +689,9 @@ int cd2401_firstOpen( rtems_libio_ioctl_args_t newarg; struct termios termios; rtems_status_code sc; + rtems_interrupt_level level; + + rtems_interrupt_disable (level); /* * Set up the line with the specified parameters. The difficulty is that @@ -634,7 +711,7 @@ int cd2401_firstOpen( sc = rtems_termios_ioctl (&newarg); if (sc != RTEMS_SUCCESSFUL) rtems_fatal_error_occurred (sc); - + /* * Turn off hardware flow control. It is a pain with 3-wire cables. * The rtems_termios_ioctl() call below results in a call to @@ -646,7 +723,7 @@ int cd2401_firstOpen( sc = rtems_termios_ioctl (&newarg); if (sc != RTEMS_SUCCESSFUL) rtems_fatal_error_occurred (sc); - + /* Mark that the channel as initialized */ CD2401_Channel_Info[minor].tty = args->iop->data1; @@ -661,6 +738,10 @@ int cd2401_firstOpen( cd2401_interrupts_initialize( TRUE ); } + CD2401_RECORD_FIRST_OPEN_INFO(( minor, Init_count )); + + rtems_interrupt_enable (level); + /* Return something */ return RTEMS_SUCCESSFUL; } @@ -682,6 +763,10 @@ int cd2401_lastClose( void *arg ) { + rtems_interrupt_level level; + + rtems_interrupt_disable (level); + /* Mark that the channel is no longer is use */ CD2401_Channel_Info[minor].tty = NULL; @@ -696,6 +781,10 @@ int cd2401_lastClose( set_vector( Prev_rx_isr, 0x5F, 1 ); } + CD2401_RECORD_LAST_CLOSE_INFO(( minor, Init_count )); + + rtems_interrupt_enable (level); + /* return something */ return RTEMS_SUCCESSFUL; } @@ -729,10 +818,13 @@ int cd2401_setAttributes( rtems_unsigned8 csize, cstopb, parodd, parenb, ignpar, inpck; rtems_unsigned8 hw_flow_ctl, sw_flow_ctl, extra_flow_ctl; rtems_unsigned8 icrnl, igncr, inlcr, brkint, ignbrk, parmrk, istrip; + rtems_unsigned8 need_reinitialization = FALSE; + rtems_unsigned8 read_enabled; rtems_unsigned16 tx_period, rx_period; rtems_unsigned32 out_baud, in_baud; + rtems_interrupt_level level; - /* Set up the line parameters */ + /* Determine what the line parameters should be */ /* Output baud rate */ switch ( cfgetospeed (t) ) { @@ -876,48 +968,110 @@ int cd2401_setAttributes( else istrip = 0; /* Leave as 8 bits */ - - /* Clear channel and disable rx and tx */ - cd2401_chan_cmd (minor, 0x40, 1); - - /* Write to the ports */ - cd2401->car = minor; /* Select channel */ - cd2401->cmr = 0x42; /* Interrupt Rx, DMA Tx, async mode */ - cd2401->cor1 = parodd | parenb | ignpar | csize; - cd2401->cor2 = sw_flow_ctl | hw_flow_ctl; - cd2401->cor3 = extra_flow_ctl | cstopb; - cd2401->cor4 = 0x0A; /* No DSR/DCD/CTS detect; FIFO threshold of 10 */ - cd2401->cor5 = 0x0A; /* No DSR/DCD/CTS detect; DTR threshold of 10 */ - cd2401->cor6 = igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck; - cd2401->cor7 = istrip; /* No LNext; ignore XON/XOFF if frame error; no tx translations */ - cd2401->u1.async.schr1 = - t->c_cc[VSTART]; /* Special char 1: XON character */ - cd2401->u1.async.schr2 = - t->c_cc[VSTOP]; /* special char 2: XOFF character */ - /* Special chars 3 and 4, char range, LNext, RFAR[1..4] and CRC are unused, left as is. */ - - /* Set baudrates for receiver and transmitter */ rx_period = cd2401_bitrate_divisor( 20000000Ul, &in_baud ); - cd2401->rbpr = (unsigned char)rx_period; - cd2401->rcor = (unsigned char)(rx_period >> 8); /* no DPLL */ tx_period = cd2401_bitrate_divisor( 20000000Ul, &out_baud ); - cd2401->tbpr = (unsigned char)tx_period; - cd2401->tcor = (tx_period >> 3) & 0xE0; /* no x1 ext clk, no loopback */ - - /* NEED TO LOOK AT THIS LINE! */ - /* Timeout for 4 chars at 9600, 8 bits per char, 1 stop bit */ - cd2401->u2.w.rtpr = 0x04; - - /* And finally: */ - if ( t->c_cflag & CREAD ) { - /* Re-initialize channel, enable rx and tx */ - cd2401_chan_cmd (minor, 0x2A, 1); - /* Enable rx data ints */ - cd2401->ier = 0x08; - } else { - /* Re-initialize channel, enable tx, disable rx */ - cd2401_chan_cmd (minor, 0x29, 1); + + /* + * If this is the first time that the line characteristics are set up, then + * the device must be re-initialized. + * Also check if we need to change anything. It is preferable to not touch + * the device if nothing changes. As soon as we touch it, it tends to + * glitch. If anything changes, we reprogram all registers. This is + * harmless. + */ + if ( ( CD2401_Channel_Info[minor].tty == 0 ) || + ( cd2401->cor1 != (parodd | parenb | ignpar | csize) ) || + ( cd2401->cor2 != (sw_flow_ctl | hw_flow_ctl) ) || + ( cd2401->cor3 != (extra_flow_ctl | cstopb) ) || + ( cd2401->cor6 != (igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck) ) || + ( cd2401->cor7 != istrip ) || + ( cd2401->u1.async.schr1 != t->c_cc[VSTART] ) || + ( cd2401->u1.async.schr2 != t->c_cc[VSTOP] ) || + ( cd2401->rbpr != (unsigned char)rx_period ) || + ( cd2401->rcor != (unsigned char)(rx_period >> 8) ) || + ( cd2401->tbpr != (unsigned char)tx_period ) || + ( cd2401->tcor != ( (tx_period >> 3) & 0xE0 ) ) ) + need_reinitialization = TRUE; + + /* Write to the ports */ + rtems_interrupt_disable (level); + + cd2401->car = minor; /* Select channel */ + read_enabled = cd2401->csr & 0x80 ? TRUE : FALSE; + + if ( (t->c_cflag & CREAD ? TRUE : FALSE ) != read_enabled ) { + /* Read enable status is changing */ + need_reinitialization = TRUE; } + + if ( need_reinitialization ) { + /* + * Could not find a way to test whether the CD2401 was done transmitting. + * The TxEmpty interrupt does not seem to indicate that the FIFO is empty + * in DMA mode. So, just wait a while for output to drain. May not be + * enough, but it will have to do (should be long enough for 1 char at + * 9600 bsp)... + */ + cd2401_udelay( 2000L ); + + /* Clear channel */ + cd2401_chan_cmd (minor, 0x40, 1); + + cd2401->car = minor; /* Select channel */ + cd2401->cmr = 0x42; /* Interrupt Rx, DMA Tx, async mode */ + cd2401->cor1 = parodd | parenb | ignpar | csize; + cd2401->cor2 = sw_flow_ctl | hw_flow_ctl; + cd2401->cor3 = extra_flow_ctl | cstopb; + cd2401->cor4 = 0x0A; /* No DSR/DCD/CTS detect; FIFO threshold of 10 */ + cd2401->cor5 = 0x0A; /* No DSR/DCD/CTS detect; DTR threshold of 10 */ + cd2401->cor6 = igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck; + cd2401->cor7 = istrip; /* No LNext; ignore XON/XOFF if frame error; no tx translations */ + /* Special char 1: XON character */ + cd2401->u1.async.schr1 = t->c_cc[VSTART]; + /* special char 2: XOFF character */ + cd2401->u1.async.schr2 = t->c_cc[VSTOP]; + + /* + * Special chars 3 and 4, char range, LNext, RFAR[1..4] and CRC + * are unused, left as is. + */ + + /* Set baudrates for receiver and transmitter */ + cd2401->rbpr = (unsigned char)rx_period; + cd2401->rcor = (unsigned char)(rx_period >> 8); /* no DPLL */ + cd2401->tbpr = (unsigned char)tx_period; + cd2401->tcor = (tx_period >> 3) & 0xE0; /* no x1 ext clk, no loopback */ + + /* Timeout for 4 chars at 9600, 8 bits per char, 1 stop bit */ + cd2401->u2.w.rtpr = 0x04; /* NEED TO LOOK AT THIS LINE! */ + + if ( t->c_cflag & CREAD ) { + /* Re-initialize channel, enable rx and tx */ + cd2401_chan_cmd (minor, 0x2A, 1); + /* Enable rx data ints */ + cd2401->ier = 0x08; + } else { + /* Re-initialize channel, enable tx, disable rx */ + cd2401_chan_cmd (minor, 0x29, 1); + } + } + + CD2401_RECORD_SET_ATTRIBUTES_INFO(( minor, need_reinitialization, csize, + cstopb, parodd, parenb, ignpar, inpck, + hw_flow_ctl, sw_flow_ctl, extra_flow_ctl, + icrnl, igncr, inlcr, brkint, ignbrk, + parmrk, istrip, tx_period, rx_period, + out_baud, in_baud )); + + rtems_interrupt_enable (level); + + /* + * Looks like the CD2401 needs time to settle after initialization. Give it + * 10 ms. I don't really believe it, but if output resumes to quickly after + * this call, the first few characters are not right. + */ + if ( need_reinitialization ) + cd2401_udelay( 10000L ); /* Return something */ return RTEMS_SUCCESSFUL; @@ -949,8 +1103,16 @@ int cd2401_startRemoteTx( int minor ) { - cd2401->car = minor; /* Select channel */ - cd2401->stcr = 0x01; /* Send SCHR1 ahead of chars in FIFO */ + rtems_interrupt_level level; + + rtems_interrupt_disable (level); + + cd2401->car = minor; /* Select channel */ + cd2401->stcr = 0x01; /* Send SCHR1 ahead of chars in FIFO */ + + CD2401_RECORD_START_REMOTE_TX_INFO(( minor )); + + rtems_interrupt_enable (level); /* Return something */ return RTEMS_SUCCESSFUL; @@ -958,7 +1120,7 @@ int cd2401_startRemoteTx( /* - * cd2401_stopRemoreTx + * cd2401_stopRemoteTx * * Defined as a callback, but it would appear that it is never called. The * POSIX standard states that when the tcflow() function is called with the @@ -983,8 +1145,16 @@ int cd2401_stopRemoteTx( int minor ) { - cd2401->car = minor; /* Select channel */ - cd2401->stcr = 0x02; /* Send SCHR2 ahead of chars in FIFO */ + rtems_interrupt_level level; + + rtems_interrupt_disable (level); + + cd2401->car = minor; /* Select channel */ + cd2401->stcr = 0x02; /* Send SCHR2 ahead of chars in FIFO */ + + CD2401_RECORD_STOP_REMOTE_TX_INFO(( minor )); + + rtems_interrupt_enable (level); /* Return something */ return RTEMS_SUCCESSFUL; @@ -992,7 +1162,7 @@ int cd2401_stopRemoteTx( /* - * cd2401_write + * cd2401_write * * Initiate DMA output. Termios guarantees that the buffer does not wrap * around, so we can do DMA strait from the supplied buffer. @@ -1017,43 +1187,75 @@ int cd2401_write( int len ) { - cd2401->car = minor; /* Select channel */ + cd2401->car = minor; /* Select channel */ if ( (cd2401->dmabsts & 0x08) == 0 ) { /* Next buffer is A. Wait for it to be ours. */ - if ( cd2401->atbsts & 0x01 ) { - CD2401_Channel_Info[minor].wait_buf_A++; - while ( cd2401->atbsts & 0x01 ); - } - CD2401_Channel_Info[minor].used_buf_A++; + while ( cd2401->atbsts & 0x01 ); + + CD2401_Channel_Info[minor].own_buf_A = FALSE; CD2401_Channel_Info[minor].len = len; CD2401_Channel_Info[minor].buf = buf; cd2401->atbadru = (rtems_unsigned16)( ( (rtems_unsigned32) buf ) >> 16 ); cd2401->atbadrl = (rtems_unsigned16)( (rtems_unsigned32) buf ); cd2401->atbcnt = len; - cd2401->atbsts = 0x03; /* CD2401 owns buffer, int when empty */ + CD2401_RECORD_WRITE_INFO(( len, buf, 'A' )); + cd2401->atbsts = 0x03; /* CD2401 owns buffer, int when empty */ } else { /* Next buffer is B. Wait for it to be ours. */ - if ( cd2401->btbsts & 0x01 ) { - CD2401_Channel_Info[minor].wait_buf_B++; - while ( cd2401->btbsts & 0x01 ); - } - CD2401_Channel_Info[minor].used_buf_B++; + while ( cd2401->btbsts & 0x01 ); + + CD2401_Channel_Info[minor].own_buf_B = FALSE; CD2401_Channel_Info[minor].len = len; CD2401_Channel_Info[minor].buf = buf; cd2401->btbadru = (rtems_unsigned16)( ( (rtems_unsigned32) buf ) >> 16 ); cd2401->btbadrl = (rtems_unsigned16)( (rtems_unsigned32) buf ); cd2401->btbcnt = len; - cd2401->btbsts = 0x03; /* CD2401 owns buffer, int when empty */ + CD2401_RECORD_WRITE_INFO(( len, buf, 'B' )); + cd2401->btbsts = 0x03; /* CD2401 owns buffer, int when empty */ } - /* Should TxD interrupts be enabled before I set up the DMA transfer? */ - cd2401->ier |= 0x01; /* enable TxD ints */ + /* Nuts -- Need TxD ints */ + CD2401_Channel_Info[minor].txEmpty = FALSE; + cd2401->ier |= 0x01; /* Return something */ return RTEMS_SUCCESSFUL; } +#if 0 +/* + * cd2401_drainOutput + * + * Wait for the txEmpty indication on the specified channel. + * + * Input parameters: + * minor - selected channel + * + * Output parameters: NONE + * + * Return value: IGNORED + * + * MUST NOT BE EXECUTED WITH THE CD2401 INTERRUPTS DISABLED! + * The txEmpty flag is set by the tx ISR. + */ +int cd2401_drainOutput( + int minor +) +{ + CD2401_RECORD_DRAIN_OUTPUT_INFO(( CD2401_Channel_Info[minor].txEmpty, + CD2401_Channel_Info[minor].own_buf_A, + CD2401_Channel_Info[minor].own_buf_B )); + + while( ! (CD2401_Channel_Info[minor].txEmpty && + CD2401_Channel_Info[minor].own_buf_A && + CD2401_Channel_Info[minor].own_buf_B) ); + + /* Return something */ + return RTEMS_SUCCESSFUL; +} +#endif + /* * _167Bug_pollRead @@ -1079,24 +1281,28 @@ int _167Bug_pollRead( { int char_not_available; unsigned char c; - + /* Check for a char in the input FIFO */ - asm volatile( "trap #15 /* Trap to 167Bug (.INSTAT) */ - .short 0x01 - move %%cc, %0 /* Get condition codes */ - andil #4, %0" - : "=d" (char_not_available) :: "%%cc" ); - + asm volatile( "movew #0x1, -(%%sp) /* Code for .INSTAT */ + movew %1, -(%%sp) /* Channel */ + trap #15 /* Trap to 167Bug */ + .short 0x60 /* Code for .REDIR */ + move %%cc, %0 /* Get condition codes */ + andil #4, %0" /* Keep the Zero bit */ + : "=d" (char_not_available) : "d" (minor): "%%cc" ); + if (char_not_available) return -1; - + /* Read the char and return it */ - asm volatile( "subq.l #2,%%a7 /* Space for result */ - trap #15 /* Trap to 167 Bug (.INCHR) */ - .short 0x00 - moveb (%%a7)+, %0" - : "=d" (c) ); - + asm volatile( "subq.l #2,%%a7 /* Space for result */ + movew #0x0, -(%%sp) /* Code for .INCHR */ + movew %1, -(%%sp) /* Channel */ + trap #15 /* Trap to 167 Bug */ + .short 0x60 /* Code for .REDIR */ + moveb (%%a7)+, %0" /* Pop char into c */ + : "=d" (c) : "d" (minor) ); + return (int)c; } @@ -1105,7 +1311,7 @@ int _167Bug_pollRead( * _167Bug_pollWrite * * Output buffer through 167Bug. Returns only once every character has been - * sent (polled output). + * sent (polled output). * * Input parameters: * minor - selected channel @@ -1127,38 +1333,62 @@ int _167Bug_pollWrite( ) { const char *endbuf = buf + len; - - asm volatile( "pea (%0) - pea (%1) - trap #15 /* trap to 167Bug (.OUTSTR) */ - .short 0x21" - :: "a" (endbuf), "a" (buf) ); - + + asm volatile( "pea (%0) /* endbuf */ + pea (%1) /* buf */ + movew #0x21, -(%%sp) /* Code for .OUTSTR */ + movew %2, -(%%sp) /* Channel */ + trap #15 /* Trap to 167Bug */ + .short 0x60" /* Code for .REDIR */ + :: "a" (endbuf), "a" (buf), "d" (minor) ); + /* Return something */ return RTEMS_SUCCESSFUL; } +/* + * Print functions: prototyped in bsp.h + * Debug printing on Channel 1 + */ + +void printk( char *fmt, ... ) +{ + va_list ap; /* points to each unnamed argument in turn */ + static char buf[256]; + unsigned int level; + + _CPU_ISR_Disable(level); + + va_start(ap, fmt); /* make ap point to 1st unnamed arg */ + vsprintf(buf, fmt, ap); /* send output to buffer */ + + BSP_output_string(buf); /* print buffer -- Channel 1 */ + + va_end(ap); /* clean up and re-enable interrupts */ + _CPU_ISR_Enable(level); +} + + +void BSP_output_string( char * buf ) +{ + int len = strlen(buf); + rtems_status_code sc; + + /* The first argument forces a print to Port2 (ttyS1) */ + sc = _167Bug_pollWrite(1, buf, len); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (sc); +} + + /* *************** * BOILERPLATE * *************** * - * All these functions are prototyped in rtems/c/src/lib/include/console.h, - * except console_reserve_resources(), which is prototyped in - * rtems/c/src/lib/libbsp/m68k/mvme167/include/bsp.h - */ - -/* - * Reserve resources consumed by this driver. Allocate enough space in the - * object table to hold semaphores for 4 minor devices. + * All these functions are prototyped in rtems/c/src/lib/include/console.h. */ -void console_reserve_resources( - rtems_configuration_table *configuration -) -{ - rtems_termios_reserve_resources (configuration, 4); -} /* * Initialize and register the device @@ -1229,7 +1459,7 @@ rtems_device_driver console_open( NULL, /* startRemoteTx */ 0 /* outputUsesInterrupts */ }; - + #else static const rtems_termios_callbacks callbacks = { @@ -1242,7 +1472,7 @@ rtems_device_driver console_open( cd2401_startRemoteTx, /* startRemoteTx */ 1 /* outputUsesInterrupts */ }; - + #endif return rtems_termios_open (major, minor, arg, &callbacks); diff --git a/c/src/lib/libbsp/m68k/mvme167/fatal/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/fatal/Makefile.am index 7787c28006..978189a3ce 100644 --- a/c/src/lib/libbsp/m68k/mvme167/fatal/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/fatal/Makefile.am @@ -1,6 +1,6 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 diff --git a/c/src/lib/libbsp/m68k/mvme167/include/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/include/Makefile.am index 3d67271c4a..cec9878eb3 100644 --- a/c/src/lib/libbsp/m68k/mvme167/include/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/include/Makefile.am @@ -1,6 +1,6 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 @@ -25,7 +25,7 @@ TMPINSTALL_FILES += $(PROJECT_INCLUDE) $(PROJECT_INCLUDE)/bsp.h \ $(PROJECT_INCLUDE)/coverhd.h $(PROJECT_INCLUDE)/page_table.h \ $(PROJECT_INCLUDE)/fatal.h -all-local: $(TMPINSTALL_FILES) +all: $(TMPINSTALL_FILES) EXTRA_DIST = bsp.h coverhd.h fatal.h page_table.h diff --git a/c/src/lib/libbsp/m68k/mvme167/include/bsp.h b/c/src/lib/libbsp/m68k/mvme167/include/bsp.h index f449e201e3..1a95d9d576 100644 --- a/c/src/lib/libbsp/m68k/mvme167/include/bsp.h +++ b/c/src/lib/libbsp/m68k/mvme167/include/bsp.h @@ -32,6 +32,24 @@ extern "C" { #include +/* + * confdefs.h overrides for this BSP: + * - termios serial ports (defaults to 1) + * - Interrupt stack space is not minimum if defined. + */ + +#define CONFIGURE_NUMBER_OF_TERMIOS_PORTS 4 +#define CONFIGURE_INTERRUPT_STACK_MEMORY (4 * 1024) + +/* + * Network driver configuration + */ + +struct rtems_bsdnet_ifconfig; +extern int uti596_attach(struct rtems_bsdnet_ifconfig * pConfig ); +#define RTEMS_BSP_NETWORK_DRIVER_NAME "uti1" +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH uti596_attach + /* * This is NOT the base address of local RAM! * This is the base local address of the VMEbus short I/O space. A local @@ -394,7 +412,27 @@ typedef volatile struct cd2401_regs_ { /* CD2401 is clocked at 20 MHz */ #define CD2401_CLK_RATE 20000000 -void console_reserve_resources( rtems_configuration_table *configuration ); +/* + * Debug print functions: implemented in console.c + */ +void printk( char *fmt, ... ); +void BSP_output_string( char * buf ); + +/* + * Representation of 82596CA LAN controller: Memory Map + */ +typedef volatile struct i82596_regs_ { + unsigned short port_lower; /* 0xFFF46000 */ + unsigned short port_upper; /* 0xFFF46002 */ + unsigned long chan_attn; /* 0xFFF46004 */ +} i82596_regs; + +/* + * Base address of the 82596. + */ +#define i82596 ((i82596_regs * const) 0xFFF46000) + + /* BSP-wide functions */ diff --git a/c/src/lib/libbsp/m68k/mvme167/network/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/network/Makefile.am index 601d7cd3e2..795c36566f 100644 --- a/c/src/lib/libbsp/m68k/mvme167/network/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/network/Makefile.am @@ -9,8 +9,6 @@ PGM = $(ARCH)/network.rel C_FILES = network.c C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o) -H_FILES = uti596.h - OBJS = $(C_O_FILES) include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg @@ -20,6 +18,8 @@ include $(top_srcdir)/../../../../../../automake/lib.am # (OPTIONAL) Add local stuff here using += # +AM_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ + $(PGM): $(OBJS) $(make-rel) @@ -31,6 +31,6 @@ endif .PRECIOUS: $(PGM) -EXTRA_DIST = network.c uti596.h +EXTRA_DIST = network.c include $(top_srcdir)/../../../../../../automake/local.am diff --git a/c/src/lib/libbsp/m68k/mvme167/network/network.c b/c/src/lib/libbsp/m68k/mvme167/network/network.c index bcfc07ef00..c8a2e71734 100644 --- a/c/src/lib/libbsp/m68k/mvme167/network/network.c +++ b/c/src/lib/libbsp/m68k/mvme167/network/network.c @@ -1,4 +1,4 @@ -/* uti596.c: An 82596 ethernet driver for rtems-bsd. +/* network.c: An 82596 ethernet driver for rtems-bsd. * * $Id$ */ @@ -9,36 +9,36 @@ * Selectively define to debug the network driver. If you define any of these * you must run with polled console I/O. */ - -#define DBG_596 -#define DBG_596_RFA + +/* +#define DBG_ADD_CMD +#define DBG_WAIT +#define DBG_SEND +#define DBG_MEM +#define DBG_SELFTEST_CMD +#define DBG_DUMP_CMD +#define DBG_RESET +#define DBG_ATTACH #define DBG_START #define DBG_INIT -#define DBG_INIT_2 -/*#define DBG_INIT_3*/ -#define DBG_RESET -#define DBG_VERSION +#define DBG_STOP +#define DBG_RX #define DBG_ISR -#define DBG_RAW_ISR -#define DBG_596_RFD -#define DBG_FR -#define DBG_RAW -#define DBG_ATTACH -#define DBG_POLLED_CMD -#define DBG_ADD -#define DBG_SUPPLY_FD - +#define DBG_IOCTL +#define DBG_STAT +#define DBG_PACKETS +*/ /* * Default number of buffer descriptors and buffer sizes. */ -#define RX_BUF_COUNT 15 -#define TX_BUF_COUNT 4 -#define TX_BD_PER_BUF 4 +#define RX_BUF_COUNT 15 +#define TX_BUF_COUNT 4 +#define TX_BD_PER_BUF 4 -#define RBUF_SIZE 1520 +#define RBUF_SIZE 1520 -#define UTI_596_ETH_MIN_SIZE 60 +#define UTI_596_ETH_MIN_SIZE 60 /* * RTEMS events @@ -62,21 +62,33 @@ #include #include "uti596.h" -#include "netexterns.h" +/* If we are running interrupt driven I/O no debug output is printed */ #if CD2401_POLLED_IO == 1 - #define printk(arglist) printk arglist; + #define printk(arglist) printk arglist; #else - #define printk(arglist) + #define printk(arglist) #endif -#define UTI_596_ASSERT( condition, str ) if (!( condition ) ) { printk((str)) } +#define UTI_596_ASSERT( condition, str ) if (!( condition ) ) { printk((str)) } -int count_rx = 0; -i596_rfd *pISR_Rfd; +/* Types of PORT commands */ +#define UTI596_RESET_PORT_FUNCTION 0 +#define UTI596_SELFTEST_PORT_FUNCTION 1 +#define UTI596_SCP_PORT_FUNCTION 2 +#define UTI596_DUMP_PORT_FUNCTION 3 +/* Types of waiting for commands */ +#define UTI596_NO_WAIT 0 +#define UTI596_WAIT_FOR_CU_ACCEPT 1 +#define UTI596_WAIT_FOR_INITIALIZATION 2 +#define UTI596_WAIT_FOR_STAT_C 3 + +/* Device dependent data structure */ static uti596_softc_ uti596_softc; +/* Globals */ +int count_rx = 0; static int scbStatus; static rtems_status_code sc; static i596_cmd *pIsrCmd; @@ -86,2354 +98,2698 @@ static i596_rfd *pIsrRfd; * Initial 596 configuration */ char uti596initSetup[] = { - 0x0E, /* Byte 0: length, prefetch off ( no RBD's ) */ - 0xC8, /* Byte 1: fifo to 8, monitor off */ - 0x40, /* Byte 2: don't save bad frames ( was save= 80, use intel's 40 )*/ - 0x2E, /* Byte 3: No source address insertion, 8 byte preamble */ - 0x00, /* Byte 4: priority and backoff defaults */ - 0x60, /* Byte 5: interframe spacing */ - 0x00, /* Byte 6: slot time LSB */ - 0xf2, /* Byte 7: slot time and retries */ - 0x0E, /* Byte 8: not promisc, disable bcast, tx no crs, crc inserted 32bit, 802.3 framing */ - 0x08, /* Byte 9: collision detect */ - 0x40, /* Byte 10: minimum frame length */ - 0xfb, /* Byte 11: tried C8 same as byte 1 in bits 6-7, else ignored*/ - 0x00, /* Byte 12: disable full duplex */ - 0x3f /* Byte 13: no multi IA, backoff enabled */ + 0x0E, /* Byte 0: length, prefetch off ( no RBD's ) */ + 0xC8, /* Byte 1: fifo to 8, monitor off */ + 0x40, /* Byte 2: don't save bad frames ( was save= 80, use intel's 40 )*/ + 0x2E, /* Byte 3: No source address insertion, 8 byte preamble */ + 0x00, /* Byte 4: priority and backoff defaults */ + 0x60, /* Byte 5: interframe spacing */ + 0x00, /* Byte 6: slot time LSB */ + 0xf2, /* Byte 7: slot time and retries */ + 0x0C, /* Byte 8: not promisc, enable bcast, tx no crs, crc inserted 32bit, 802.3 framing */ + 0x08, /* Byte 9: collision detect */ + 0x40, /* Byte 10: minimum frame length */ + 0xfb, /* Byte 11: tried C8 same as byte 1 in bits 6-7, else ignored*/ + 0x00, /* Byte 12: disable full duplex */ + 0x3f /* Byte 13: no multi IA, backoff enabled */ }; -/* Required RTEMS network driver functions and tasks (reset daemon extra) */ - -static void uti596_start( struct ifnet * ); -void uti596_init( void * ); -void uti596_stop( uti596_softc_ * ); -void uti596_txDaemon( void * ); -void uti596_rxDaemon( void * ); -void uti596_resetDaemon( void * ); -rtems_isr uti596_DynamicInterruptHandler (rtems_vector_number ); -static int uti596_ioctl( struct ifnet *, int, caddr_t ); -void uti596_stats( uti596_softc_ * ); - /* Local Routines */ -void uti596_initialize_hardware( uti596_softc_ * ); -void uti596_initMem( uti596_softc_ * ); -int uti596_initRFA( int ); -void uti596addPolledCmd( i596_cmd * ); -void uti596Diagnose( int ); -i596_rfd * uti596dequeue( i596_rfd ** ); -void uti596reset( void ); -void uti596_reset_hardware( uti596_softc_ *); -void uti596clearListStatus( i596_rfd * ); -void send_packet( struct ifnet *, struct mbuf * ); -void uti596addCmd( i596_cmd *pCmd ); -void uti596supplyFD( i596_rfd * ); -void uti596append( i596_rfd ** , i596_rfd * ); - -void printk_time( void ); -void dump_scb( void ); - -#ifdef DBG_INIT_3 +static unsigned long word_swap ( unsigned long ); +static void * malloc_16byte_aligned ( void **, void ** adjusted_pointer, size_t ); +RTEMS_INLINE_ROUTINE void uti596_writePortFunction ( void *, unsigned long ); +RTEMS_INLINE_ROUTINE void uti596_portReset( void ); +static unsigned long uti596_portSelfTest( i596_selftest * ); +static int uti596_portDump ( i596_dump_result * ); +static int uti596_wait ( uti596_softc_ *, unsigned8 ); +static int uti596_issueCA ( uti596_softc_ *, unsigned8 ); +static void uti596_addCmd ( i596_cmd * ); +static void uti596_addPolledCmd ( i596_cmd * ); +static void uti596_CU_dump ( i596_dump_result * ); +static void uti596_dump_scb ( void ); +static int uti596_setScpAndScb ( uti596_softc_ * ); +static int uti596_diagnose ( void ); +static int uti596_configure ( uti596_softc_ * ); +static int uti596_IAsetup ( uti596_softc_ * ); +static int uti596_initTBD ( uti596_softc_ * ); +static int uti596_initRFA ( int ); +static void uti596_initMem ( uti596_softc_ * ); +static void uti596_initialize ( uti596_softc_ * ); +static void uti596_initialize_hardware ( uti596_softc_ * ); +static void uti596_reset_hardware ( uti596_softc_ *); +static void uti596_reset ( void ); +static void uti596_clearListStatus ( i596_rfd * ); +static i596_rfd * uti596_dequeue ( i596_rfd ** ); +static void uti596_append ( i596_rfd ** , i596_rfd * ); +static void uti596_supplyFD ( i596_rfd * ); +static void send_packet ( struct ifnet *, struct mbuf * ); + + +/* Required RTEMS network driver functions and tasks (plus reset daemon) */ + +static void uti596_start ( struct ifnet * ); +void uti596_init ( void * ); +void uti596_stop ( uti596_softc_ * ); +void uti596_txDaemon ( void * ); +void uti596_rxDaemon ( void * ); +void uti596_resetDaemon( void * ); +rtems_isr uti596_DynamicInterruptHandler ( rtems_vector_number ); +static int uti596_ioctl ( struct ifnet *, int, caddr_t ); +void uti596_stats ( uti596_softc_ * ); + +#ifdef DBG_PACKETS +static void dumpQ( void ); +static void show_buffers( void ); +static void show_queues( void ); static void print_eth ( unsigned char * ); static void print_hdr ( unsigned char * ); static void print_pkt ( unsigned char * ); static void print_echo ( unsigned char * ); #endif -int uti596dump( char * ); -void dumpQ( void ); -void show_buffers( void ); -void show_queues( void ); - -/* Helper function for reading/writing big endian memory structures */ -unsigned long word_swap(unsigned long); -/* Waits for the command word to clear. The command word is cleared AFTER the interrupt is - * generated. This allows the CPU to issue the next command +/* + * word_swap + * + * Return a 32 bit value, swapping the upper and lower words first. + * + * Input parameters: + * val - 32 bit value to swap + * + * Output parameters: NONE + * + * Return value: + * Input value with upper and lower 16-bit words swapped */ -#define UTI_WAIT_COMMAND_ACCEPTED(duration,function) \ -{ rtems_interval ticks_per_second, start_ticks, end_ticks; \ - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); \ - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \ - end_ticks = start_ticks + ticks_per_second; \ - do { \ - if (uti596_softc.scb.command == 0) \ - break; \ - else { \ - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \ - } \ - } while (start_ticks <= end_ticks); \ - if ((uti596_softc.scb.command != 0) || (start_ticks > end_ticks)) \ - printf("%s: i82596 timed out with status %x, cmd %x.\n", function, \ - uti596_softc.scb.status, uti596_softc.scb.command); \ +static unsigned long word_swap( + unsigned long val +) +{ + return (((val >> 16)&(0x0000ffff)) | ((val << 16)&(0xffff0000))); } -#define UTI_WAIT_TICKS \ -{ rtems_interval ticks_per_second, start_ticks, end_ticks; \ - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); \ - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \ - end_ticks = start_ticks + ticks_per_second; \ - do { \ - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); \ - } while (start_ticks <= end_ticks); \ -} -/************************************************************************/ - - - /*********************************************************************** - * Function: uti596_attach - * - * Description: - * Configure the driver, and connect to the network stack - * - * Algorithm: - * - * Check parameters in the ifconfig structure, and - * set driver parameters accordingly. - * initialize required rx and tx buffers - * link driver data structure onto device list - * return 1 on successful completion - * - ***********************************************************************/ -int uti596_attach( - struct rtems_bsdnet_ifconfig * pConfig +/* + * malloc_16byte_aligned + * + * Allocate a block of a least nbytes aligned on a 16-byte boundary. + * Clients are responsible to store both the real address and the adjusted + * address. The real address must be used to free the block. + * + * Input parameters: + * real_pointer - pointer to a void * pointer in which to store the starting + * address of the block. Required for free. + * adjusted_pointer - pointer to a void * pointer in which to store the + * starting address of the block rounded up to the next + * 16 byte boundary. + * nbytes - number of bytes of storage requested + * + * Output parameters: + * real_pointer - starting address of the block. + * adjusted_pointer - starting address of the block rounded up to the next + * 16 byte boundary. + * + * Return value: + * starting address of the block rounded up to the next 16 byte boundary. + * NULL if no storage was allocated. + */ +static void * malloc_16byte_aligned( + void ** real_pointer, + void ** adjusted_pointer, + size_t nbytes ) { - uti596_softc_ *sc = &uti596_softc; /* device dependent data structure */ - struct ifnet * ifp = &sc->arpcom.ac_if; /* ifnet structure */ - - int unitNumber; - char *unitName; - -#ifdef DBG_ATTACH - printk(("uti596_attach: begins\n")) -#endif - - /* The NIC is not started yet */ - sc->started = 0; - - /* Indicate to ULCS that this is initialized */ - ifp->if_softc = sc; - sc->pScp = NULL; - - /* Parse driver name */ - if ((unitNumber = rtems_bsdnet_parse_driver_name (pConfig, &unitName)) < 0) - return 0; - - ifp->if_name = unitName; - ifp->if_unit = unitNumber; + *real_pointer = malloc( nbytes + 0xF, 0, M_NOWAIT ); + *adjusted_pointer = (void *)(((unsigned long)*real_pointer + 0xF ) & 0xFFFFFFF0 ); + return *adjusted_pointer; +} - /* Assign mtu */ - if ( pConfig -> mtu ) - ifp->if_mtu = pConfig -> mtu; - else - ifp->if_mtu = ETHERMTU; - /* For now the ethernet address must be specified in the ifconfig structure, - * else FIXME so it can be read in from BBRAM at $FFFC1F2C (6 bytes) - * mvme167 manual p. 1-47 - */ - if ( pConfig->hardware_address) { - memcpy (sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN); +/* + * uti596_scp_alloc + * + * Allocate a new scp, possibly freeing a previously allocated one. + * + * Input parameters: + * sc - pointer to the global uti596_softc in which to store pointers + * to the newly allocated block. + * + * Output parameters: NONE + * + * Return value: + * Pointer to the newly allocated, 16-byte aligned scp. + */ +static i596_scp * uti596_scp_alloc( + uti596_softc_ * sc +) +{ + if( sc->base_scp != NULL ) { + #ifdef DBG_MEM + printk(("uti596_scp_alloc: Already have an SCP at %p\n", sc->base_scp)) + #endif + return sc->pScp; } + + /* allocate enough memory for the Scp block to be aligned on 16 byte boundary */ + malloc_16byte_aligned( (void *)&(sc->base_scp), (void *)&(sc->pScp), sizeof( i596_scp ) ); + + #ifdef DBG_MEM + printk(("uti596_scp_alloc: Scp base address is %p\n", sc->base_scp)) + printk(("uti596_scp_alloc: Scp aligned address is : %p\n",sc->pScp)) + #endif - /* Assign requested receive buffer descriptor count */ - if (pConfig->rbuf_count) - sc->rxBdCount = pConfig->rbuf_count; - else - sc->rxBdCount = RX_BUF_COUNT; + return sc->pScp; +} - /* Assign requested tx buffer descriptor count */ - if (pConfig->xbuf_count) - sc->txBdCount = pConfig->xbuf_count; - else - sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF; - /* Set up fields in the ifnet structure*/ - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; - ifp->if_snd.ifq_maxlen = ifqmaxlen; - ifp->if_init = uti596_init; - ifp->if_ioctl = uti596_ioctl; - ifp->if_start = uti596_start; - ifp->if_output = ether_output; +/* + * uti596_writePortFunction + * + * Write the command into the PORT. + * + * Input parameters: + * addr - 16-byte aligned address to write into the PORT. + * cmd - 4-bit cmd to write into the PORT + * + * Output parameters: NONE + * + * Return value: NONE + * + * The Motorola manual swapped the high and low registers. + */ +RTEMS_INLINE_ROUTINE void uti596_writePortFunction( + void * addr, + unsigned long cmd +) +{ + i82596->port_lower = (unsigned short)(((unsigned long)addr & 0xFFF0) | cmd); + i82596->port_upper = (unsigned short)(((unsigned long)addr >> 16 ) & 0xFFFF); +} - /* uti596_softc housekeeping */ - sc->started = 1; - sc->pInboundFrameQueue = I596_NULL; - sc->scb.command = 0; - /* - * Attach the interface - */ - if_attach (ifp); - ether_ifattach (ifp); - return 1; +/* + * uti596_portReset + * + * Issue a port Reset to the uti596 + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: NONE + */ +RTEMS_INLINE_ROUTINE void uti596_portReset( void ) +{ + uti596_writePortFunction( NULL, UTI596_RESET_PORT_FUNCTION ); } -/*********************************************************************** - * Function: uti596_start + +/* + * uti596_portSelfTest * - * Description: - * start the driver + * Perform a self-test. Wait for up to 1 second for the test to + * complete. Normally, the test should complete in a very short time, + * so busy waiting is not an issue. * - * Algorithm: - * send an event to the tx task - * set the if_flags + * Input parameters: + * stp - pointer to a 16-byte aligned uti596_selftest structure. * - ***********************************************************************/ -static void uti596_start( - struct ifnet *ifp + * Output parameters: NONE + * + * Return value: + * 32-bit result field if successful, -1 otherwise. + */ +static unsigned long uti596_portSelfTest( + i596_selftest * stp ) { - uti596_softc_ *sc = ifp->if_softc; -#ifdef DBG_INIT - printk(("uti596_start: begins\n")) -#endif - rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); - ifp->if_flags |= IFF_OACTIVE; + rtems_interval ticks_per_second, start_ticks, end_ticks; + + stp->results = 0xFFFFFFFF; + uti596_writePortFunction( stp, UTI596_SELFTEST_PORT_FUNCTION ); + + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + end_ticks = start_ticks + ticks_per_second; + + do { + if( stp->results != 0xFFFFFFFF ) + break; + else + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_SELFTEST_CMD + printk(("uti596_selftest: Timed out\n" )) + #endif + return -1; + } + else { + #ifdef DBG_SELFTEST_CMD + printk(("uti596_selftest: Succeeded with signature = 0x%08x, result = 0x%08x\n", + stp->signature, + stp->results)) + #endif + return stp->results; + } } -/*********************************************************************** - * Function: uti596_init + +/* + * uti596_portDump * - * Description: - * driver initialization + * Perform a dump Wait for up to 1 second for the test to + * complete. Normally, the test should complete in a very short time, + * so busy waiting is not an issue. * - * Algorithm: - * initialize the 82596 - * start driver tx and rx tasks, and reset task - * send the RX_START command the the RU - * set if_flags + * Input parameters: + * dp - pointer to a 16-byte aligned uti596_dump structure. * + * Output parameters: NONE * - ***********************************************************************/ -void uti596_init( - void * arg + * Return value: + * 16-bit dump_status field if successful, -1 otherwise. + */ +static int uti596_portDump( + i596_dump_result * dp ) { - uti596_softc_ *sc = arg; - struct ifnet *ifp = &sc->arpcom.ac_if; + rtems_interval ticks_per_second, start_ticks, end_ticks; + + dp->dump_status = 0; + uti596_writePortFunction( dp, UTI596_DUMP_PORT_FUNCTION ); - if (sc->txDaemonTid == 0) { + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + end_ticks = start_ticks + ticks_per_second; + + do { + if( dp->dump_status != 0xA006 ) + break; + else + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_DUMP_CMD + printk(("uti596_dump: Timed out with dump at 0x%08x\n", (unsigned long)dp )) + #endif + return -1; + } + else { + #ifdef DBG_DUMP_CMD + printk(("uti596_dump: Succeeded with dump at = 0x%08x\n", (unsigned long)dp )) + #endif + return dp->dump_status; + } +} - /* - * Initialize the 82596 - */ -#ifdef DBG_INIT - printk(("uti596_init: begins\nuti596_init: initializing the 82596...\n")) -#endif - uti596_initialize_hardware(sc); - /* - * Start driver tasks - */ -#ifdef DBG_INIT - printk(("uti596_init: starting driver tasks...\n")) -#endif - sc->txDaemonTid = rtems_bsdnet_newproc ("UTtx", 2*4096, uti596_txDaemon, sc); - sc->rxDaemonTid = rtems_bsdnet_newproc ("UTrx", 2*4096, uti596_rxDaemon, sc); - sc->resetDaemonTid = rtems_bsdnet_newproc ("UTrt", 2*4096, uti596_resetDaemon, sc); +/* + * uti596_wait + * + * Wait for a certain condition. + * + * Input parameters: + * sc - pointer to the uti596_softc struct + * wait_type - UTI596_NO_WAIT + * UTI596_WAIT_FOR_CU_ACCEPT + * UTI596_WAIT_FOR_INITIALIZATION + * UTI596_WAIT_FOR_STAT_C + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise. + */ +static int uti596_wait( + uti596_softc_ *sc, + unsigned8 waitType +) +{ + rtems_interval ticks_per_second, start_ticks, end_ticks; + + switch( waitType ) { + case UTI596_NO_WAIT: + return 0; -#ifdef DBG_INIT - printk(("uti596_init: After attach, status of board = 0x%x\n", sc->scb.status )) -#endif - } + case UTI596_WAIT_FOR_CU_ACCEPT: + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + end_ticks = start_ticks + ticks_per_second; + + do { + if (sc->scb.command == 0) + break; + else + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + + } while (start_ticks <= end_ticks); + + if( (sc->scb.command != 0) || (start_ticks > end_ticks) ) { + printf("i82596 timed out with status %x, cmd %x.\n", + sc->scb.status, sc->scb.command); + return -1; + } + else + return 0; + + case UTI596_WAIT_FOR_INITIALIZATION: + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + end_ticks = start_ticks + ticks_per_second; + + do { + if( !sc->iscp.busy ) + break; + else + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_WAIT + printk(("uti596_setScpAndScb: Timed out\n" )) + #endif + return -1; + } + else { + #ifdef DBG_WAIT + printk(("uti596_setScpAndScb: Succeeded\n" )) + #endif + return 0; + } - /* - * Enable receiver - */ -#ifdef DBG_INIT - printk(("uti596_init: enabling the reciever...\n" )) -#endif - sc->scb.command = RX_START; + case UTI596_WAIT_FOR_STAT_C: + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + end_ticks = start_ticks + ticks_per_second; + + do { + if( *sc->pCurrent_command_status & STAT_C ) + break; + else + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); + } while (start_ticks <= end_ticks); + + if (start_ticks > end_ticks ) { + #ifdef DBG_WAIT + printk(("uti596_initMem: timed out - STAT_C not obtained\n" )) + #endif + return -1; + } + else { + #ifdef DBG_WAIT + printk(("uti596_initMem: STAT_C obtained OK\n" )) + #endif + return 0; + } + } + return -1; +} + + +/* + * uti596_issueCA + * + * Issue a Channel Attention command. Possibly wait for the + * command to start or complete. + * + * Input parameters: + * sc - pointer to the uti596_softc + * wait_type - UTI596_NO_WAIT + * UTI596_WAIT_BEGIN + * UTI596_WAIT_COMPLETION + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise. + */ +static int uti596_issueCA( + uti596_softc_ *sc, + unsigned8 waitType +) +{ + /* Issue Channel Attention */ i82596->chan_attn = 0x00000000; - UTI_WAIT_COMMAND_ACCEPTED(4000,"uti596_init: RX_START"); - /* - * Tell the world that we're running. - */ - ifp->if_flags |= IFF_RUNNING; -#ifdef DBG_INIT - printk(("uti596_init: completed.\n")) -#endif + return (uti596_wait ( sc, waitType )); } -/*********************************************************************** - * Function: uti596stop - * - * Description: - * stop the driver - * - * Algorithm: - * mark driver as not started, - * mark transmitter as busy - * abort any transmissions/receptions - * clean-up all buffers ( RFD's et. al. ) + +/* + * uti596_addCmd + * + * Add a uti596_cmd onto the end of the CBL command chain, + * or to the start if the chain is empty. + * + * Input parameters: + * pCmd - a pointer to the command to be added. * + * Output parameters: NONE * + * Return value: NONE + */ +static void uti596_addCmd( + i596_cmd *pCmd +) +{ + ISR_Level level; + + #ifdef DBG_ADD_CMD + printk(("uti596_addCmd: Adding command 0x%x\n", pCmd -> command )) + #endif + + /* Mark command as last in list, to return an interrupt */ + pCmd->command |= (CMD_EOL | CMD_INTR ); + pCmd->status = 0; + pCmd->next = I596_NULL; + + _ISR_Disable(level); + + if (uti596_softc.pCmdHead == I596_NULL) { + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd; + uti596_softc.scb.cmd_pointer = word_swap ((unsigned long)pCmd); + + uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); + uti596_softc.scb.command = CUC_START; + uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT ); + + _ISR_Enable(level); + } + else { + uti596_softc.pCmdTail->next = (i596_cmd *) word_swap ((unsigned long)pCmd); + uti596_softc.pCmdTail = pCmd; + _ISR_Enable(level); + } + + #ifdef DBG_ADD_CMD + printk(("uti596_addCmd: Scb status & command 0x%x 0x%x\n", + uti596_softc.scb.status, + uti596_softc.scb.command )) + #endif +} + + +/* + * uti596_addPolledCmd + * + * Add a single uti596_cmd to the end of the command block list + * for processing, send a CU_START and wait for its acceptance + * + * Input parameters: + * sc - a pointer to the uti596_softc struct * + * Output parameters: NONE * - ***********************************************************************/ - -/* static */ void uti596_stop( - uti596_softc_ *sc + * Return value: NONE + */ +void uti596_addPolledCmd( + i596_cmd *pCmd ) { - struct ifnet *ifp = &sc->arpcom.ac_if; - ifp->if_flags &= ~IFF_RUNNING; - sc->started = 0; + #ifdef DBG_ADD_CMD + printk(("uti596_addPolledCmd: Adding command 0x%x\n", pCmd -> command )) + #endif -#ifdef DBG_596 - printk(("uti596stop: %s: Shutting down ethercard, status was %4.4x.\n", - uti596_softc.arpcom.ac_if.if_name, uti596_softc.scb.status)) -#endif + pCmd->status = 0; + pCmd->command |= CMD_EOL ; /* only command in list*/ + pCmd->next = I596_NULL; - printk(("Stopping interface\n")) - sc->scb.command = CUC_ABORT | RX_ABORT; - i82596->chan_attn = 0x00000000; -} + uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd; + uti596_softc.scb.cmd_pointer = word_swap((unsigned long)pCmd); + uti596_softc.scb.command = CUC_START; + uti596_issueCA ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL; + uti596_softc.scb.cmd_pointer = (unsigned long) I596_NULL; -/*********************************************************************** - * Function: void uti596_txDaemon - * - * Description: Transmit task - * - * Algorithm: Get mbufs to be transmitted, stuff into RFDs, send - * - ***********************************************************************/ + #ifdef DBG_ADD_CMD + printk(("uti596_addPolledCmd: Scb status & command 0x%x 0x%x\n", + uti596_softc.scb.status, + uti596_softc.scb.command )) + #endif +} -void uti596_txDaemon( - void *arg -) + +/* + * uti596_CU_dump + * + * Dump the LANC 82596 registers + * The outcome is the same as the portDump() but executed + * via the CU instead of via a PORT access. + * + * Input parameters: + * drp - a pointer to a i596_dump_result structure. + * + * Output parameters: NONE + * + * Return value: NONE + */ +static void uti596_CU_dump ( i596_dump_result * drp) { - uti596_softc_ *sc = (uti596_softc_ *)arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mbuf *m; - rtems_event_set events; + i596_dump dumpCmd; - for (;;) { - /* - * Wait for packet from stack - */ - rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, &events); + dumpCmd.cmd.command = CmdDump; + dumpCmd.cmd.next = I596_NULL; + dumpCmd.pData = (char *) drp; + uti596_softc.cmdOk = 0; + uti596_addCmd ( (i596_cmd *) &dumpCmd ); - /* - * Send packets till queue is empty. - * Ensure that irq is on before sending. - */ - for (;;) { - /* Get the next mbuf chain to transmit. */ - IF_DEQUEUE(&ifp->if_snd, m); - if (!m) - break; +} - send_packet (ifp, m); /* blocks */ - } - ifp->if_flags &= ~IFF_OACTIVE; /* no more to send, mark output inactive */ - } + +/* + * uti596_dump_scb + * + * Dump the system control block + * This function expands to nothing when using interrupt driven I/O + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: NONE + */ +static void uti596_dump_scb ( void ) +{ + printk(("status 0x%x\n",uti596_softc.scb.status)) + printk(("command 0x%x\n",uti596_softc.scb.command)) + printk(("cmd 0x%x\n",(int)uti596_softc.scb.pCmd)) + printk(("rfd 0x%x\n",(int)uti596_softc.scb.pRfd)) + printk(("crc_err 0x%x\n",uti596_softc.scb.crc_err)) + printk(("align_err 0x%x\n",uti596_softc.scb.align_err)) + printk(("resource_err 0x%x\n",uti596_softc.scb.resource_err )) + printk(("over_err 0x%x\n",uti596_softc.scb.over_err)) + printk(("rcvdt_err 0x%x\n",uti596_softc.scb.rcvdt_err)) + printk(("short_err 0x%x\n",uti596_softc.scb.short_err)) + printk(("t_on 0x%x\n",uti596_softc.scb.t_on)) + printk(("t_off 0x%x\n",uti596_softc.scb.t_off)) } -/*********************************************************************** - * Function: uti596_rxDaemon + +/* + * uti596_setScpAndScb * - * Description: Receiver task + * Issue the first channel attention after reset and wait for the busy + * field to clear in the iscp. * - * Algorithm: Extract the packet from an RFD, and place into an - * mbuf chain. Place the mbuf chain in the network task - * queue. Assumes that the frame check sequence is removed - * by the 82596. + * Input parameters: + * sc - pointer to the global uti596_softc * - ***********************************************************************/ - -/* static */ void uti596_rxDaemon( - void *arg + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise. + */ +static int uti596_setScpAndScb( + uti596_softc_ * sc ) { - uti596_softc_ *sc = (uti596_softc_ *)arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mbuf *m; + /* set the busy flag in the iscp */ + sc->iscp.busy = 1; - i596_rfd *pRfd; - ISR_Level level; - int tid; - rtems_event_set events; - struct ether_header *eh; + /* the command block list (CBL) is empty */ + sc->scb.command = 0; + sc->scb.cmd_pointer = (unsigned long) I596_NULL; /* all 1's */ + sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */ - int frames = 0; -#ifdef DBG_INIT_3 - int i; -#endif + uti596_writePortFunction( sc->pScp, UTI596_SCP_PORT_FUNCTION ); + + /* Issue CA: pass the scb address to the 596 */ + return ( uti596_issueCA ( sc, UTI596_WAIT_FOR_INITIALIZATION ) ); +} -#ifdef DBG_596 - printk(("uti596_rxDaemon: begin\n")) - printk(("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd)) -#endif - rtems_task_ident (0, 0, &tid); +/* + * uti596_diagnose + * + * Send a diagnose command to the CU + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_diagnose( void ) +{ + i596_cmd diagnose; -#ifdef DBG_596 - printk(("uti596_rxDaemon: RX tid = 0x%x\n", tid)) -#endif + diagnose.command = CmdDiagnose; + diagnose.status = 0; + uti596_softc.pCurrent_command_status = &diagnose.status; + uti596_addPolledCmd(&diagnose); + return (uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_STAT_C )); - for(;;) { - /* - * Wait for packet. - */ -#ifdef DBG_596 - printk(("uti596_rxDaemon: Receiver sleeps\n")) -#endif + #ifdef DBG_INIT + printk(("Status diagnostic: 0xa000 is a success ... 0x%2.2x\n", diagnose.status)) + #endif +} - rtems_bsdnet_event_receive (INTERRUPT_EVENT, - RTEMS_WAIT|RTEMS_EVENT_ANY, - RTEMS_NO_TIMEOUT, - &events); -#ifdef DBG_596 - printk(("uti596_rxDaemon: Receiver wakes\n")) -#endif - /* - * While received frames are available. Note that the frame may be - * a fragment, so it is NOT a complete packet. - */ - pRfd = uti596dequeue( &sc->pInboundFrameQueue); - while ( pRfd && - pRfd != I596_NULL && - pRfd -> stat & STAT_C ) - { - -#ifdef DBG_INIT_3 - printk(("\nuti596_rxDaemon: Received packet:\n")) - print_eth( pRfd->data); -#endif - if ( pRfd->stat & STAT_OK) { /* a good frame */ - int pkt_len = pRfd->count & 0x3fff; /* the actual # of bytes received */ +/* + * uti596_configure + * + * Send the CU a configure command with the desired + * configuration structure + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_configure ( + uti596_softc_ * sc +) +{ + sc->set_conf.cmd.command = CmdConfigure; + memcpy (sc->set_conf.data, uti596initSetup, 14); + uti596_addPolledCmd( (i596_cmd *) &sc->set_conf); -#ifdef DBG_596 - printk(("uti596_rxDaemon: Good frame, @%p, data @%p length %d\n", pRfd, pRfd -> data , pkt_len)) -#endif - frames++; - - /* - * Allocate an mbuf to give to the stack - * The format of the data portion of the RFD is: - * . - * The FRAME CHECK SEQUENCE / CRC is stripped by the uti596. - * This is to be optimized later.... should not have to memcopy! - */ - MGETHDR(m, M_WAIT, MT_DATA); - MCLGET(m, M_WAIT); - - m->m_pkthdr.rcvif = ifp; - /* move everything into an mbuf */ - memcpy(m->m_data, - pRfd->data, - pkt_len); - - m->m_len = m->m_pkthdr.len = pkt_len - sizeof(struct ether_header) - 4; - - /* move the header to an mbuf */ - eh = mtod (m, struct ether_header *); - m->m_data += sizeof(struct ether_header); - -#ifdef DBG_596 - printk(("uti596_rxDaemon: m->m_ext: %p pRfd -> data: %p\n", - m->m_ext, pRfd->data)) -#endif -#ifdef DBG_INIT_3 - printk(("uti596_rxDaemon: mbuf contains:\n")) - print_eth( (char *) (((int)m->m_data)-sizeof(struct ether_header))); - for ( i = 0; i<20; i++) { - printk((".")) - } -#endif - ether_input (ifp, eh, m); + /* Poll for successful command completion */ + sc->pCurrent_command_status = &(sc->set_conf.cmd.status); + return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) ); +} - } /* end if STAT_OK */ - else { - /* - * A bad frame is present: Note that this could be the last RFD! - */ -#ifdef DBG_596 - printk(("uti596_rxDaemon: Bad frame\n")) -#endif - /* - * FIX ME: use the statistics from the SCB - */ - sc->stats.rx_errors++; - if ((sc->scb.pRfd->stat) & 0x0001) - sc->stats.collisions++; - if ((sc->scb.pRfd->stat) & 0x0080) - sc->stats.rx_length_errors++; - if ((sc->scb.pRfd->stat) & 0x0100) - sc->stats.rx_over_errors++; - if ((sc->scb.pRfd->stat) & 0x0200) - sc->stats.rx_fifo_errors++; - if ((sc->scb.pRfd->stat) & 0x0400) - sc->stats.rx_frame_errors++; - if ((sc->scb.pRfd->stat) & 0x0800) - sc->stats.rx_crc_errors++; - if ((sc->scb.pRfd->stat) & 0x1000) - sc->stats.rx_length_errors++; - } +/* + * uti596_IAsetup + * + * Send the CU an Individual Address setup command with + * the ethernet hardware address + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_IAsetup ( + uti596_softc_ * sc +) +{ + int i; + + sc->set_add.cmd.command = CmdSASetup; + for ( i=0; i<6; i++) { + sc->set_add.data[i]=sc->arpcom.ac_enaddr[i]; + } + sc->cmdOk = 0; + uti596_addPolledCmd((i596_cmd *)&sc->set_add); - UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD\n") + /* Poll for successful command completion */ + sc->pCurrent_command_status = &(sc->set_add.cmd.status); + return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) ); +} -#ifdef DBG_SUPPLY_FD - printk(("uti596_rxDaemon: Supply FD Starting\n")) -#endif - _ISR_Disable(level); - uti596supplyFD ( pRfd ); /* Return RFD to RFA. */ - _ISR_Enable(level); -#ifdef DBG_SUPPLY_FD - printk(("uti596_rxDaemon: Supply FD Complete\n")) -#endif - pRfd = uti596dequeue( &sc->pInboundFrameQueue); /* grab next frame */ - } /* end while */ - } /* end for(;;) */ +/* + * uti596_initTBD + * + * Initialize transmit buffer descriptors + * dynamically allocate mem for the number of tbd's required + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: + * 0 if successful, -1 otherwise + */ +static int uti596_initTBD ( uti596_softc_ * sc ) +{ + int i; + i596_tbd *pTbd, *pPrev; + + /* Set up a transmit command with a tbd ready */ + sc->pLastUnkRFD = I596_NULL; + sc->pTxCmd = (i596_tx *) calloc (1,sizeof (struct i596_tx) ); + sc->pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) ); + if ((sc->pTxCmd == NULL) || (sc->pTbd == NULL)) { + return -1; + } + sc->pTxCmd->pTbd = (i596_tbd *) word_swap ((unsigned long) sc->pTbd); + sc->pTxCmd->cmd.command = CMD_FLEX|CmdTx; + sc->pTxCmd->pad = 0; + sc->pTxCmd->count = 0; /* all bytes are in list of TBD's */ + + pPrev = pTbd = sc->pTbd; -#ifdef DBG_596 - printk (("uti596_rxDaemon: frames ... %d\n", frames)) -#endif + /* Allocate a linked list of tbd's each with it's 'next' field written + * with upper and lower words swapped (for big endian), and mark the end. + */ + for ( i=0; itxBdCount; i++) { + if ( (pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) )) == NULL ) { + return -1; + } + pPrev->next = (i596_tbd *) word_swap ((unsigned long) pTbd); + pPrev = pTbd; + } + pTbd->next = I596_NULL; + return 0; } -/*********************************************************************** - * Function: void uti596_resetDaemon + +/* + * uti596_initRFA + * + * Initialize the Receive Frame Area + * dynamically allocate mem for the number of rfd's required + * + * Input parameters: + * sc - a pointer to the uti596_softc struct * - * Description: - ***********************************************************************/ -void uti596_resetDaemon( - void *arg -) + * Output parameters: NONE + * + * Return value: + * # of buffer descriptors successfully allocated + */ +static int uti596_initRFA( int num ) { - uti596_softc_ *sc = (uti596_softc_ *)arg; - rtems_event_set events; - rtems_time_of_day tm_struct; + i596_rfd *pRfd; + int i = 0; - /* struct ifnet *ifp = &sc->arpcom.ac_if; */ + #ifdef DBG_INIT + printk(("uti596_initRFA: begins\n Requested frame descriptors ... %d.\n", num)) + #endif - for (;;) { - /* Wait for reset event from ISR */ - rtems_bsdnet_event_receive (NIC_RESET_EVENT, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, &events); + /* + * Create the first RFD in the RFA + */ + pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd)); + if ( !pRfd ) { + printk(("Can't allocate first buffer.\n")) + return 0; + } + else { + uti596_softc.countRFD = 1; + uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; + } - rtems_clock_get(RTEMS_CLOCK_GET_TOD, &tm_struct); - printk(("reset daemon: Resetting NIC @ %d:%d:%d \n", - tm_struct.hour, tm_struct.minute, tm_struct.second)) + /* Create remaining RFDs */ + for (i = 1; i < num; i++) { + pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd) ); + if ( pRfd != NULL ) { + uti596_softc.countRFD++; /* update count */ + uti596_softc.pEndRFA->next = + (i596_rfd *) word_swap ((unsigned long) pRfd); /* write the link */ + uti596_softc.pEndRFA = pRfd; /* move the end */ + } + else { + printk(("Can't allocate all buffers: only %d allocated\n", i)) + break; + } + } /* end for */ - sc->stats.nic_reset_count++; - /* Reinitialize the LANC */ - rtems_bsdnet_semaphore_obtain (); - uti596reset(); - rtems_bsdnet_semaphore_release (); - } -} + uti596_softc.pEndRFA->next = I596_NULL; + UTI_596_ASSERT(uti596_softc.countRFD == RX_BUF_COUNT,"INIT:WRONG RFD COUNT\n" ) + + #ifdef DBG_INIT + printk (("uti596_initRFA: Head of RFA is buffer %p \n\ + uti596_initRFA: End of RFA is buffer %p \n", + uti596_softc.pBeginRFA, uti596_softc.pEndRFA )) + #endif + /* Walk and initialize the RFD's */ + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = (i596_rfd *) word_swap ((unsigned long)pRfd->next) ) + { + pRfd->cmd = 0x0000; + pRfd->stat = 0x0000; + pRfd->pRbd = I596_NULL; + pRfd->count = 0; /* number of bytes in buffer: usually less than size */ + pRfd->size = 1532; /* was 1532; buffer size ( All RBD ) */ + } /* end for */ + + /* mark the last RFD as the last one in the RDL */ + uti596_softc.pEndRFA -> cmd = CMD_EOL; + uti596_softc.pSavedRfdQueue = + uti596_softc.pEndSavedQueue = I596_NULL; /* initially empty */ + + uti596_softc.savedCount = 0; + uti596_softc.nop.cmd.command = CmdNOp; /* initialize the nop command */ + + return (i); /* the number of allocated buffers */ +} - /*********************************************************************** - * Function: uti596_DynamicInterruptHandler - * - * Description: - * This is the interrupt handler for the uti596 board - * - * Algorithm: - * - ***********************************************************************/ -/* static */ rtems_isr uti596_DynamicInterruptHandler( - rtems_vector_number irq +/* + * uti596_initMem + * + * Initialize the 82596 memory structures for Tx and Rx + * dynamically allocate mem for the number of tbd's required + * + * Input parameters: + * sc - a pointer to the uti596_softc struct + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_initMem( + uti596_softc_ * sc ) { -#ifdef DEBUG_ISR - printk(("uti596_DynamicInterruptHandler: begins")) -#endif - - UTI_WAIT_COMMAND_ACCEPTED(20000,"****ERROR:on ISR entry"); + int i; - scbStatus = uti596_softc.scb.status & 0xf000; + #ifdef DBG_INIT + printk(("uti596_initMem: begins\n")) + #endif - if ( scbStatus ) { - /* acknowledge interrupts */ - - /* Write to the ICLR bit in the PCCchip2 control registers to clear - * the INT status bit. Clearing INT here *before* sending the CA signal - * to the 82596 should ensure that interrupts won't be lost. - */ - pccchip2->LANC_int_ctl |=0x08; - pccchip2->LANC_berr_ctl |=0x08; - - /* printk(("***INFO: ACK %x\n", scbStatus))*/ - - /* Send the CA signal to acknowledge interrupt */ - uti596_softc.scb.command = scbStatus; - i82596->chan_attn = 0x00000000; + sc->resetDone = 0; - if( uti596_softc.resetDone ) { - /* stack is attached */ - UTI_WAIT_COMMAND_ACCEPTED(20000,"****ERROR:ACK"); - } - else { - /* printk(("***INFO: ACK'd w/o processing. status = %x\n", scbStatus)) */ - return; - } - } - else { - printk(("\n***ERROR: Spurious interrupt. Resetting...\n")) - uti596_softc.nic_reset = 1; + /* + * Set up receive frame area (RFA) + */ + i = uti596_initRFA( sc->rxBdCount ); + if ( i < sc->rxBdCount ) { + printk(("init_rfd: only able to allocate %d receive frame descriptors\n", i)) } + + /* + * Write the SCB with a pointer to the receive frame area + * and keep a pointer for our use. + */ + sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA); + sc->scb.pRfd = sc->pBeginRFA; + /* + * Diagnose the health of the board + */ + uti596_diagnose(); - if ( (scbStatus & SCB_STAT_CX) && !(scbStatus & SCB_STAT_CNA) ){ - printk_time(); - printk(("\n*****ERROR: Command Complete, and CNA available: 0x%x\nResetting...", scbStatus)) - uti596_softc.nic_reset = 1; - return; - } + /* + * Configure the 82596 + */ + uti596_configure( sc ); - if ( !(scbStatus & SCB_STAT_CX) && (scbStatus & SCB_STAT_CNA) ) { - printk_time(); - printk(("\n*****ERROR: CNA, NO CX:0x%x\nResetting...",scbStatus)) - uti596_softc.nic_reset = 1; - return; - } + /* + * Set up the Individual (hardware) Address + */ + uti596_IAsetup ( sc ); - if ( scbStatus & SCB_CUS_SUSPENDED ) { - printk_time(); - printk(("\n*****ERROR: Command unit suspended!:0x%x\nResetting...",scbStatus)) - uti596_softc.nic_reset = 1; - return; - } + /* + * Initialize the transmit buffer descriptors + */ + uti596_initTBD( sc ); - if ( scbStatus & RU_SUSPENDED ) { - printk_time(); - printk(("\n*****ERROR: Receive unit suspended!:0x%x\nResetting...",scbStatus)) - uti596_softc.nic_reset = 1; - return; - } + /* Padding used to fill short tx frames */ + memset ( &sc->zeroes, 0, 64); - if ( scbStatus & SCB_STAT_RNR ) { - printk_time(); - printk(("\n*****WARNING: RNR %x\n",scbStatus)) - if (uti596_softc.pBeginRFA != I596_NULL) { - printk(("*****INFO: RFD cmd: %x status:%x\n", uti596_softc.pBeginRFA->cmd, - uti596_softc.pBeginRFA->stat)) - } - else { - printk(("*****WARNING: RNR condition with NULL BeginRFA\n")) - } - } + /* now need ISR */ + sc->resetDone = 1; +} - /* - * Receive Unit Control - * a frame is received - */ - if ( scbStatus & SCB_STAT_FR ) { - uti596_softc.rxInterrupts++; - -#ifdef DBG_FR - printk(("uti596_DynamicInterruptHandler: Frame received\n")) -#endif - if ( uti596_softc.pBeginRFA == I596_NULL || - !( uti596_softc.pBeginRFA -> stat & STAT_C)) { - dump_scb(); - uti596_softc.nic_reset = 1; - } - else { - while ( uti596_softc.pBeginRFA != I596_NULL && - ( uti596_softc.pBeginRFA -> stat & STAT_C)) { +/* + * uti596_initialize + * + * Reset the 82596 and initialize it with a new SCP. + * + * Input parameters: + * sc - pointer to the uti596_softc + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_initialize( + uti596_softc_ *sc +) +{ + /* Reset the device. Stops it from doing whatever it might be doing. */ + uti596_portReset(); -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: pBeginRFA != NULL\n")) -#endif - count_rx ++; - if ( count_rx > 1) { - printk(("****WARNING: Received 2 frames on 1 interrupt \n")) - } - /* Give Received Frame to the ULCS */ - uti596_softc.countRFD--; + /* Get a new System Configuration Pointer */ + uti596_scp_alloc( sc ); - if ( uti596_softc.countRFD < 0 ) { - printk(("ISR: Count < 0 !!! count == %d, beginRFA = %p\n", - uti596_softc.countRFD, uti596_softc.pBeginRFA)) - } - uti596_softc.stats.rx_packets++; - /* the rfd next link is stored with upper and lower words swapped so read it that way */ - pIsrRfd = (i596_rfd *) word_swap ((unsigned long)uti596_softc.pBeginRFA->next); - /* the append destroys the link */ - uti596append( &uti596_softc.pInboundFrameQueue , uti596_softc.pBeginRFA ); + /* write the SYSBUS: interrupt pin active high, LOCK disabled, + * internal triggering, linear mode + */ + sc->pScp->sysbus = 0x54; + + /* provide the iscp to the scp, keep a pointer for our use */ + sc->pScp->iscp_pointer = word_swap((unsigned long)&sc->iscp); + sc->pScp->iscp = &sc->iscp; - /* - * if we have just received the a frame in the last unknown RFD, - * then it is certain that the RFA is empty. - */ - if ( uti596_softc.pLastUnkRFD == uti596_softc.pBeginRFA ) { - UTI_596_ASSERT(uti596_softc.pLastUnkRFD != I596_NULL,"****ERROR:LastUnk is NULL, begin ptr @ end!\n") - uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD = I596_NULL; - } + /* provide the scb to the iscp, keep a pointer for our use */ + sc->iscp.scb_pointer = word_swap((unsigned long)&sc->scb); + sc->iscp.scb = &sc->scb; -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: Wake %#x\n",uti596_softc.rxDaemonTid)) -#endif - sc = rtems_event_send(uti596_softc.rxDaemonTid, INTERRUPT_EVENT); - if ( sc != RTEMS_SUCCESSFUL ) { - rtems_panic("Can't notify rxDaemon: %s\n", - rtems_status_text (sc)); - } -#ifdef DBG_RAW_ISR - else { - printk(("uti596_DynamicInterruptHandler: Rx Wake: %#x\n",uti596_softc.rxDaemonTid)) - } -#endif + #ifdef DBG_INIT + printk(("uti596_initialize: Starting i82596.\n")) + #endif - uti596_softc.pBeginRFA = pIsrRfd; - } /* end while */ - } /* end if */ + /* Set up the 82596 */ + uti596_setScpAndScb( sc ); + + /* clear the scb command word */ + sc->scb.command = 0; +} - if ( uti596_softc.pBeginRFA == I596_NULL ) { - /* adjust the pEndRFA to reflect an empty list */ - if ( uti596_softc.pLastUnkRFD == I596_NULL && uti596_softc.countRFD != 0 ) { - printk(("Last Unk is NULL, BeginRFA is null, and count == %d\n", - uti596_softc.countRFD)) - } - uti596_softc.pEndRFA = I596_NULL; - if ( uti596_softc.countRFD != 0 ) { - printk(("****ERROR:Count is %d, but begin ptr is NULL\n", - uti596_softc.countRFD )) - } - } - } /* end if ( scbStatus & SCB_STAT_FR ) */ +/* + * uti596_initialize_hardware + * + * Reset the 82596 and initialize it with a new SCP. Enable bus snooping. + * Install the interrupt handlers. + * + * Input parameters: + * sc - pointer to the uti596_softc + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_initialize_hardware( + uti596_softc_ *sc +) +{ + rtems_isr_entry dummy; - /* - * Command Unit Control - * a command is completed - */ - if ( scbStatus & SCB_STAT_CX ) { -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: CU\n")) -#endif + printk(("uti596_initialize_hardware: begins\n")) - pIsrCmd = uti596_softc.pCmdHead; + /* Get the PCCChip2 to assert bus snooping signals on behalf of the i82596 */ + pccchip2->LANC_berr_ctl = 0x40; - /* For ALL completed commands */ - if ( pIsrCmd != I596_NULL && pIsrCmd->status & STAT_C ) { + uti596_initialize( sc ); + + /* + * Configure interrupt control in PCCchip2 + */ + pccchip2->LANC_error = 0xff; /* clear status register */ + pccchip2->LANC_int_ctl = 0x5d; /* lvl 5, enabled, edge-sensitive rising */ + pccchip2->LANC_berr_ctl = 0x5d; /* bus error: lvl 5, enabled, snoop control + * will supply dirty data and leave dirty data + * on read access and sink any data on write + */ + /* + * Install the interrupt handler + * calls rtems_interrupt_catch + */ + dummy = (rtems_isr_entry) set_vector( uti596_DynamicInterruptHandler, 0x57, 1 ); -#ifdef DBG_RAW_ISR - printk(("uti596_DynamicInterruptHandler: pIsrCmd != NULL\n")) -#endif + /* Initialize the 82596 memory */ + uti596_initMem(sc); - /* Adjust the command block list */ - uti596_softc.pCmdHead = (i596_cmd *) word_swap ((unsigned long)pIsrCmd->next); + #ifdef DBG_INIT + printk(("uti596_initialize_hardware: After attach, status of board = 0x%x\n", sc->scb.status )) + #endif +} - /* - * If there are MORE commands to process, - * the serialization in the raw routine has failed. - * ( Perhaps AddCmd is bad? ) - */ - UTI_596_ASSERT(uti596_softc.pCmdHead == I596_NULL, "****ERROR: command serialization failed\n") - - /* What if the command did not complete OK? */ - switch ( pIsrCmd->command & 0x7) { - case CmdConfigure: - /* printk(("****INFO:Configure OK\n")) */ - uti596_softc.cmdOk = 1; - break; +/* + * uti596_reset_hardware + * + * Reset the 82596 and initialize it with an SCP. + * + * Input parameters: + * sc - pointer to the uti596_softc + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_reset_hardware( + uti596_softc_ *sc +) +{ + rtems_status_code status_code; + i596_cmd *pCmd; - case CmdDump: -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: dump!\n")) -#endif - uti596_softc.cmdOk = 1; - break; + pCmd = sc->pCmdHead; /* This is a tx command for sure (99.99999%) */ - case CmdDiagnose: -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: diagnose!\n")) -#endif - uti596_softc.cmdOk = 1; - break; + /* the command block list (CBL) is empty */ + sc->scb.cmd_pointer = (unsigned long) I596_NULL; /* all 1's */ + sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */ - case CmdSASetup: - /* printk(("****INFO:Set address interrupt\n")) */ - if ( pIsrCmd -> status & STAT_OK ) { - uti596_softc.cmdOk = 1; - } - else { - printk(("****ERROR:SET ADD FAILED\n")) - } - break; + #ifdef DBG_RESET + printk(("uti596_reset_hardware\n")) + #endif + uti596_initialize( sc ); + + /* + * Wake the transmitter if needed. + */ + if ( sc->txDaemonTid && pCmd != I596_NULL ) { + printk(("****RESET: wakes transmitter!\n")) + status_code = rtems_event_send (sc->txDaemonTid, + INTERRUPT_EVENT); - case CmdTx: - UTI_596_ASSERT(uti596_softc.txDaemonTid, "****ERROR:Null txDaemonTid\n") -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: wake TX:0x%x\n",uti596_softc.txDaemonTid)) -#endif - if ( uti596_softc.txDaemonTid ) { - /* Ensure that the transmitter is present */ - sc = rtems_event_send (uti596_softc.txDaemonTid, - INTERRUPT_EVENT); + if ( status_code != RTEMS_SUCCESSFUL ) { + printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n", + sc->txDaemonTid, rtems_status_text (status_code) )) + } + } - if ( sc != RTEMS_SUCCESSFUL ) { - printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n", - uti596_softc.txDaemonTid, rtems_status_text (sc) )) - } -#ifdef DBG_RAW_ISR - else { - printk(("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid)) - } -#endif - } - break; + #ifdef DBG_RESET + printk(("uti596_reset_hardware: After reset_hardware, status of board = 0x%x\n", sc->scb.status )) + #endif +} - case CmdMulticastList: - printk(("***ERROR:Multicast?!\n")) - pIsrCmd->next = I596_NULL; - break; - case CmdTDR: { - unsigned long status = *( (unsigned long *)pIsrCmd)+1; - printk(("****ERROR:TDR?!\n")) - - if (status & STAT_C) { - /* mark the TDR command successful */ - uti596_softc.cmdOk = 1; - } - else { - if (status & 0x4000) { - printk(("****WARNING:Transceiver problem.\n")) - } - if (status & 0x2000) { - printk(("****WARNING:Termination problem.\n")) - } - if (status & 0x1000) { - printk(("****WARNING:Short circuit.\n")) - /* printk(("****INFO:Time %ld.\n", status & 0x07ff)) */ - } - } - } - break; +/* + * uti596_clearListStatus + * + * Clear the stat fields for all RFDs + * + * Input parameters: + * pRfd - a pointer to the head of the RFA + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_clearListStatus( + i596_rfd *pRfd +) +{ + while ( pRfd != I596_NULL ) { + pRfd -> stat = 0; + pRfd = (i596_rfd *) word_swap((unsigned long)pRfd-> next); + } +} - default: { - /* - * This should never be reached - */ - printk(("CX but NO known command\n")) - } - } /* end switch */ - pIsrCmd = uti596_softc.pCmdHead; /* next command */ - if ( pIsrCmd != I596_NULL ) { - printk(("****WARNING: more commands in list, but no start to NIC\n")) - } - } /* end if pIsrCmd != NULL && pIsrCmd->stat & STAT_C */ - - else { - if ( pIsrCmd != I596_NULL ) { - /* The command MAY be NULL from a RESET */ - /* Reset the ethernet card, and wake the transmitter (if necessary) */ - printk_time(); - printk(("****INFO: Request board reset ( tx )\n")) - uti596_softc.nic_reset = 1; - if ( uti596_softc.txDaemonTid) { - /* Ensure that a transmitter is present */ - sc = rtems_event_send (uti596_softc.txDaemonTid, - INTERRUPT_EVENT); - if ( sc != RTEMS_SUCCESSFUL ) { - printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n",uti596_softc.txDaemonTid, rtems_status_text (sc) )) - } -#ifdef DBG_RAW_ISR - else { - printk(("uti596_DynamicInterruptHandler: ****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid)) - } -#endif - } - } - } - } /* end if command complete */ +/* + * uti596_reset + * + * Reset the 82596 and reconfigure + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_reset( void ) +{ + uti596_softc_ *sc = &uti596_softc; + #ifdef DBG_RESET + printk(("uti596_reset: begin\n")) + #endif - /* - * If the receiver has stopped, - * check if this is a No Resources scenario, - * Try to add more RFD's ( no RBDs are used ) - */ - if ( uti596_softc.started ) { - if ( scbStatus & SCB_STAT_RNR ) { -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: INFO:RNR: status %#x \n", uti596_softc.scb.status )) -#endif - /* - * THE RECEIVER IS OFF! - */ - if ( uti596_softc.pLastUnkRFD != I596_NULL ) { - /* We have an unknown RFD, it is not inbound */ - if ( uti596_softc.pLastUnkRFD -> stat & (STAT_C | STAT_B )) { /* in use */ - uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD; /* update end */ - } - else { - /* - * It is NOT in use, and since RNR, we know EL bit of pEndRFA was read! - * So, unlink it from the RFA and move it to the saved queue. - * But pBegin can equal LastUnk! - */ + /* Wait for the CU to be available, then + * reset the ethernet hardware. Must re-config. + */ + sc->resetDone = 0; + uti596_wait ( sc, UTI596_WAIT_FOR_CU_ACCEPT ); + uti596_reset_hardware ( &uti596_softc ); - if ( uti596_softc.pEndRFA != I596_NULL ) { - /* check added feb24. */ -#ifdef DEBUG_RFA - if ((i596_rfd *)word_swap((unsigned long)uti596_softc.pEndRFA->next) != uti596_softc.pLastUnkRFD) { - printk(("***ERROR:UNK: %p not end->next: %p, end: %p\n", - uti596_softc.pLastUnkRFD, - uti596_softc.pEndRFA -> next, - uti596_softc.pEndRFA)) - printk(("***INFO:countRFD now %d\n", - uti596_softc.countRFD)) - printk(("\n\n")) - } -#endif - uti596_softc.pEndRFA -> next = I596_NULL; /* added feb 16 */ - } - uti596append( &uti596_softc.pSavedRfdQueue, uti596_softc.pLastUnkRFD ); - uti596_softc.savedCount++; - uti596_softc.pEndSavedQueue = uti596_softc.pLastUnkRFD; - uti596_softc.countRFD--; /* It was not in the RFA */ - /* - * The Begin pointer CAN advance this far. We must resynch the CPU side - * with the chip. - */ - if ( uti596_softc.pBeginRFA == uti596_softc.pLastUnkRFD ) { -#ifdef DEBUG_RFA - if ( uti596_softc.countRFD != 0 ) { - printk(("****INFO:About to set begin to NULL, with count == %d\n\n", - uti596_softc.countRFD )) - } -#endif - uti596_softc.pBeginRFA = I596_NULL; - UTI_596_ASSERT(uti596_softc.countRFD == 0, "****ERROR:Count must be zero here!\n") - } - } - uti596_softc.pLastUnkRFD = I596_NULL; - } /* end if exists UnkRFD */ + #ifdef DBG_RESET + uti596_diagnose(); + #endif - /* - * Append the saved queue to the RFA. - * Any further RFD's being supplied will be added to - * this new list. - */ - if ( uti596_softc.pSavedRfdQueue != I596_NULL ) { - /* entries to add */ - if ( uti596_softc.pBeginRFA == I596_NULL ) { - /* add at beginning to list */ -#ifdef DEBUG_RFA - if(uti596_softc.countRFD != 0) { - printk(("****ERROR:Begin pointer is NULL, but count == %d\n", - uti596_softc.countRFD)) - } -#endif - uti596_softc.pBeginRFA = uti596_softc.pSavedRfdQueue; - uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; - uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ - } - else { -#ifdef DEBUG_RFA - if ( uti596_softc.countRFD <= 0) { - printk(("****ERROR:Begin pointer is not NULL, but count == %d\n", - uti596_softc.countRFD)) - } -#endif - UTI_596_ASSERT( uti596_softc.pEndRFA != I596_NULL, "****WARNING: END RFA IS NULL\n") - UTI_596_ASSERT( uti596_softc.pEndRFA->next == I596_NULL, "****ERROR:END RFA -> next must be NULL\n") + /* + * Configure the 82596 + */ + uti596_configure( sc ); - uti596_softc.pEndRFA->next = (i596_rfd *)word_swap((unsigned long)uti596_softc.pSavedRfdQueue); - uti596_softc.pEndRFA->cmd &= ~CMD_EOL; /* clear the end of list */ - uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; - uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ -#ifdef DEBUG_ISR - printk(("uti596_DynamicInterruptHandler: count... %d, saved ... %d \n", - uti596_softc.countRFD, - uti596_softc.savedCount)) -#endif - } - /* printk(("Isr: countRFD = %d\n",uti596_softc.countRFD)) */ - uti596_softc.countRFD += uti596_softc.savedCount; - /* printk(("Isr: after countRFD = %d\n",uti596_softc.countRFD)) */ - uti596_softc.savedCount = 0; - } + /* + * Set up the Individual (hardware) Address + */ + uti596_IAsetup ( sc ); -#ifdef DBG_596_RFD - printk(("uti596_DynamicInterruptHandler: The list starts here %p\n",uti596_softc.pBeginRFA )) -#endif + sc->pCmdHead = sc->pCmdTail = sc->scb.pCmd = I596_NULL; - if ( uti596_softc.countRFD > 1) { - printk_time(); - printk(("****INFO: pBeginRFA -> stat = 0x%x\n",uti596_softc.pBeginRFA -> stat)) - printk(("****INFO: pBeginRFA -> cmd = 0x%x\n",uti596_softc.pBeginRFA -> cmd)) - uti596_softc.pBeginRFA -> stat = 0; - UTI_596_ASSERT(uti596_softc.scb.command == 0, "****ERROR:scb command must be zero\n") - uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; - uti596_softc.scb.Rfd_val = word_swap((unsigned long)uti596_softc.pBeginRFA); - /* start RX here */ - printk(("****INFO: ISR Starting receiver\n")) - uti596_softc.scb.command = RX_START; /* should this also be CU start? */ - i82596->chan_attn = 0x00000000; - } - } /* end stat_rnr */ - } /* end if receiver started */ -#ifdef DBG_ISR - printk(("uti596_DynamicInterruptHandler: X\n")) -#endif - count_rx=0; - - - /* Do this last, to ensure that the reset is called at the right time. */ - if ( uti596_softc.nic_reset ) { - uti596_softc.nic_reset = 0; - sc = rtems_event_send(uti596_softc.resetDaemonTid, NIC_RESET_EVENT); - if ( sc != RTEMS_SUCCESSFUL ) - rtems_panic ("Can't notify resetDaemon: %s\n", rtems_status_text (sc)); + /* restore the RFA */ + + if ( sc->pLastUnkRFD != I596_NULL ) { + sc-> pEndRFA = sc->pLastUnkRFD; /* The end position can be updated */ + sc-> pLastUnkRFD = I596_NULL; } - return; -} -/*********************************************************************** - * Function: uti596_ioctl - * - * Description: - * driver ioctl function - * handles SIOCGIFADDR, SIOCSIFADDR, SIOCSIFFLAGS - * - * Algorithm: - * - ***********************************************************************/ - -static int uti596_ioctl( - struct ifnet *ifp, - int command, caddr_t data -) -{ - uti596_softc_ *sc = ifp->if_softc; - int error = 0; + sc->pEndRFA->next = sc->pSavedRfdQueue; + if ( sc->pSavedRfdQueue != I596_NULL ) { + sc->pEndRFA = sc->pEndSavedQueue; + sc->pSavedRfdQueue = sc->pEndSavedQueue = I596_NULL; + sc -> countRFD = sc->rxBdCount ; + } -#ifdef DBG_INIT - printk(("uti596_ioctl: begins\n", sc->pScp)) -#endif + /* Re-address the head of the RFA in the SCB */ + sc->scb.pRfd = sc->pBeginRFA; + sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA); - switch (command) { - case SIOCGIFADDR: - case SIOCSIFADDR: - printk(("SIOCSIFADDR\n")) - ether_ioctl (ifp, command, data); - break; + /* Clear the status of all RFDs */ + uti596_clearListStatus( sc->pBeginRFA ); - case SIOCSIFFLAGS: - printk(("SIOCSIFFLAGS\n")) - switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { - case IFF_RUNNING: - printk(("IFF_RUNNING\n")) - uti596_stop (sc); - break; + printk(("uti596_reset: Starting NIC\n")) - case IFF_UP: - printk(("IFF_UP\n")) - uti596_init (sc); - break; + /* Start the receiver */ + sc->scb.command = RX_START; + sc->started = 1; /* assume that the start is accepted */ + sc->resetDone = 1; + uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT ); + + UTI_596_ASSERT(sc->pCmdHead == I596_NULL, "Reset: CMD not cleared\n") - case IFF_UP | IFF_RUNNING: - printk(("IFF_UP and RUNNING\n")) - uti596_stop (sc); - uti596_init (sc); - break; + #ifdef DBG_RESET + printk(("uti596_reset: completed\n")) + #endif +} - default: - printk(("default\n")) - break; - } - break; - case SIO_RTEMS_SHOW_STATS: - printk(("show stats\n")) - uti596_stats (sc); - break; +/* + * uti596_dequeue + * + * Remove an RFD from the received fram queue + * + * Input parameters: + * ppQ - a pointer to a i596_rfd pointer + * + * Output parameters: NONE + * + * Return value: + * pRfd - a pointer to the dequeued RFD + */ +i596_rfd * uti596_dequeue( + i596_rfd ** ppQ +) +{ + ISR_Level level; + i596_rfd * pRfd; + + _ISR_Disable(level); - /* FIXME: All sorts of multicast commands need to be added here! */ - default: - printk(("default: EINVAL\n")) - error = EINVAL; - break; + /* invalid address, or empty queue or emptied queue */ + if( ppQ == NULL || *ppQ == NULL || *ppQ == I596_NULL) { + _ISR_Enable(level); + return I596_NULL; } - return error; + /* + * Point to the dequeued buffer, then + * adjust the queue pointer and detach the buffer + */ + pRfd = *ppQ; + *ppQ = (i596_rfd *) word_swap ((unsigned long) pRfd->next); + pRfd->next = I596_NULL; /* unlink the rfd being returned */ + + _ISR_Enable(level); + return pRfd; } -/*********************************************************************** - * Function: uti596_stats - * - * Description: - * print out the collected data + +/* + * uti596_append + * + * Remove an RFD buffer from the RFA and tack it on to + * the received frame queue for processing. + * + * Input parameters: + * ppQ - a pointer to the queue pointer + * pRfd - a pointer to the buffer to be returned * - * Algorithm: - * use printf + * Output parameters: NONE * - ***********************************************************************/ + * Return value: NONE + */ -void uti596_stats( - uti596_softc_ *sc +void uti596_append( + i596_rfd ** ppQ, + i596_rfd * pRfd ) { - printf("CPU Reports:\n"); - printf (" Tx raw send count:%-8lu", sc->rawsndcnt); - printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); - printf (" Tx Interrupts:%-8lu\n", sc->txInterrupts); - printf (" Rx Packets:%-8u", sc->stats.rx_packets); - printf (" Tx Attempts:%-u\n", sc->stats.tx_packets); - - printf (" Rx Dropped:%-8u", sc->stats.rx_dropped); - printf (" Rx IP Packets:%-8u", sc->stats.rx_packets); - printf (" Tx Errors:%-8u\n", sc->stats.tx_errors); - printf (" Tx aborted:%-8u", sc->stats.tx_aborted_errors); - printf (" Tx Dropped:%-8u\n", sc->stats.tx_dropped); - printf (" Tx IP packets:%-8u", sc->stats.tx_packets); - - printf (" Collisions Detected:%-8u\n", sc->stats.collisions); - printf (" Tx Heartbeat Errors:%-8u", sc->stats.tx_heartbeat_errors); - printf (" Tx Carrier Errors:%-8u\n", sc->stats.tx_carrier_errors); - printf (" Tx Aborted Errors:%-8u", sc->stats.tx_aborted_errors); - printf (" Rx Length Errors:%-8u\n", sc->stats.rx_length_errors); - printf (" Rx Overrun Errors:%-8u", sc->stats.rx_over_errors); - printf (" Rx Fifo Errors:%-8u\n", sc->stats.rx_fifo_errors); - printf (" Rx Framing Errors:%-8u", sc->stats.rx_frame_errors); - printf (" Rx crc errors:%-8u\n", sc->stats.rx_crc_errors); - printf (" TX WAITS: %-8lu\n", sc->txRawWait); + i596_rfd *p; - printf (" NIC resets: %-8u\n", sc->stats.nic_reset_count); + if ( pRfd != NULL && pRfd != I596_NULL) { + pRfd -> next = I596_NULL; + pRfd -> cmd |= CMD_EOL; /* set EL bit */ - printf(" NIC reports\n"); + if ( *ppQ == NULL || *ppQ == I596_NULL ) { + /* empty list */ + *ppQ = pRfd; + } + else { + /* walk to the end of the list */ + for ( p=*ppQ; + p->next != I596_NULL; + p=(i596_rfd *) word_swap ((unsigned long)p->next) ); - dump_scb(); + /* append the rfd */ + p->cmd &= ~CMD_EOL; /* Clear EL bit at end */ + p->next = (i596_rfd *) word_swap ((unsigned long)pRfd); + } + } + else { + printk(("Illegal attempt to append: %p\n", pRfd)) + } } -/*********************************************************************** - *************************** LOCAL ROUTINES **************************** - ***********************************************************************/ - - -/*********************************************************************** - * Function: void uti596_initialize_hardware +/* + * uti596_supplyFD + * + * Return a buffer (RFD) to the receive frame area (RFA). + * Call with interrupts disabled. + * + * Input parameters: + * pRfd - a pointer to the buffer to be returned * - * Description: - ***********************************************************************/ -void uti596_initialize_hardware( - uti596_softc_ *sc + * Output parameters: NONE + * + * Return value: NONE + */ +void uti596_supplyFD ( + i596_rfd * pRfd ) { - int boguscnt = 1000; - rtems_isr_entry dummy; - - printk(("uti596_initialize_hardware: begins\n")) - - pccchip2->LANC_berr_ctl = 0x40; /* Enable snooping */ - - /* reset the board */ - i82596->port_lower = 0x0000; /* Each Port access must consist of two 16-bit writes */ - i82596->port_upper = 0x0000; - - /* allocate enough memory for the Scp block to be aligned on 16 bit boundary */ - uti596_softc.pScp = (i596_scp *) calloc(1,sizeof(struct i596_scp) + 0xf); - -#ifdef DBG_INIT - printk(("uti596_initialize_hardware: Scp address initially %p\n", sc->pScp)) -#endif - - /* align the block */ - sc->pScp = (i596_scp *) - ((((int)uti596_softc.pScp) + 0xf) & 0xfffffff0); - -#ifdef DBG_INIT - printk(("uti596_initialize_hardware: change scp address to : %p\n",sc->pScp)) -#endif - - /* change the scp address */ -#ifdef DBG_INIT - printk(("uti596_initialize_hardware: Change the SCP address\n")) -#endif - - /* reset the board */ - i82596->port_lower = 0x0000; - i82596->port_upper = 0x0000; - - /* supply the Scp address - * Lower Command Word D31-D16; Upper Command Word D15-D0 - */ - i82596->port_lower = (((int)sc->pScp) & 0xfff0) | 0x0002; - i82596->port_upper = (((int)sc->pScp) >> 16 ) & 0xffff; + i596_rfd *pLastRfd; - - /* write the SYSBUS: interrupt pin active high, LOCK disabled, - * internal triggering, linear mode - */ - sc->pScp->sysbus = word_swap(0x00540000); - - /* provide the iscp to the scp, keep a pointer for our use */ - sc->pScp->iscp_val = word_swap((unsigned long)&sc->iscp); - sc->pScp->iscp = &sc->iscp; + UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD!\n") + + pRfd -> cmd = CMD_EOL; + pRfd -> pRbd = I596_NULL; + pRfd -> next = I596_NULL; + pRfd -> stat = 0x0000; /* clear STAT_C and STAT_B bits */ - /* provide the scb to the iscp, keep a pointer for our use */ - sc->iscp.scb_val = word_swap((unsigned long)&sc->scb); - sc->iscp.scb = &sc->scb; + /* + * Check if the list is empty: + */ + if ( uti596_softc.pBeginRFA == I596_NULL ) { - /* set the busy flag in the iscp */ - sc->iscp.stat = word_swap(0x00000001); + /* Start a list with one entry */ + uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; + UTI_596_ASSERT(uti596_softc.countRFD == 0, "Null begin, but non-zero count\n") + if ( uti596_softc.pLastUnkRFD != I596_NULL ) { + printk(("LastUnkRFD is NOT NULL!!\n")) + } + uti596_softc.countRFD = 1; + return; + } + + /* + * Check if the last RFD is used/read by the 596. + */ + pLastRfd = uti596_softc.pEndRFA; - /* the command block list (CBL) is empty */ - sc->scb.Cmd_val = (unsigned long) I596_NULL; /* all 1's */ - sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */ + /* C = complete, B = busy (prefetched) */ + if ( pLastRfd != I596_NULL && ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) { + + /* + * Not yet too late to add it + */ + pLastRfd -> next = (i596_rfd *) word_swap ((unsigned long)pRfd); + pLastRfd -> cmd &= ~CMD_EOL; /* RESET_EL : reset EL bit to 0 */ + uti596_softc.countRFD++; /* Lets assume we add it successfully + If not, the RFD may be used, and may + decrement countRFD < 0 !! */ + /* + * Check if the last RFD was used while appending. + */ + if ( pLastRfd -> stat & ( STAT_C | STAT_B ) ) { /* completed or was prefetched */ + /* + * Either the EL bit of the last rfd has been read by the 82596, + * and it will stop after reception,( true when RESET_EL not reached ) or + * the EL bit was NOT read by the 82596 and it will use the linked + * RFD for the next reception. ( true when RESET_EL was reached ) + * So, it is unknown whether or not the linked rfd will be used. + * Therefore, the end of list CANNOT be updated. + */ + UTI_596_ASSERT ( uti596_softc.pLastUnkRFD == I596_NULL, "Too many Unk RFD's\n" ) + uti596_softc.pLastUnkRFD = pRfd; + return; + } + else { + /* + * The RFD being added was not touched by the 82596 + */ + if (uti596_softc.pLastUnkRFD != I596_NULL ) { -#ifdef DBG_596 - printk(("uti596_initialize_hardware: Starting i82596.\n")) -#endif + uti596_append(&uti596_softc.pSavedRfdQueue, pRfd); /* Only here! saved Q */ + uti596_softc.pEndSavedQueue = pRfd; + uti596_softc.savedCount++; + uti596_softc.countRFD--; - /* Issue CA: pass the scb address to the 596 */ - i82596->chan_attn = 0x00000000; + } + else { + + uti596_softc.pEndRFA = pRfd; /* the RFA has been extended */ + + if ( ( uti596_softc.scb.status & SCB_STAT_RNR || + uti596_softc.scb.status & RU_NO_RESOURCES ) && + uti596_softc.countRFD > 1 ) { + + /* Ensure that beginRFA is not EOL */ + uti596_softc.pBeginRFA -> cmd &= ~CMD_EOL; - UTI_WAIT_TICKS + UTI_596_ASSERT(uti596_softc.pEndRFA -> next == I596_NULL, "supply: List buggered\n") + UTI_596_ASSERT(uti596_softc.pEndRFA -> cmd & CMD_EOL, "supply: No EOL at end.\n") + UTI_596_ASSERT(uti596_softc.scb.command == 0, "Supply: scb command must be zero\n") - /* Wait for the 596 to read the SCB address and clear 'stat' */ - while (sc->iscp.stat) { - if (--boguscnt == 0) { - printk(("initialize_hardware: timed out with status %4.4lx\n", - sc->iscp.stat )) - break; - } - } /* end while */ + #ifdef DBG_MEM + printk(("uti596_supplyFD: starting receiver")) + #endif - /* clear the scb command word */ - sc->scb.command = 0; - - /* - * Configure interrupt control in PCCchip2 - */ - pccchip2->LANC_error = 0xff; /* clear status register */ - pccchip2->LANC_int_ctl = 0x5d; /* lvl 5, enabled, edge-sensitive rising */ - pccchip2->LANC_berr_ctl = 0x5d; /* bus error: lvl 5, enabled, snoop control - * will supply dirty data and leave dirty data - * on read access and sink any data on write - */ + /* start the receiver */ + UTI_596_ASSERT(uti596_softc.pBeginRFA != I596_NULL, "rx start w/ NULL begin! \n") + uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; + uti596_softc.scb.rfd_pointer = word_swap ((unsigned long) uti596_softc.pBeginRFA); + + /* Don't ack RNR! The receiver should be stopped in this case */ + uti596_softc.scb.command = RX_START | SCB_STAT_RNR; + + UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n") - /* - * Install the interrupt handler - * calls rtems_interrupt_catch - */ - dummy = (rtems_isr_entry) set_vector( uti596_DynamicInterruptHandler, 0x57, 1 ); - + /* send CA signal */ + uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT ); + } + } + return; + } + } + else { + /* + * too late , pLastRfd in use ( or NULL ), + * in either case, EL bit has been read, and RNR condition will occur + */ + uti596_append( &uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */ - /* Initialize the 82596 memory */ - uti596_initMem(sc); + uti596_softc.pEndSavedQueue = pRfd; /* reset end of saved queue */ + uti596_softc.savedCount++; -#ifdef DBG_INIT - printk(("uti596_initialize_hardware: After attach, status of board = 0x%x\n", sc->scb.status )) -#endif + return; + } } -/*********************************************************************** - * Function: uti596_initMem - * - * Description: - * creates the necessary descriptors for the - * uti596 board, hooks the interrupt, and starts the board. - * Assumes that interrupts are hooked. + +/* + * send_packet + * + * Send a raw ethernet packet, add a + * transmit command to the CBL + * + * Input parameters: + * ifp - a pointer to the ifnet structure + * m - a pointer to the mbuf being sent * - * Algorithm: + * Output parameters: NONE * - ***********************************************************************/ - -void uti596_initMem( - uti596_softc_ * sc + * Return value: NONE + */ +void send_packet( + struct ifnet *ifp, struct mbuf *m ) { - int i,count; - i596_tbd *pTbd, *pPrev; - -#ifdef DBG_INIT - printk(("uti596_initMem: begins\n")) -#endif - - sc->resetDone = 0; - - /* - * Set up receive frame area (RFA) - */ -#ifdef DBG_INIT - printk(("uti596_initMem: Initializing the RFA...\n")) -#endif - i = uti596_initRFA( sc->rxBdCount ); - if ( i < sc->rxBdCount ) { - printk(("init_rfd: only able to allocate %d receive frame descriptors\n", i)) - } - - sc->scb.Rfd_val = word_swap((unsigned long)sc->pBeginRFA); - sc->scb.pRfd = sc->pBeginRFA; - - /* - * Diagnose the health of the board - * send the CU a diagnostic command - */ -#ifdef DBG_INIT - printk(("uti596_initMem: Running diagnostics...\n")) -#endif - uti596Diagnose(1); - - /* - * Configure the 82596 - * send the CU a configure command with our initial setup - */ -#ifdef DBG_INIT - printk(("uti596_initMem: Configuring...\n")) -#endif - sc->set_conf.cmd.command = CmdConfigure; - memcpy (sc->set_conf.data, uti596initSetup, 14); - uti596addPolledCmd( (i596_cmd *) &sc->set_conf); - - /* Poll for successful command completion */ - count = 2000; - while( !( sc->set_conf.cmd.status & STAT_C ) && --count ) { - printk((".")) - } - - if ( count ) { - printk(("Configure OK, count = %d\n",count)) - } - else { - printk(("***Configure failed\n")) - } - /* - * Set up the Internet Address - * send the CU an IA-setup command - */ -#ifdef DBG_INIT - printk(("uti596_initMem: Setting Address...\n")) -#endif - sc->set_add.cmd.command = CmdSASetup; - for ( i=0; i<6; i++) { - sc->set_add.data[i]=sc->arpcom.ac_enaddr[i]; -#ifdef DBG_INIT - printk(("uti596_initMem: copying byte %d: 0x%x\n", i, sc->set_add.data[i])) -#endif - } - sc->cmdOk = 0; - uti596addPolledCmd((i596_cmd *)&sc->set_add); + i596_tbd *pPrev = I596_NULL; + i596_tbd *pRemainingTbdList; + i596_tbd *pTbd; + struct mbuf *n, *input_m = m; + uti596_softc_ *sc = ifp->if_softc; + struct mbuf *l = NULL; + unsigned int length = 0; + rtems_status_code status; + int bd_count = 0; + rtems_event_set events; - /* Poll for successful command completion */ - count = 2000; - while( !(sc->set_add.cmd.status & STAT_C ) && --count) { - printk((".")) - } + /* + * For all mbufs in the chain, + * fill a transmit buffer descriptor for each + */ + pTbd = (i596_tbd*) word_swap ((unsigned long)sc->pTxCmd->pTbd); - if ( count ) { - printk(("Set Address OK, count= %d\n",count)) + do { + if (m->m_len) { + /* + * Fill in the buffer descriptor + */ + length += m->m_len; + pTbd->data = (char *) word_swap ((unsigned long) mtod (m, void *)); + pTbd->size = m->m_len; + pPrev = pTbd; + pTbd = (i596_tbd *) word_swap ((unsigned long) pTbd->next); + l = m; + m = m->m_next; } else { - printk(("Set Address Failed\n")) - } -#ifdef DBG_INIT - printk(( "uti596_initMem: After initialization, status and command: 0x%x, 0x%x\n", - sc->scb.status, sc->scb.status)) -#endif + /* + * Just toss empty mbufs + */ + MFREE (m, n); + m = n; + if (l != NULL) + l->m_next = m; + } + } while( m != NULL && ++bd_count < 16 ); - /* - *Initialize transmit buffer descriptors - */ -#ifdef DBG_INIT - printk(( "uti596_initMem:Initializing TBDs...\n")) -#endif - sc->pLastUnkRFD = I596_NULL; - sc->pTxCmd = (i596_tx *) calloc (1,sizeof (struct i596_tx) ); - sc->pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) ); - sc->pTxCmd->pTbd = (i596_tbd *) word_swap ((unsigned long) sc->pTbd); - sc->pTxCmd->cmd.command = CMD_FLEX|CmdTx; - sc->pTxCmd->pad = 0; - sc->pTxCmd->count = 0; /* all bytes are in list of TBD's */ - - pPrev = pTbd = sc->pTbd; - - /* Allocate a linked list of tbd's each with it's 'next' field written - * with upper and lower words swapped (for big endian), and mark the end. - */ - for ( i=0; itxBdCount; i++) { - pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) ); - pPrev->next = (i596_tbd *) word_swap ((unsigned long) pTbd); - pPrev = pTbd; - } - pTbd->next = I596_NULL; - - /* Padding used to fill short tx frames */ - memset ( &sc->zeroes, 0, 64); - -#ifdef DBG_596 - printk(( "uti596_initMem: After receiver start, status and command: 0x%x, 0x%x\n", - sc->scb.status, sc->scb.status)) -#endif + /* This should never happen */ + if ( bd_count == 16 ) { + printk(("TX ERROR:Too many mbufs in the packet!!!\n")) + printk(("Must coalesce!\n")) + } -#ifdef DBG_596 - printk(("uti596_initMem allows ISR's\n")) -#endif - sc->resetDone = 1; /* now need ISR */ -} + if ( length < UTI_596_ETH_MIN_SIZE ) { + pTbd->data = (char *) word_swap ((unsigned long) sc->zeroes); /* add padding to pTbd */ + pTbd->size = UTI_596_ETH_MIN_SIZE - length; /* zeroes have no effect on the CRC */ + } + else /* Don't use pTbd in the send routine */ + pTbd = pPrev; -/*********************************************************************** - * Function: uti596initRFA(int num) - * - * Description: - * attempts to allocate and initialize ( chain together ) - * the requested number of FD's - * - * Algorithm: - * - ***********************************************************************/ + /* Disconnect the packet from the list of Tbd's */ + pRemainingTbdList = (i596_tbd *) word_swap ((unsigned long)pTbd->next); + pTbd->next = I596_NULL; + pTbd->size |= UTI_596_END_OF_FRAME; -int uti596_initRFA( int num ) -{ - i596_rfd *pRfd; - int i = 0; + sc->rawsndcnt++; -#ifdef DBG_596 - printk(("uti596_initRFA: begins\n Requested frame descriptors ... %d.\n", num)) -#endif + #ifdef DBG_SEND + printk(("send_packet: sending packet\n")) + #endif - /* - * Create the first RFD in the RFA - */ - pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd)); - if ( !pRfd ) { - printk(("Can't allocate first buffer.\n")) - return 0; - } - else { - uti596_softc.countRFD = 1; - uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; - printk(("First Rfd allocated @: %p\n", - uti596_softc.pBeginRFA)) - } + /* Sending Zero length packet: shouldn't happen */ + if (pTbd->size <= 0) return; - /* Create remaining RFAs */ - for (i = 1; i < num; i++) { - pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd) ); - if ( pRfd != NULL ) { - uti596_softc.countRFD++; /* update count */ - uti596_softc.pEndRFA->next = - (i596_rfd *) word_swap ((unsigned long) pRfd); /* write the link */ - uti596_softc.pEndRFA = pRfd; /* move the end */ -#ifdef DBG_596_RFA - printk(("uti596_initRFA: Allocated RFD @ %p\n", pRfd)) -#endif - } - else { - printk(("Can't allocate all buffers: only %d allocated\n", i)) - break; - } - } /* end for */ + #ifdef DBG_PACKETS + printk (("\nsend_packet: Transmitter adds packet\n")) + print_hdr ( sc->pTxCmd->pTbd->data ); /* print the first part */ + print_pkt ( sc->pTxCmd->pTbd->next->data ); /* print the first part */ + print_echo (sc->pTxCmd->pTbd->data); + #endif - uti596_softc.pEndRFA->next = I596_NULL; - UTI_596_ASSERT(uti596_softc.countRFD == RX_BUF_COUNT,"INIT:WRONG RFD COUNT\n" ) + /* add the command to the output command queue */ + uti596_addCmd ( (i596_cmd *) sc->pTxCmd ); -#ifdef DBG_596_RFA - printk (("uti596_initRFA: Head of RFA is buffer %p \n\ - uti596_initRFA: End of RFA is buffer %p \n", - uti596_softc.pBeginRFA, - uti596_softc.pEndRFA )) -#endif - /* Initialize the RFD's */ - for ( pRfd = uti596_softc.pBeginRFA; - pRfd != I596_NULL; - pRfd = (i596_rfd *) word_swap ((unsigned long)pRfd->next) ) { - - pRfd->cmd = 0x0000; - pRfd->stat = 0x0000; - pRfd->pRbd = I596_NULL; - pRfd->count = 0; /* number of bytes in buffer: usually less than size */ - pRfd->size = 1532; /* was 1532; buffer size ( All RBD ) */ - if ( pRfd -> data == NULL ) { - printk(("Can't allocate the RFD data buffer\n")) - } - } + /* sleep until the command has been processed or Timeout encountered. */ + status= rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + if ( status != RTEMS_SUCCESSFUL ) { + printk(("Could not sleep %s\n", rtems_status_text(status))) + } + + #ifdef DBG_SEND + printk(("send_packet: RAW - wake\n")) + #endif - /* mark the last RFD as the last one in the RDL */ - uti596_softc.pEndRFA -> cmd = CMD_EOL; + sc->txInterrupts++; - uti596_softc.pSavedRfdQueue = - uti596_softc.pEndSavedQueue = I596_NULL; /* initially empty */ + if ( sc->pTxCmd -> cmd.status & STAT_OK ) { + sc->stats.tx_packets++; + } + else { - uti596_softc.savedCount = 0; + printk(("*** send_packet: Driver Error 0x%x\n", sc->pTxCmd -> cmd.status )) + + sc->stats.tx_errors++; + if ( sc->pTxCmd->cmd.status & 0x0020 ) + sc->stats.tx_retries_exceeded++; + if (!(sc->pTxCmd->cmd.status & 0x0040)) + sc->stats.tx_heartbeat_errors++; + if ( sc->pTxCmd->cmd.status & 0x0400 ) + sc->stats.tx_carrier_errors++; + if ( sc->pTxCmd->cmd.status & 0x0800 ) + sc->stats.collisions++; + if ( sc->pTxCmd->cmd.status & 0x1000 ) + sc->stats.tx_aborted_errors++; + } /* end if stat_ok */ - uti596_softc.nop.cmd.command = CmdNOp; /* initialize the nop command */ + /* + * Restore the transmitted buffer descriptor chain. + */ + pTbd -> next = (i596_tbd *) word_swap ((unsigned long)pRemainingTbdList); - return (i); /* the number of allocated buffers */ + /* + * Free the mbufs used by the sender. + */ + m = input_m; + while ( m != NULL ) { + MFREE(m,n); + m = n; + } } - /*********************************************************************** - * Function: uti596addPolledCmd - * - * Description: - * This routine issues a single command then polls for it's - * completion. - * - * Algorithm: - * Give the command to the driver. ( CUC_START is ALWAYS required ) - * Poll for completion. - * - ***********************************************************************/ - -void uti596addPolledCmd( - i596_cmd *pCmd + +/*********************************************************************** + * Function: uti596_attach + * + * Description: + * Configure the driver, and connect to the network stack + * + * Algorithm: + * + * Check parameters in the ifconfig structure, and + * set driver parameters accordingly. + * Initialize required rx and tx buffers. + * Link driver data structure onto device list. + * Return 1 on successful completion. + * + ***********************************************************************/ + +int uti596_attach( + struct rtems_bsdnet_ifconfig * pConfig ) { + uti596_softc_ *sc = &uti596_softc; /* device dependent data structure */ + struct ifnet * ifp = &sc->arpcom.ac_if; /* ifnet structure */ - #ifdef DBG_596 - printk(("uti596addPolledCmd: Adding command 0x%x\n", pCmd -> command )) - #endif - -#ifdef DBG_POLLED_CMD - - switch ( pCmd -> command & 0x7 ) { /* check bottom 3 bits */ - case CmdConfigure: - printk(("uti596addPolledCmd: Configure Command 0x%x\n", pCmd->command)) - break; - case CmdSASetup: - printk(("uti596addPolledCmd: Set CMDress Command 0x%x\n", pCmd->command)) - break; - case CmdMulticastList: - printk(("uti596addPolledCmd: Multi-cast list 0x%x\n", pCmd->command)) - break; - case CmdNOp: - printk(("uti596addPolledCmd: NO op 0x%x\n", pCmd->command)) - break; - case CmdTDR: - printk(("uti596addPolledCmd: TDR 0x%x\n", pCmd->command)) - break; - case CmdDump: - printk(("uti596addPolledCmd: Dump 0x%x\n", pCmd->command)) - break; - case CmdDiagnose: - printk(("uti596addPolledCmd: Diagnose 0x%x\n", pCmd->command)) - break; - case CmdTx: - break; - default: - printk(("PolledCMD: ****Unknown Command encountered 0x%x\n", pCmd->command)) - break; - } /* end switch */ + int unitNumber; + char *unitName; -#endif + #ifdef DBG_ATTACH + printk(("uti596_attach: begins\n")) + #endif - pCmd->status = 0; - pCmd->command |= CMD_EOL ; /* only command in list*/ + /* The NIC is not started yet */ + sc->started = 0; - pCmd->next = I596_NULL; + /* Indicate to ULCS that this is initialized */ + ifp->if_softc = sc; + sc->pScp = NULL; - UTI_WAIT_COMMAND_ACCEPTED(10000,"Add Polled command: wait prev"); + /* Parse driver name */ + if ((unitNumber = rtems_bsdnet_parse_driver_name (pConfig, &unitName)) < 0) + return 0; - uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd; - uti596_softc.scb.Cmd_val = word_swap((unsigned long)pCmd); - uti596_softc.scb.command = CUC_START; - i82596->chan_attn = 0x00000000; + ifp->if_name = unitName; + ifp->if_unit = unitNumber; - UTI_WAIT_COMMAND_ACCEPTED(10000,"Add Polled command: start"); - uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL; - uti596_softc.scb.Cmd_val = (unsigned long) I596_NULL; + /* Assign mtu */ + if ( pConfig -> mtu ) + ifp->if_mtu = pConfig -> mtu; + else + ifp->if_mtu = ETHERMTU; -#ifdef DBG_POLLED_CMD - printk(("uti596addPolledCmd: Scb status & command 0x%x 0x%x\n", - uti596_softc.scb.status, - uti596_softc.scb.command )) -#endif -} + /* Ethernet address can be specified in the ifconfig structure or + * it can be read in from BBRAM at $FFFC1F2C (6 bytes) + * mvme167 manual p. 1-47 + */ + if ( pConfig->hardware_address) { + memcpy (sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN); + } + else { + memcpy (sc->arpcom.ac_enaddr, (char *)0xFFFC1F2C, ETHER_ADDR_LEN); + } + + /* Assign requested receive buffer descriptor count */ + if (pConfig->rbuf_count) + sc->rxBdCount = pConfig->rbuf_count; + else + sc->rxBdCount = RX_BUF_COUNT; + + /* Assign requested tx buffer descriptor count */ + if (pConfig->xbuf_count) + sc->txBdCount = pConfig->xbuf_count; + else + sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF; + + /* Set up fields in the ifnet structure*/ + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_init = uti596_init; + ifp->if_ioctl = uti596_ioctl; + ifp->if_start = uti596_start; + ifp->if_output = ether_output; + + /* uti596_softc housekeeping */ + sc->started = 1; + sc->pInboundFrameQueue = I596_NULL; + sc->scb.command = 0; + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + return 1; +} /*********************************************************************** - * Function: void uti596Diagnose + * Function: uti596_start * * Description: - * + * start the driver + * + * Algorithm: + * send an event to the tx task + * set the if_flags + * ***********************************************************************/ -void uti596Diagnose( - int verbose +static void uti596_start( + struct ifnet *ifp ) { - i596_cmd diagnose; - int count=10000; - - diagnose.command = CmdDiagnose; - diagnose.status = 0; - uti596addPolledCmd(&diagnose); - while( !( diagnose.status & STAT_C ) && count ) { - if(verbose) { - printk((".")) - } - count --; - } - if(verbose) { - printk(("Status diagnostic: 0xa000 is a success ... 0x%2.2x\n", diagnose.status)) - } + uti596_softc_ *sc = ifp->if_softc; + + #ifdef DBG_START + printk(("uti596_start: begins\n")) + #endif + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; } /*********************************************************************** - * Function: void uti596dequeue + * Function: uti596_init * * Description: - * removes an RFD from the received frame queue, + * driver initialization * * Algorithm: + * initialize the 82596 + * start driver tx and rx tasks, and reset task + * send the RX_START command the the RU + * set if_flags + * * ***********************************************************************/ -i596_rfd * uti596dequeue( - i596_rfd ** ppQ +void uti596_init( + void * arg ) { - ISR_Level level; + uti596_softc_ *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; - i596_rfd * pRfd; - _ISR_Disable(level); + if (sc->txDaemonTid == 0) { - /* invalid address, or empty queue or emptied queue */ - if( ppQ == NULL || *ppQ == NULL || *ppQ == I596_NULL) { - _ISR_Enable(level); - return I596_NULL; - } + /* + * Initialize the 82596 + */ + #ifdef DBG_INIT + printk(("uti596_init: begins\nuti596_init: initializing the 82596...\n")) + #endif + uti596_initialize_hardware(sc); + + /* + * Start driver tasks + */ + #ifdef DBG_INIT + printk(("uti596_init: starting driver tasks...\n")) + #endif + sc->txDaemonTid = rtems_bsdnet_newproc ("UTtx", 2*4096, uti596_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("UTrx", 2*4096, uti596_rxDaemon, sc); + sc->resetDaemonTid = rtems_bsdnet_newproc ("UTrt", 2*4096, uti596_resetDaemon, sc); - pRfd = *ppQ; /* The dequeued buffer */ - *ppQ = (i596_rfd *) \ - word_swap ((unsigned long) pRfd->next); /* advance the queue pointer */ - pRfd->next = I596_NULL; /* unlink the rfd being returned */ + #ifdef DBG_INIT + printk(("uti596_init: After attach, status of board = 0x%x\n", sc->scb.status )) + #endif + } - _ISR_Enable(level); - return pRfd; + /* + * Enable receiver + */ + #ifdef DBG_INIT + printk(("uti596_init: enabling the reciever...\n" )) + #endif + sc->scb.command = RX_START; + uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT ); + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + #ifdef DBG_INIT + printk(("uti596_init: completed.\n")) + #endif } /*********************************************************************** - * Function: void uti596reset + * Function: uti596stop * * Description: + * stop the driver + * + * Algorithm: + * mark driver as not started, + * mark transmitter as busy + * abort any transmissions/receptions + * clean-up all buffers ( RFD's et. al. ) + * + * ***********************************************************************/ -void uti596reset( void ) + +/* static */ void uti596_stop( + uti596_softc_ *sc +) { - int i,count; - uti596_softc_ *sc = &uti596_softc; - /* i596_rfd * pRfd; */ + struct ifnet *ifp = &sc->arpcom.ac_if; -#ifdef DBG_RESET - printk(("uti596reset: begin\n")) -#endif + ifp->if_flags &= ~IFF_RUNNING; + sc->started = 0; - sc->resetDone = 0; - UTI_WAIT_COMMAND_ACCEPTED(10000, "reset: wait for previous command complete"); - uti596_reset_hardware(&uti596_softc); /* reset the ethernet hardware. must re-config */ + #ifdef DBG_STOP + printk(("uti596stop: %s: Shutting down ethercard, status was %4.4x.\n", + uti596_softc.arpcom.ac_if.if_name, uti596_softc.scb.status)) + #endif -#ifdef DBG_RESET - uti596Diagnose(1); -#endif + printk(("Stopping interface\n")) + sc->scb.command = CUC_ABORT | RX_ABORT; + i82596->chan_attn = 0x00000000; +} - sc->set_conf.cmd.command = CmdConfigure; - memcpy (sc->set_conf.data, uti596initSetup, 14); - uti596addPolledCmd( (i596_cmd *) &sc->set_conf); - /* POLL */ - count = 2000; - while( !( sc->set_conf.cmd.status & STAT_C ) && --count ) { - printk((".")) - } - if ( count ) { - printk(("Configure OK, count = %d\n",count)) - } - else { - printk(("reset: Configure failed\n")) - } +/*********************************************************************** + * Function: void uti596_txDaemon + * + * Description: Transmit task + * + * Algorithm: Get mbufs to be transmitted, stuff into RFDs, send + * + ***********************************************************************/ - /* - * Create the IA setup command - */ - -#ifdef DBG_RESET - printk(("uti596reset: Setting Address\n")) -#endif - sc->set_add.cmd.command = CmdSASetup; - for ( i=0; i<6; i++) { - sc->set_add.data[i]=sc->arpcom.ac_enaddr[i]; - } - sc->cmdOk = 0; - uti596addPolledCmd((i596_cmd *)&sc->set_add); - - count = 2000; - while( !(sc->set_add.cmd.status & STAT_C ) && --count) { - printk((".")) - } - if ( count ) { - printk(("Reset Set Address OK, count= %d\n",count)) - } - else { - printk(("Reset Set Address Failed\n")) - } - - sc->pCmdHead = sc->pCmdTail = sc->scb.pCmd = I596_NULL; - -#ifdef DBG_RESET - printk(( "uti596reset: After reset, status and command: 0x%x, 0x%x\n", - sc->scb.status, sc->scb.status)) -#endif - - /* restore the RFA */ +void uti596_txDaemon( + void *arg +) +{ + uti596_softc_ *sc = (uti596_softc_ *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; - /* dumpQ(); */ + for (;;) { + /* + * Wait for packet from stack + */ + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); - if ( sc->pLastUnkRFD != I596_NULL ) { - sc-> pEndRFA = sc->pLastUnkRFD; /* The end position can be updated */ - sc-> pLastUnkRFD = I596_NULL; - } + /* + * Send packets till queue is empty. + * Ensure that irq is on before sending. + */ + for (;;) { + /* Get the next mbuf chain to transmit. */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; - sc->pEndRFA->next = sc->pSavedRfdQueue; - if ( sc->pSavedRfdQueue != I596_NULL ) { - sc->pEndRFA = sc->pEndSavedQueue; - sc->pSavedRfdQueue = sc->pEndSavedQueue = I596_NULL; - sc -> countRFD = sc->rxBdCount ; + send_packet (ifp, m); /* blocks */ + } + ifp->if_flags &= ~IFF_OACTIVE; /* no more to send, mark output inactive */ } - - sc->scb.pRfd = sc->pBeginRFA; /* readdress the head of the RFA in the SCB */ - sc->scb.Rfd_val = word_swap((unsigned long)sc->pBeginRFA); - - uti596clearListStatus(sc->pBeginRFA ); - - /* dumpQ(); */ - - printk(("Reset:Starting NIC\n")) - sc->scb.command = RX_START; - sc->started = 1; /* we assume that the start works */ - sc->resetDone = 1; - i82596->chan_attn = 0x00000000; - UTI_WAIT_COMMAND_ACCEPTED(4000, "reset"); - printk(("Reset:Start complete \n")) - UTI_596_ASSERT(sc->pCmdHead == I596_NULL, "Reset: CMD not cleared\n") - -#ifdef DBG_RESET - printk(("uti596reset: completed\n")) -#endif } - /*********************************************************************** - * Function: void uti596_reset_hardware + * Function: uti596_rxDaemon + * + * Description: Receiver task + * + * Algorithm: Extract the packet from an RFD, and place into an + * mbuf chain. Place the mbuf chain in the network task + * queue. Assumes that the frame check sequence is removed + * by the 82596. * - * Description: ***********************************************************************/ -void uti596_reset_hardware( - uti596_softc_ *sc + +/* static */ void uti596_rxDaemon( + void *arg ) { - int boguscnt = 1000; - rtems_status_code status_code; - i596_cmd *pCmd; - - - printk(("uti596_reset_hardware\n")) - pCmd = sc->pCmdHead; /* This is a tx command for sure (99.99999%) */ - - /* reset the board */ - i82596->port_lower = 0x0000; - i82596->port_upper = 0x0000; + uti596_softc_ *sc = (uti596_softc_ *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; - if ( sc->pScp == NULL ) { - printk(("Calloc scp\n")) - uti596_softc.pScp = (i596_scp *) calloc(1,sizeof(struct i596_scp) + 0xf); - } + i596_rfd *pRfd; + ISR_Level level; + int tid; + rtems_event_set events; + struct ether_header *eh; -#ifdef DBG_RESET - printk(("uti596_reset_hardware: Scp address %p\n", sc->pScp)) -#endif + int frames = 0; - /* align the block */ - sc->pScp = (i596_scp *) - ((((int)uti596_softc.pScp) + 0xf) & 0xfffffff0); + #ifdef DBG_RX + printk(("uti596_rxDaemon: begin\n")) + printk(("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd)) + #endif -#ifdef DBG_RESET - printk(("uti596_reset_hardware: change scp address to : %p\n",sc->pScp)) -#endif + rtems_task_ident (0, 0, &tid); - /* change the scp address */ -#ifdef DBG_RESET - printk(("uti596_reset_hardware: Change the SCP address\n")) -#endif + for(;;) { + /* + * Wait for packet. + */ + #ifdef DBG_RX + printk(("uti596_rxDaemon: Receiver sleeps\n")) + #endif + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + #ifdef DBG_RX + printk(("uti596_rxDaemon: Receiver wakes\n")) + #endif + /* + * While received frames are available. Note that the frame may be + * a fragment, so it is NOT a complete packet. + */ + pRfd = uti596_dequeue( &sc->pInboundFrameQueue); + while ( pRfd && + pRfd != I596_NULL && + pRfd -> stat & STAT_C ) + { - /* reset the board */ - i82596->port_lower = 0x0000; - i82596->port_upper = 0x0000; - - /* supply the Scp address - * Lower Command Word D31-D16; Upper Command Word D15-D0 - */ - i82596->port_lower = (((int)sc->pScp) & 0xfff0) | 0x0002; - i82596->port_upper = (((int)sc->pScp) >> 16 ) & 0xffff; + if ( pRfd->stat & STAT_OK) { /* a good frame */ + int pkt_len = pRfd->count & 0x3fff; /* the actual # of bytes received */ - /* write the SYSBUS: interrupt pin active high, LOCK disabled, - * internal triggering, linear mode - */ - sc->pScp->sysbus = word_swap(0x00540000); - - /* provide the iscp to the scp, keep a pointer for our use */ - sc->pScp->iscp_val = word_swap((unsigned long)&sc->iscp); - sc->pScp->iscp = &sc->iscp; + #ifdef DBG_RX + printk(("uti596_rxDaemon: Good frame, @%p, data @%p length %d\n", pRfd, pRfd -> data , pkt_len)) + #endif + frames++; - /* provide the scb to the iscp, keep a pointer for our use */ - sc->iscp.scb_val = word_swap((unsigned long)&sc->scb); - sc->iscp.scb = &sc->scb; + /* + * Allocate an mbuf to give to the stack + * The format of the data portion of the RFD is: + * . + * The FRAME CHECK SEQUENCE / CRC is stripped by the uti596. + * This is to be optimized later.... should not have to memcopy! + */ + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + + m->m_pkthdr.rcvif = ifp; + /* move everything into an mbuf */ + memcpy(m->m_data, pRfd->data, pkt_len); + m->m_len = m->m_pkthdr.len = pkt_len - sizeof(struct ether_header) - 4; + + /* move the header to an mbuf */ + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + + #ifdef DBG_PACKETS + { + int i; + printk(("uti596_rxDaemon: mbuf contains:\n")) + print_eth( (char *) (((int)m->m_data)-sizeof(struct ether_header))); + for ( i = 0; i<20; i++) { + printk((".")) + } + } + #endif + + ether_input (ifp, eh, m); + + } /* end if STAT_OK */ + + else { + /* + * A bad frame is present: Note that this could be the last RFD! + */ + #ifdef DBG_RX + printk(("uti596_rxDaemon: Bad frame\n")) + #endif + /* + * FIX ME: use the statistics from the SCB + */ + sc->stats.rx_errors++; + if ((sc->scb.pRfd->stat) & 0x0001) + sc->stats.collisions++; + if ((sc->scb.pRfd->stat) & 0x0080) + sc->stats.rx_length_errors++; + if ((sc->scb.pRfd->stat) & 0x0100) + sc->stats.rx_over_errors++; + if ((sc->scb.pRfd->stat) & 0x0200) + sc->stats.rx_fifo_errors++; + if ((sc->scb.pRfd->stat) & 0x0400) + sc->stats.rx_frame_errors++; + if ((sc->scb.pRfd->stat) & 0x0800) + sc->stats.rx_crc_errors++; + if ((sc->scb.pRfd->stat) & 0x1000) + sc->stats.rx_length_errors++; + } - /* set the busy flag in the iscp */ - sc->iscp.stat = word_swap(0x00000001); + UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD\n") - /* the command block list (CBL) is empty */ - sc->scb.Cmd_val = (unsigned long) I596_NULL; /* all 1's */ - sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */ + _ISR_Disable(level); + uti596_supplyFD ( pRfd ); /* Return RFD to RFA. */ + _ISR_Enable(level); - /* - * Wake the transmitter if needed. - */ - if ( uti596_softc.txDaemonTid && pCmd != I596_NULL ) { - printk(("****RESET: wakes transmitter!\n")) - status_code = rtems_event_send (uti596_softc.txDaemonTid, - INTERRUPT_EVENT); + pRfd = uti596_dequeue( &sc->pInboundFrameQueue); /* grab next frame */ - if ( status_code != RTEMS_SUCCESSFUL ) { - printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n", - uti596_softc.txDaemonTid, rtems_status_text (status_code) )) - } - } + } /* end while */ + } /* end for() */ -#ifdef DBG_596 - printk(("uti596_reset_hardware: starting i82596.\n")) -#endif + #ifdef DBG_RX + printk (("uti596_rxDaemon: frames ... %d\n", frames)) + #endif +} - /* Pass the scb address to the 596 */ - i82596->chan_attn = 0x00000000; - while (sc->iscp.stat) - if (--boguscnt == 0) - { - printk(("reset_hardware: timed out with status %4.4lx\n", - sc->iscp.stat )) - break; - } +/*********************************************************************** + * Function: void uti596_resetDaemon + * + * Description: + ***********************************************************************/ +void uti596_resetDaemon( + void *arg +) +{ + uti596_softc_ *sc = (uti596_softc_ *)arg; + rtems_event_set events; + rtems_time_of_day tm_struct; - /* clear the command word */ - sc->scb.command = 0; + /* struct ifnet *ifp = &sc->arpcom.ac_if; */ -#ifdef DBG_RESET - printk(("uti596_reset_hardware: After reset_hardware, status of board = 0x%x\n", sc->scb.status )) -#endif -} + for (;;) { + /* Wait for reset event from ISR */ + rtems_bsdnet_event_receive (NIC_RESET_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); - /*********************************************************************** - * Function: uti596clearListStatus - * - * Description: - * Clear the stat fields for all rfd's - * Algorithm: - * - ***********************************************************************/ + rtems_clock_get(RTEMS_CLOCK_GET_TOD, &tm_struct); + printk(("reset daemon: Resetting NIC @ %d:%d:%d \n", + tm_struct.hour, tm_struct.minute, tm_struct.second)) -void uti596clearListStatus( - i596_rfd *pRfd -) -{ - while ( pRfd != I596_NULL ) { - pRfd -> stat = 0; - pRfd = (i596_rfd *) word_swap((unsigned long)pRfd-> next); + sc->stats.nic_reset_count++; + /* Reinitialize the LANC */ + rtems_bsdnet_semaphore_obtain (); + uti596_reset(); + rtems_bsdnet_semaphore_release (); } } - /*********************************************************************** - * Function: send_packet - * - * Description: Send a raw ethernet packet - * - * Algorithm: - * increment some stats counters, - * create the transmit command, - * add the command to the CBL, - * wait for event - * - ***********************************************************************/ -void send_packet( - struct ifnet *ifp, struct mbuf *m +/*********************************************************************** + * Function: uti596_DynamicInterruptHandler + * + * Description: + * This is the interrupt handler for the uti596 board + * + ***********************************************************************/ + +/* static */ rtems_isr uti596_DynamicInterruptHandler( + rtems_vector_number irq ) { - i596_tbd *pPrev = I596_NULL; - i596_tbd *pRemainingTbdList; - i596_tbd *pTbd; - struct mbuf *n, *input_m = m; + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: begins")) + #endif - uti596_softc_ *sc = ifp->if_softc; + uti596_wait (&uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT); - struct mbuf *l = NULL; - unsigned int length = 0; - rtems_status_code status; - int bd_count = 0; - rtems_event_set events; + scbStatus = uti596_softc.scb.status & 0xf000; - /* - * For all mbufs in the chain, - * fill a transmit buffer descriptor for each - */ - pTbd = (i596_tbd*) word_swap ((unsigned long)sc->pTxCmd->pTbd); + if ( scbStatus ) { + /* acknowledge interrupts */ + + /* Write to the ICLR bit in the PCCchip2 control registers to clear + * the INT status bit. Clearing INT here *before* sending the CA signal + * to the 82596 should ensure that interrupts won't be lost. + */ + pccchip2->LANC_int_ctl |=0x08; + pccchip2->LANC_berr_ctl |=0x08; + + /* printk(("***INFO: ACK %x\n", scbStatus))*/ + + /* Send the CA signal to acknowledge interrupt */ + uti596_softc.scb.command = scbStatus; + uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT ); - do { - if (m->m_len) { - /* - * Fill in the buffer descriptor - */ - length += m->m_len; - pTbd->data = (char *) word_swap ((unsigned long) mtod (m, void *)); - pTbd->size = m->m_len; - pPrev = pTbd; - pTbd = (i596_tbd *) word_swap ((unsigned long) pTbd->next); - l = m; - m = m->m_next; + if( uti596_softc.resetDone ) { + /* stack is attached */ + uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT ); } else { - /* - * Just toss empty mbufs - */ - MFREE (m, n); - m = n; - if (l != NULL) - l->m_next = m; + printk(("***INFO: ACK'd w/o processing. status = %x\n", scbStatus)) + return; } - } while( m != NULL && ++bd_count < 16 ); - - /* This should never happen */ - if ( bd_count == 16 ) { - printk(("TX ERROR:Too many mbufs in the packet!!!\n")) - printk(("Must coalesce!\n")) } - - if ( length < UTI_596_ETH_MIN_SIZE ) { - pTbd->data = (char *) word_swap ((unsigned long) sc->zeroes); /* add padding to pTbd */ - pTbd->size = UTI_596_ETH_MIN_SIZE - length; /* zeroes have no effect on the CRC */ + else { + printk(("\n***ERROR: Spurious interrupt. Resetting...\n")) + uti596_softc.nic_reset = 1; } - else - pTbd = pPrev; /* Don't use pTbd in the send routine */ - - /* Disconnect the packet from the list of Tbd's */ - pRemainingTbdList = (i596_tbd *) word_swap ((unsigned long)pTbd->next); - pTbd->next = I596_NULL; - pTbd->size |= UTI_596_END_OF_FRAME; -#ifdef DBG_RAW - printk(("send_packet: RAW - Add cmd and sleep\n")) -#endif - sc->rawsndcnt++; + if ( (scbStatus & SCB_STAT_CX) && !(scbStatus & SCB_STAT_CNA) ) { + printk(("\n*****ERROR: Command Complete, and CNA available: 0x%x\nResetting...", scbStatus)) + uti596_softc.nic_reset = 1; + return; + } -#ifdef DBG_RAW - printk(("send_packet: RAW - sending packet\n")) -#endif + if ( !(scbStatus & SCB_STAT_CX) && (scbStatus & SCB_STAT_CNA) ) { + printk(("\n*****ERROR: CNA, NO CX:0x%x\nResetting...",scbStatus)) + uti596_softc.nic_reset = 1; + return; + } - /* Sending Zero length packet: shouldn't happen */ - if (pTbd->size <= 0) return ; + if ( scbStatus & SCB_CUS_SUSPENDED ) { + printk(("\n*****ERROR: Command unit suspended!:0x%x\nResetting...",scbStatus)) + uti596_softc.nic_reset = 1; + return; + } -#ifdef DBG_INIT_3 - printk(("\nsend_packet: Transmitter adds packet\n")) - print_hdr ( sc->pTxCmd->pTbd->data ); /* print the first part */ - print_pkt ( sc->pTxCmd->pTbd->next->data ); /* print the first part */ - /* print_echo(sc->pTxCmd->pTbd->data); */ -#endif + if ( scbStatus & RU_SUSPENDED ) { + printk(("\n*****ERROR: Receive unit suspended!:0x%x\nResetting...",scbStatus)) + uti596_softc.nic_reset = 1; + return; + } - /* add the command to the output command queue */ - uti596addCmd ( (i596_cmd *) sc->pTxCmd ); + if ( scbStatus & SCB_STAT_RNR ) { + printk(("\n*****WARNING: RNR %x\n",scbStatus)) + if (uti596_softc.pBeginRFA != I596_NULL) { + printk(("*****INFO: RFD cmd: %x status:%x\n", uti596_softc.pBeginRFA->cmd, + uti596_softc.pBeginRFA->stat)) + } + else { + printk(("*****WARNING: RNR condition with NULL BeginRFA\n")) + } + } - /* sleep until the command has been processed or Timeout encountered. */ - status= rtems_bsdnet_event_receive (INTERRUPT_EVENT, - RTEMS_WAIT|RTEMS_EVENT_ANY, - RTEMS_NO_TIMEOUT, - &events); + /* + * Receive Unit Control + * a frame is received + */ + if ( scbStatus & SCB_STAT_FR ) { + uti596_softc.rxInterrupts++; + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: Frame received\n")) + #endif + if ( uti596_softc.pBeginRFA == I596_NULL || + !( uti596_softc.pBeginRFA -> stat & STAT_C)) { + uti596_dump_scb(); + uti596_softc.nic_reset = 1; + } + else { + while ( uti596_softc.pBeginRFA != I596_NULL && + ( uti596_softc.pBeginRFA -> stat & STAT_C)) { - if ( status != RTEMS_SUCCESSFUL ) { - printk(("Could not sleep %s\n", rtems_status_text(status))) + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: pBeginRFA != NULL\n")) + #endif + count_rx ++; + if ( count_rx > 1) { + printk(("****WARNING: Received 2 frames on 1 interrupt \n")) + } + /* Give Received Frame to the ULCS */ + uti596_softc.countRFD--; + + if ( uti596_softc.countRFD < 0 ) { + printk(("ISR: Count < 0 !!! count == %d, beginRFA = %p\n", + uti596_softc.countRFD, uti596_softc.pBeginRFA)) + } + uti596_softc.stats.rx_packets++; + /* the rfd next link is stored with upper and lower words swapped so read it that way */ + pIsrRfd = (i596_rfd *) word_swap ((unsigned long)uti596_softc.pBeginRFA->next); + /* the append destroys the link */ + uti596_append( &uti596_softc.pInboundFrameQueue , uti596_softc.pBeginRFA ); + + /* + * if we have just received the a frame in the last unknown RFD, + * then it is certain that the RFA is empty. + */ + if ( uti596_softc.pLastUnkRFD == uti596_softc.pBeginRFA ) { + UTI_596_ASSERT(uti596_softc.pLastUnkRFD != I596_NULL,"****ERROR:LastUnk is NULL, begin ptr @ end!\n") + uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD = I596_NULL; + } + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: Wake %#x\n",uti596_softc.rxDaemonTid)) + #endif + sc = rtems_event_send(uti596_softc.rxDaemonTid, INTERRUPT_EVENT); + if ( sc != RTEMS_SUCCESSFUL ) { + rtems_panic("Can't notify rxDaemon: %s\n", + rtems_status_text (sc)); + } + #ifdef DBG_ISR + else { + printk(("uti596_DynamicInterruptHandler: Rx Wake: %#x\n",uti596_softc.rxDaemonTid)) + } + #endif + + uti596_softc.pBeginRFA = pIsrRfd; + } /* end while */ + } /* end if */ + + if ( uti596_softc.pBeginRFA == I596_NULL ) { + /* adjust the pEndRFA to reflect an empty list */ + if ( uti596_softc.pLastUnkRFD == I596_NULL && uti596_softc.countRFD != 0 ) { + printk(("Last Unk is NULL, BeginRFA is null, and count == %d\n", + uti596_softc.countRFD)) + } + uti596_softc.pEndRFA = I596_NULL; + if ( uti596_softc.countRFD != 0 ) { + printk(("****ERROR:Count is %d, but begin ptr is NULL\n", + uti596_softc.countRFD )) + } + } + } /* end if ( scbStatus & SCB_STAT_FR ) */ + + + /* + * Command Unit Control + * a command is completed + */ + if ( scbStatus & SCB_STAT_CX ) { + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: CU\n")) + #endif + + pIsrCmd = uti596_softc.pCmdHead; + + /* For ALL completed commands */ + if ( pIsrCmd != I596_NULL && pIsrCmd->status & STAT_C ) { + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: pIsrCmd != NULL\n")) + #endif + + /* Adjust the command block list */ + uti596_softc.pCmdHead = (i596_cmd *) word_swap ((unsigned long)pIsrCmd->next); + + /* + * If there are MORE commands to process, + * the serialization in the raw routine has failed. + * ( Perhaps AddCmd is bad? ) + */ + UTI_596_ASSERT(uti596_softc.pCmdHead == I596_NULL, "****ERROR: command serialization failed\n") + + /* What if the command did not complete OK? */ + switch ( pIsrCmd->command & 0x7) { + case CmdConfigure: + + uti596_softc.cmdOk = 1; + break; + + case CmdDump: + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: dump!\n")) + #endif + uti596_softc.cmdOk = 1; + break; + + case CmdDiagnose: + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: diagnose!\n")) + #endif + uti596_softc.cmdOk = 1; + break; + + case CmdSASetup: + /* printk(("****INFO:Set address interrupt\n")) */ + if ( pIsrCmd -> status & STAT_OK ) { + uti596_softc.cmdOk = 1; + } + else { + printk(("****ERROR:SET ADD FAILED\n")) + } + break; + + case CmdTx: + UTI_596_ASSERT(uti596_softc.txDaemonTid, "****ERROR:Null txDaemonTid\n") + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: wake TX:0x%x\n",uti596_softc.txDaemonTid)) + #endif + if ( uti596_softc.txDaemonTid ) { + /* Ensure that the transmitter is present */ + sc = rtems_event_send (uti596_softc.txDaemonTid, + INTERRUPT_EVENT); + + if ( sc != RTEMS_SUCCESSFUL ) { + printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n", + uti596_softc.txDaemonTid, rtems_status_text (sc) )) + } + #ifdef DBG_ISR + else { + printk(("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid)) + } + #endif + } + break; + + case CmdMulticastList: + printk(("***ERROR:Multicast?!\n")) + pIsrCmd->next = I596_NULL; + break; + + case CmdTDR: { + unsigned long status = *( (unsigned long *)pIsrCmd)+1; + printk(("****ERROR:TDR?!\n")) + + if (status & STAT_C) { + /* mark the TDR command successful */ + uti596_softc.cmdOk = 1; + } + else { + if (status & 0x4000) { + printk(("****WARNING:Transceiver problem.\n")) + } + if (status & 0x2000) { + printk(("****WARNING:Termination problem.\n")) + } + if (status & 0x1000) { + printk(("****WARNING:Short circuit.\n")) + /* printk(("****INFO:Time %ld.\n", status & 0x07ff)) */ + } + } + } + break; + + default: { + /* + * This should never be reached + */ + printk(("CX but NO known command\n")) + } + } /* end switch */ + + pIsrCmd = uti596_softc.pCmdHead; /* next command */ + if ( pIsrCmd != I596_NULL ) { + printk(("****WARNING: more commands in list, but no start to NIC\n")) + } + } /* end if pIsrCmd != NULL && pIsrCmd->stat & STAT_C */ + + else { + if ( pIsrCmd != I596_NULL ) { + /* The command MAY be NULL from a RESET */ + /* Reset the ethernet card, and wake the transmitter (if necessary) */ + printk(("****INFO: Request board reset ( tx )\n")) + uti596_softc.nic_reset = 1; + if ( uti596_softc.txDaemonTid) { + /* Ensure that a transmitter is present */ + sc = rtems_event_send (uti596_softc.txDaemonTid, + INTERRUPT_EVENT); + if ( sc != RTEMS_SUCCESSFUL ) { + printk(("****ERROR:Could NOT send event to tid 0x%x : %s\n", + uti596_softc.txDaemonTid, rtems_status_text (sc) )) + } + #ifdef DBG_ISR + else { + printk(("uti596_DynamicInterruptHandler: ****INFO:Tx wake: %#x\n", + uti596_softc.txDaemonTid)) + } + #endif + } + } + } + } /* end if command complete */ + + + /* + * If the receiver has stopped, + * check if this is a No Resources scenario, + * Try to add more RFD's ( no RBDs are used ) + */ + if ( uti596_softc.started ) { + if ( scbStatus & SCB_STAT_RNR ) { + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: INFO:RNR: status %#x \n", + uti596_softc.scb.status )) + #endif + /* + * THE RECEIVER IS OFF! + */ + if ( uti596_softc.pLastUnkRFD != I596_NULL ) { + /* We have an unknown RFD, it is not inbound */ + if ( uti596_softc.pLastUnkRFD -> stat & (STAT_C | STAT_B )) { /* in use */ + uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD; /* update end */ + } + else { + /* + * It is NOT in use, and since RNR, we know EL bit of pEndRFA was read! + * So, unlink it from the RFA and move it to the saved queue. + * But pBegin can equal LastUnk! + */ + + if ( uti596_softc.pEndRFA != I596_NULL ) { + /* check added feb24. */ + #ifdef DBG_ISR + if ((i596_rfd *)word_swap((unsigned long)uti596_softc.pEndRFA->next) != uti596_softc.pLastUnkRFD) { + printk(("***ERROR:UNK: %p not end->next: %p, end: %p\n", + uti596_softc.pLastUnkRFD, + uti596_softc.pEndRFA -> next, + uti596_softc.pEndRFA)) + printk(("***INFO:countRFD now %d\n", + uti596_softc.countRFD)) + printk(("\n\n")) + } + #endif + uti596_softc.pEndRFA -> next = I596_NULL; /* added feb 16 */ + } + uti596_append( &uti596_softc.pSavedRfdQueue, uti596_softc.pLastUnkRFD ); + uti596_softc.savedCount++; + uti596_softc.pEndSavedQueue = uti596_softc.pLastUnkRFD; + uti596_softc.countRFD--; /* It was not in the RFA */ + /* + * The Begin pointer CAN advance this far. We must resynch the CPU side + * with the chip. + */ + if ( uti596_softc.pBeginRFA == uti596_softc.pLastUnkRFD ) { + #ifdef DBG_ISR + if ( uti596_softc.countRFD != 0 ) { + printk(("****INFO:About to set begin to NULL, with count == %d\n\n", + uti596_softc.countRFD )) + } + #endif + uti596_softc.pBeginRFA = I596_NULL; + UTI_596_ASSERT(uti596_softc.countRFD == 0, "****ERROR:Count must be zero here!\n") + } + } + uti596_softc.pLastUnkRFD = I596_NULL; + } /* end if exists UnkRFD */ + + /* + * Append the saved queue to the RFA. + * Any further RFD's being supplied will be added to + * this new list. + */ + if ( uti596_softc.pSavedRfdQueue != I596_NULL ) { + /* entries to add */ + if ( uti596_softc.pBeginRFA == I596_NULL ) { + /* add at beginning to list */ + #ifdef DBG_ISR + if(uti596_softc.countRFD != 0) { + printk(("****ERROR:Begin pointer is NULL, but count == %d\n", + uti596_softc.countRFD)) + } + #endif + uti596_softc.pBeginRFA = uti596_softc.pSavedRfdQueue; + uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; + uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ + } + else { + #ifdef DBG_ISR + if ( uti596_softc.countRFD <= 0) { + printk(("****ERROR:Begin pointer is not NULL, but count == %d\n", + uti596_softc.countRFD)) + } + #endif + UTI_596_ASSERT( uti596_softc.pEndRFA != I596_NULL, "****WARNING: END RFA IS NULL\n") + UTI_596_ASSERT( uti596_softc.pEndRFA->next == I596_NULL, "****ERROR:END RFA -> next must be NULL\n") + + uti596_softc.pEndRFA->next = (i596_rfd *)word_swap((unsigned long)uti596_softc.pSavedRfdQueue); + uti596_softc.pEndRFA->cmd &= ~CMD_EOL; /* clear the end of list */ + uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; + uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: count... %d, saved ... %d \n", + uti596_softc.countRFD, + uti596_softc.savedCount)) + #endif + } + /* printk(("Isr: countRFD = %d\n",uti596_softc.countRFD)) */ + uti596_softc.countRFD += uti596_softc.savedCount; + /* printk(("Isr: after countRFD = %d\n",uti596_softc.countRFD)) */ + uti596_softc.savedCount = 0; + } + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: The list starts here %p\n",uti596_softc.pBeginRFA )) + #endif + + if ( uti596_softc.countRFD > 1) { + printk(("****INFO: pBeginRFA -> stat = 0x%x\n",uti596_softc.pBeginRFA -> stat)) + printk(("****INFO: pBeginRFA -> cmd = 0x%x\n",uti596_softc.pBeginRFA -> cmd)) + uti596_softc.pBeginRFA -> stat = 0; + UTI_596_ASSERT(uti596_softc.scb.command == 0, "****ERROR:scb command must be zero\n") + uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; + uti596_softc.scb.rfd_pointer = word_swap((unsigned long)uti596_softc.pBeginRFA); + /* start RX here */ + printk(("****INFO: ISR Starting receiver\n")) + uti596_softc.scb.command = RX_START; /* should this also be CU start? */ + i82596->chan_attn = 0x00000000; + } + } /* end stat_rnr */ + } /* end if receiver started */ + + #ifdef DBG_ISR + printk(("uti596_DynamicInterruptHandler: X\n")) + #endif + count_rx=0; + + + /* Do this last, to ensure that the reset is called at the right time. */ + if ( uti596_softc.nic_reset ) { + uti596_softc.nic_reset = 0; + sc = rtems_event_send(uti596_softc.resetDaemonTid, NIC_RESET_EVENT); + if ( sc != RTEMS_SUCCESSFUL ) + rtems_panic ("Can't notify resetDaemon: %s\n", rtems_status_text (sc)); } + return; +} -#ifdef DBG_RAW - printk(("send_packet: RAW - wake\n")) -#endif - - sc->txInterrupts++; -#ifdef DBG_INIT_3 - printk(("\nsend_packet: Transmitter issued packet\n")) - print_hdr ( sc->pTxCmd->pTbd -> data ); /* print the first part */ - print_pkt ( sc->pTxCmd->pTbd ->next-> data ); /* print the first part */ -#endif +/*********************************************************************** + * Function: uti596_ioctl + * + * Description: + * driver ioctl function + * handles SIOCGIFADDR, SIOCSIFADDR, SIOCSIFFLAGS + * + ***********************************************************************/ + +static int uti596_ioctl( + struct ifnet *ifp, + int command, caddr_t data +) +{ + uti596_softc_ *sc = ifp->if_softc; + int error = 0; - if ( sc->pTxCmd -> cmd.status & STAT_OK ) { - sc->stats.tx_packets++; - } - else { -#ifdef DBG_RAW - printk(("******send_packet: Driver Error 0x%x\n", sc->pTxCmd -> cmd.status )) -#endif - sc->stats.tx_errors++; - if ( sc->pTxCmd->cmd.status & 0x0020 ) - sc->stats.tx_retries_exceeded++; - if (!(sc->pTxCmd->cmd.status & 0x0040)) - sc->stats.tx_heartbeat_errors++; - if ( sc->pTxCmd->cmd.status & 0x0400 ) - sc->stats.tx_carrier_errors++; - if ( sc->pTxCmd->cmd.status & 0x0800 ) - sc->stats.collisions++; - if ( sc->pTxCmd->cmd.status & 0x1000 ) - sc->stats.tx_aborted_errors++; - } /* end if stat_ok */ + #ifdef DBG_IOCTL + printk(("uti596_ioctl: begins\n", sc->pScp)) + #endif - /* - * Restore the transmited buffer descriptor chain. - */ - pTbd -> next = (i596_tbd *) word_swap ((unsigned long)pRemainingTbdList); + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + printk(("SIOCSIFADDR\n")) + ether_ioctl (ifp, command, data); + break; - /* - * Free the mbufs used by the sender. - */ - m = input_m; - while ( m != NULL ) { - MFREE(m,n); - m = n; - } -} + case SIOCSIFFLAGS: + printk(("SIOCSIFFLAGS\n")) + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + printk(("IFF_RUNNING\n")) + uti596_stop (sc); + break; - /*********************************************************************** - * Function: uti596addCmd - * - * Description: - * This routine adds a command onto the end of the - * command chain - * - * Algorithm: - * Add the command to the end of an existing chain, - * or start the chain and issue a CUC_START - * - * - ***********************************************************************/ - -/* static */ void uti596addCmd( - i596_cmd *pCmd -) -{ - ISR_Level level; - - #ifdef DBG_596 - printk(("uti596addCmd: Adding command 0x%x\n", pCmd -> command )) - #endif - -#ifdef DBG_ADD - - switch ( pCmd -> command & 0x7 ){ /* check bottom 3 bits */ - case CmdConfigure: - printk(("uti596addCmd: Configure Command 0x%x\n", pCmd->command)) - break; - case CmdSASetup: - printk(("uti596addCmd: Set Address Command 0x%x\n", pCmd->command)) - break; - case CmdMulticastList: - printk(("uti596addCmd: Multi-cast list 0x%x\n", pCmd->command)) - break; - case CmdNOp: - printk(("uti596addCmd: NO op 0x%x\n", pCmd->command)) - break; - case CmdTDR: - printk(("uti596addCmd: TDR 0x%x\n", pCmd->command)) - break; - case CmdDump: - printk(("uti596addCmd: Dump 0x%x\n", pCmd->command)) - break; - case CmdDiagnose: - printk(("uti596addCmd: Diagnose 0x%x\n", pCmd->command)) - break; - case CmdTx: - break; - default: - printk(("****Unknown Command encountered 0x%x\n", pCmd->command)) - break; - } /* end switch */ -#endif + case IFF_UP: + printk(("IFF_UP\n")) + uti596_init (sc); + break; - pCmd->status = 0; - pCmd->command |= (CMD_EOL | CMD_INTR ); /* all commands last in list & return an interrupt */ + case IFF_UP | IFF_RUNNING: + printk(("IFF_UP and RUNNING\n")) + uti596_stop (sc); + uti596_init (sc); + break; - pCmd->next = I596_NULL; + default: + printk(("default\n")) + break; + } + break; - _ISR_Disable(level); - if (uti596_softc.pCmdHead == I596_NULL) - { - uti596_softc.pCmdHead = - uti596_softc.pCmdTail = - uti596_softc.scb.pCmd = pCmd; - uti596_softc.scb.Cmd_val = word_swap ((unsigned long)pCmd); -#ifdef DBG_596 - printk(("uti596addCmd: First Cmd\n")) -#endif - UTI_WAIT_COMMAND_ACCEPTED(10000,"add command"); /* wait for acceptance of previous command */ - uti596_softc.scb.command = CUC_START; - i82596->chan_attn = 0x00000000; - _ISR_Enable(level); - } - else - { -#ifdef DBG_596 - printk(("uti596addCmd: Chained Cmd\n")) -#endif - uti596_softc.pCmdTail->next = (i596_cmd *) word_swap ((unsigned long)pCmd); - uti596_softc.pCmdTail = pCmd; - _ISR_Enable(level); - } + case SIO_RTEMS_SHOW_STATS: + printk(("show stats\n")) + uti596_stats (sc); + break; -#ifdef DBG_596 - printk(("uti596addCmd: Scb status & command 0x%x 0x%x\n", - uti596_softc.scb.status, - uti596_softc.scb.command )) -#endif + /* FIXME: All sorts of multicast commands need to be added here! */ + default: + printk(("default: EINVAL\n")) + error = EINVAL; + break; + } + + return error; } /*********************************************************************** - * Function: uti596supplyFD + * Function: uti596_stats * - * Description: returns a buffer to the receive frame pool. - * call this with Inetrrupts disabled! + * Description: + * print out the collected data * * Algorithm: + * use printf * ***********************************************************************/ - -void uti596supplyFD( - i596_rfd * pRfd + +void uti596_stats( + uti596_softc_ *sc ) { - i596_rfd *pLastRfd; + printf ("CPU Reports:\n"); + printf (" Tx raw send count:%-8lu", sc->rawsndcnt); + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Tx Interrupts:%-8lu\n", sc->txInterrupts); + printf (" Rx Packets:%-8u", sc->stats.rx_packets); + printf (" Tx Attempts:%-u\n", sc->stats.tx_packets); - UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD!\n") - pRfd -> cmd = CMD_EOL; - pRfd -> pRbd = I596_NULL; - pRfd -> next = I596_NULL; - pRfd -> stat = 0x0000; /* clear STAT_C and STAT_B bits */ + printf (" Rx Dropped:%-8u", sc->stats.rx_dropped); + printf (" Rx IP Packets:%-8u", sc->stats.rx_packets); + printf (" Tx Errors:%-8u\n", sc->stats.tx_errors); + printf (" Tx aborted:%-8u", sc->stats.tx_aborted_errors); + printf (" Tx Dropped:%-8u\n", sc->stats.tx_dropped); + printf (" Tx IP packets:%-8u", sc->stats.tx_packets); - /* - * Check if the list is empty: - */ - if ( uti596_softc.pBeginRFA == I596_NULL ) { - /* Init a list w/ one entry */ - uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; - UTI_596_ASSERT(uti596_softc.countRFD == 0, "Null begin, but non-zero count\n") - if ( uti596_softc.pLastUnkRFD != I596_NULL ) { - printk(("LastUnkRFD is NOT NULL!!\n")) - } - uti596_softc.countRFD = 1; - return; - } - /* - * Check if the last RFD is used/read by the 596. - */ - pLastRfd = uti596_softc.pEndRFA; + printf (" Collisions Detected:%-8u\n", sc->stats.collisions); + printf (" Tx Heartbeat Errors:%-8u", sc->stats.tx_heartbeat_errors); + printf (" Tx Carrier Errors:%-8u\n", sc->stats.tx_carrier_errors); + printf (" Tx Aborted Errors:%-8u", sc->stats.tx_aborted_errors); + printf (" Rx Length Errors:%-8u\n", sc->stats.rx_length_errors); + printf (" Rx Overrun Errors:%-8u", sc->stats.rx_over_errors); + printf (" Rx Fifo Errors:%-8u\n", sc->stats.rx_fifo_errors); + printf (" Rx Framing Errors:%-8u", sc->stats.rx_frame_errors); + printf (" Rx crc errors:%-8u\n", sc->stats.rx_crc_errors); - if ( pLastRfd != I596_NULL && - ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) { /* C = complete, B = busy (prefetched) */ + printf (" TX WAITS: %-8lu\n", sc->txRawWait); - /* - * Not yet too late to add it - */ - pLastRfd -> next = (i596_rfd *) word_swap ((unsigned long)pRfd); - pLastRfd -> cmd &= ~CMD_EOL; /* RESET_EL : reset EL bit to 0 */ - uti596_softc.countRFD++; /* Lets assume we add it successfully - If not, the RFD may be used, and may decrement countRFD < 0 !!*/ - /* - * Check if the last RFD was used while appending. - */ - if ( pLastRfd -> stat & ( STAT_C | STAT_B ) ) { /* completed or was prefetched */ - /* - * Either the EL bit of the last rfd has been read by the 82596, - * and it will stop after reception,( true when RESET_EL not reached ) or - * the EL bit was NOT read by the 82596 and it will use the linked - * RFD for the next reception. ( true is RESET_EL was reached ) - * So, it is unknown whether or not the linked rfd will be used. - * Therefore, the end of list CANNOT be updated. - */ - UTI_596_ASSERT ( uti596_softc.pLastUnkRFD == I596_NULL, "Too many Unk RFD's\n" ) - uti596_softc.pLastUnkRFD = pRfd; - return; - } - else { - /* - * The RFD being added was not touched by the 82596 - */ - if (uti596_softc.pLastUnkRFD != I596_NULL ) { + printf (" NIC resets: %-8u\n", sc->stats.nic_reset_count); - uti596append(&uti596_softc.pSavedRfdQueue, pRfd); /* Only here! saved Q */ - uti596_softc.pEndSavedQueue = pRfd; - uti596_softc.savedCount++; - uti596_softc.countRFD--; + printf (" NIC reports\n"); - } - else { - uti596_softc.pEndRFA = pRfd; /* the RFA has been extended */ - if ( ( uti596_softc.scb.status & SCB_STAT_RNR || - uti596_softc.scb.status & RU_NO_RESOURCES ) && - uti596_softc.countRFD > 1 ) { - uti596_softc.pBeginRFA -> cmd &= ~CMD_EOL; /* Ensure that beginRFA is not EOL */ + #ifdef DBG_STAT + uti596_dump_scb(); + #endif +} - UTI_596_ASSERT(uti596_softc.pEndRFA -> next == I596_NULL, "supply: List buggered\n") - UTI_596_ASSERT(uti596_softc.pEndRFA -> cmd & CMD_EOL, "supply: No EOL at end.\n") - UTI_596_ASSERT(uti596_softc.scb.command == 0, "Supply: scb command must be zero\n") -#ifdef DBG_START - printk(("uti596supplyFD: starting receiver")) -#endif - /* start the receiver */ - UTI_596_ASSERT(uti596_softc.pBeginRFA != I596_NULL, "rx start w/ NULL begin! \n") - uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; - uti596_softc.scb.Rfd_val = word_swap ((unsigned long) uti596_softc.pBeginRFA); - uti596_softc.scb.command = RX_START | SCB_STAT_RNR; /* Don't ack RNR! The receiver - * should be stopped in this case */ - UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n") - i82596->chan_attn = 0x00000000; /* send CA signal */ - } - } - return; - } - } - else { - /* - * too late , pLastRfd in use ( or NULL ), - * in either case, EL bit has been read, and RNR condition will occur - */ - uti596append( &uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */ - uti596_softc.pEndSavedQueue = pRfd; /* reset end of saved queue */ - uti596_softc.savedCount++; - return; - } -} +/************************ PACKET DEBUG ROUTINES ************************/ -/*********************************************************************** - * Function: void uti596append - * - * Description: - * adds an RFD to the end of the received frame queue, - * for processing by the rxproc. - * Also removes this RFD from the RFA - * - * Algorithm: +#ifdef DBG_PACKETS + +/* + * dumpQ * - ***********************************************************************/ -void uti596append( - i596_rfd ** ppQ, - i596_rfd * pRfd -) + * Dumps frame queues for debugging + */ +static void dumpQ( void ) { + i596_rfd *pRfd; - i596_rfd *p; - - if ( pRfd != NULL && pRfd != I596_NULL) { - pRfd -> next = I596_NULL; - pRfd -> cmd |= CMD_EOL; /* set EL bit */ - - if ( *ppQ == NULL || *ppQ == I596_NULL ) { - /* empty list */ - *ppQ = pRfd; - } - else { - /* walk to the end of the list */ - for ( p=*ppQ; - p->next != I596_NULL; - p=(i596_rfd *) word_swap ((unsigned long)p->next) ); - - /* append the rfd */ - p->cmd &= ~CMD_EOL; /* Clear EL bit at end */ - p->next = (i596_rfd *) word_swap ((unsigned long)pRfd); - } + printk(("savedQ:\n")) + + for( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL; + pRfd = pRfd -> next) { + printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) } - else { - printk(("Illegal attempt to append: %p\n", pRfd)) + + printk(("Inbound:\n")) + + for( pRfd = uti596_softc.pInboundFrameQueue; + pRfd != I596_NULL; + pRfd = pRfd -> next) { + printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) + } + + printk(("Last Unk: %p\n", uti596_softc.pLastUnkRFD )) + printk(("RFA:\n")) + + for( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = pRfd -> next) { + printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) } } -/*********************************************************************** - * Function: void printk_time - * - * Description: - ***********************************************************************/ -void printk_time( void ) + +/* + * show_buffers + * + * Print out the RFA and frame queues + */ +static void show_buffers (void) { - rtems_time_of_day tm_struct; + i596_rfd *pRfd; + + printk(("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n", + uti596_softc.scb.command, + uti596_softc.scb.status, + uti596_softc.countRFD)) + + printk(("\nRFA: \n")) + + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = pRfd->next) { + printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd)) + } + printk(("\nInbound: \n")) + + for ( pRfd = uti596_softc.pInboundFrameQueue; + pRfd != I596_NULL; + pRfd = pRfd->next) { + printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd)) + } - rtems_clock_get(RTEMS_CLOCK_GET_TOD, &tm_struct); - printk(("Current time: %d:%d:%d \n", - tm_struct.hour, - tm_struct.minute, - tm_struct.second)) + printk(("\nSaved: \n")) + + for ( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL; + pRfd = pRfd->next) { + printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd)) + } + + printk(("\nUnknown: %p\n",uti596_softc.pLastUnkRFD)) } -/*********************************************************************** - * Function: void dump_scb + +/* + * show_queues * - * Description: - ***********************************************************************/ -void dump_scb( void ) + * Print out the saved frame queue and the RFA + */ +static void show_queues(void) { - printk(("status 0x%x\n",uti596_softc.scb.status)) - printk(("command 0x%x\n",uti596_softc.scb.command)) - printk(("cmd 0x%x\n",(int)uti596_softc.scb.pCmd)) - printk(("rfd 0x%x\n",(int)uti596_softc.scb.pRfd)) - printk(("crc_err 0x%x\n",uti596_softc.scb.crc_err)) - printk(("align_err 0x%x\n",uti596_softc.scb.align_err)) - printk(("resource_err 0x%x\n",uti596_softc.scb.resource_err )) - printk(("over_err 0x%x\n",uti596_softc.scb.over_err)) - printk(("rcvdt_err 0x%x\n",uti596_softc.scb.rcvdt_err)) - printk(("short_err 0x%x\n",uti596_softc.scb.short_err)) - printk(("t_on 0x%x\n",uti596_softc.scb.t_on)) - printk(("t_off 0x%x\n",uti596_softc.scb.t_off)) -} + i596_rfd *pRfd; + printk(("CMD: 0x%x, Status: 0x%x\n", + uti596_softc.scb.command, + uti596_softc.scb.status)) + printk(("saved Q\n")) + + for ( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL && + pRfd != NULL; + pRfd = pRfd->next) { + printk(("0x%p\n", pRfd)) + } -#ifdef DBG_INIT_3 + printk(("End saved Q 0x%p\n", uti596_softc.pEndSavedQueue)) - /*********************************************************************** - ** - ** Debugging Functions - ** - ***********************************************************************/ + printk(("\nRFA:\n")) + + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL && + pRfd != NULL; + pRfd = pRfd->next) { + printk(("0x%p\n", pRfd)) + } + printk(("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA)) +} - /*********************************************************************** - * Function: print_eth - * - * Description: - * Print the contents of an ethernet packet header - * CANNOT BE CALLED FROM ISR - * - * Algorithm: - * Print Destination, Src, and type of packet - * - ***********************************************************************/ -/* static */ void print_eth( +/* + * print_eth + * + * Print the contents of an ethernet packet + * CANNOT BE CALLED FROM ISR + */ +static void print_eth( unsigned char *add ) { @@ -2445,12 +2801,12 @@ void dump_scb( void ) for (i = 0; i < 6; i++) { printk ((" %2.2X", add[i])) - } + } printk (("\n")) printk (("Source")) for (i = 6; i < 12; i++) { - printk ((" %2.2X", add[i])) + printk ((" %2.2X", add[i])) } printk (("\n")) @@ -2467,19 +2823,19 @@ void dump_scb( void ) for ( i=0; i< 5 ; i++) { printk (("%x:", add[22 + i])) - } + } printk (("%x\n", add[27])) printk (("Sender IP addr: ")) for ( i=0; i< 3 ; i++) { printk (("%u.", add[28 + i])) - } + } printk (("%u\n", add[31])) printk (("Target Enet addr: ")) for ( i=0; i< 5 ; i++) { printk (( "%x:", add[32 + i])) - } + } printk (("%x\n", add[37])) printk (("Target IP addr: ")) @@ -2489,7 +2845,9 @@ void dump_scb( void ) printk (("%u\n", add[41])) } - if ( add[12] == 0x08 && add[13] == 0x00 ) { /* an IP packet */ + + if ( add[12] == 0x08 && add[13] == 0x00 ) { + /* an IP packet */ printk (("*********************IP HEADER******************\n")) printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15])) printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] ))) @@ -2502,41 +2860,25 @@ void dump_scb( void ) for ( i=0; i< 3 ; i++) { printk (("%u.", add[26 + i])) - } + } printk (("%u\n", add[29])) printk (("Destination IP address: ")) for ( i=0; i< 3 ; i++) { printk (("%u.", add[30 + i])) - } - printk (("%u\n", add[33])) - /* printk(("********************IP Packet Data*******************\n")) - length -=20; - for ( i=0; i < length ; i++) { - printk(("0x%2.2x ", add[34+i])) } - printk(("\n")) - - printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37])) - printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39])) - printk(("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41])) - */ + printk (("%u\n", add[33])) } } - /*********************************************************************** - * Function: print_hdr - * - * Description: - * Print the contents of an ethernet packet header - * CANNOT BE CALLED FROM ISR - * - * Algorithm: - * Print Destination, Src, and type of packet - * - ***********************************************************************/ - -/* static */ void print_hdr( + +/* + * print_hdr + * + * Print the contents of an ethernet packet header + * CANNOT BE CALLED FROM ISR + */ +static void print_hdr( unsigned char *add ) { @@ -2548,29 +2890,24 @@ void dump_scb( void ) for (i = 0; i < 6; i++) { printk ((" %2.2X", add[i])) - } + } printk (("\nSource")) for (i = 6; i < 12; i++) { printk ((" %2.2X", add[i])) - } + } printk (("\nframe type %2.2X%2.2X\n", add[12], add[13])) printk (("print_hdr: completed")) } - /*********************************************************************** - * Function: print_pkt - * - * Description: - * Print the contents of an ethernet packet header - * CANNOT BE CALLED FROM ISR - * - * Algorithm: - * Print Destination, Src, and type of packet - * - ***********************************************************************/ - -/* static */ void print_pkt( + +/* + * Function: print_pkt + * + * Print the contents of an ethernet packet & data + * CANNOT BE CALLED FROM ISR + */ +static void print_pkt( unsigned char *add ) { @@ -2591,18 +2928,18 @@ void dump_scb( void ) for ( i=0; i< 5 ; i++) { printk (( "%x:", add[22 + i])) - } + } printk (("%x\n", add[27])) printk (("Sender IP addr: ")) for ( i=0; i< 3 ; i++) { printk (("%u.", add[28 + i])) - } + } printk (("%u\n", add[31])) printk (("Target Enet addr: ")) for ( i=0; i< 5 ; i++) { - printk (( "%x:", add[32 + i])) + printk (( "%x:", add[32 + i])) } printk (("%x\n", add[37])) printk (("Target IP addr: ")) @@ -2627,7 +2964,7 @@ void dump_scb( void ) for ( i=0; i< 3 ; i++) { printk(( "%u.", add[26 + i])) - } + } printk(("%u\n", add[29])) printk(("Destination IP address: ")) @@ -2649,19 +2986,14 @@ void dump_scb( void ) } } - /*********************************************************************** - * Function: print_echo - * - * Description: - * Print the contents of an ethernet packet header - * CANNOT BE CALLED FROM ISR - * - * Algorithm: - * Prints only echo packets - * - ***********************************************************************/ - -/* static */ void print_echo( + +/* + * print_echo + * + * Print the contents of an echo packet + * CANNOT BE CALLED FROM ISR + */ +static void print_echo( unsigned char *add ) { @@ -2677,13 +3009,13 @@ void dump_scb( void ) for (i = 0; i < 6; i++) { printk ((" %2.2X", add[i])) - } + } printk (("\n")) printk (("Source")) for (i = 6; i < 12; i++) { printk ((" %2.2X", add[i])) - } + } printk (("\n")) printk (("frame type %2.2X%2.2X\n", add[12], add[13])) @@ -2699,7 +3031,7 @@ void dump_scb( void ) for ( i=0; i< 3 ; i++) { printk (("%u.", add[26 + i])) - } + } printk (("%u\n", add[29])) printk (("Destination IP address: ")) @@ -2712,7 +3044,7 @@ void dump_scb( void ) for ( i=0; i < length ; i++) { printk(("0x%2.2x ", add[34+i])) - } + } printk(("\n")) printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37])) printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39])) @@ -2721,169 +3053,4 @@ void dump_scb( void ) } } -#endif - -/*********************************************************************** - * Function: uti596dump - * - * Description: Dump 596 registers - * - * Algorithm: - ***********************************************************************/ -/* static */ int uti596dump( - char * pDumpArea -) -{ - i596_dump dumpCmd; - int boguscnt = 25000000; /* over a second! */ - -#ifdef DBG_596 - printk(("uti596dump: begin\n")) -#endif - - dumpCmd.cmd.command = CmdDump; - dumpCmd.cmd.next = I596_NULL; - dumpCmd.pData = pDumpArea; - uti596_softc.cmdOk = 0; - uti596addCmd ( (i596_cmd *)&dumpCmd); - while (1) { - if ( --boguscnt == 0) { - printk(("Dump command was not processed within spin loop delay\n")) - return 0; - } - else { - if ( uti596_softc.cmdOk ) { - return 1; /* successful completion */ - } - } - } -} - -/*********************************************************************** - * Function: void dumpQ - * - * Description: - ***********************************************************************/ -void dumpQ( void ) -{ - i596_rfd *pRfd; - - printk(("savedQ:\n")) - - for( pRfd = uti596_softc.pSavedRfdQueue; - pRfd != I596_NULL; - pRfd = pRfd -> next) { - printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) - } - - printk(("Inbound:\n")) - - for( pRfd = uti596_softc.pInboundFrameQueue; - pRfd != I596_NULL; - pRfd = pRfd -> next) { - printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) - } - - printk(("Last Unk: %p\n", uti596_softc.pLastUnkRFD )) - printk(("RFA:\n")) - - for( pRfd = uti596_softc.pBeginRFA; - pRfd != I596_NULL; - pRfd = pRfd -> next) { - printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd)) - } -} - - -/*********************************************************************** - * Function: void show_buffers - * - * Description: - ***********************************************************************/ -void show_buffers (void) -{ - i596_rfd *pRfd; - - printk(("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n", - uti596_softc.scb.command, - uti596_softc.scb.status, - uti596_softc.countRFD)) - - printk(("\nRFA: \n")) - - for ( pRfd = uti596_softc.pBeginRFA; - pRfd != I596_NULL; - pRfd = pRfd->next) { - printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", - pRfd, pRfd->stat, pRfd->cmd)) - } - printk(("\nInbound: \n")) - - for ( pRfd = uti596_softc.pInboundFrameQueue; - pRfd != I596_NULL; - pRfd = pRfd->next) { - printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", - pRfd, pRfd->stat, pRfd->cmd)) - } - - printk(("\nSaved: \n")) - - for ( pRfd = uti596_softc.pSavedRfdQueue; - pRfd != I596_NULL; - pRfd = pRfd->next) { - printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n", - pRfd, pRfd->stat, pRfd->cmd)) - } - - printk(("\nUnknown: %p\n",uti596_softc.pLastUnkRFD)) -} - -/*********************************************************************** - * Function: void show_queues - * - * Description: - ***********************************************************************/ -void show_queues(void) -{ - i596_rfd *pRfd; - - printk(("CMD: 0x%x, Status: 0x%x\n", - uti596_softc.scb.command, - uti596_softc.scb.status)) - printk(("saved Q\n")) - - for ( pRfd = uti596_softc.pSavedRfdQueue; - pRfd != I596_NULL && - pRfd != NULL; - pRfd = pRfd->next) { - printk(("0x%p\n", pRfd)) - } - - printk(("End saved Q 0x%p\n", uti596_softc.pEndSavedQueue)) - - printk(("\nRFA:\n")) - - for ( pRfd = uti596_softc.pBeginRFA; - pRfd != I596_NULL && - pRfd != NULL; - pRfd = pRfd->next) { - printk(("0x%p\n", pRfd)) - } - - printk(("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA)) -} - - /*********************************************************************** - * Function: word_swap - * - * Description: - * Return a 32 bit value, swapping the upper - * and lower words first. - * - ***********************************************************************/ -unsigned long word_swap (unsigned long val) -{ - return (((val >> 16)&(0x0000ffff)) | ((val << 16)&(0xffff0000))); -} - - +#endif \ No newline at end of file diff --git a/c/src/lib/libbsp/m68k/mvme167/network/uti596.h b/c/src/lib/libbsp/m68k/mvme167/network/uti596.h index 5757767526..d1d3d1ae2e 100644 --- a/c/src/lib/libbsp/m68k/mvme167/network/uti596.h +++ b/c/src/lib/libbsp/m68k/mvme167/network/uti596.h @@ -3,7 +3,6 @@ /* * EII: March 11: Created v. 0.0 - * Jan 12/98 Added STAT bits, s11-=s5 and max_colls. * * $Id$ */ @@ -55,14 +54,11 @@ struct enet_statistics{ int nic_reset_count; /* The number of times uti596reset() has been called. */ }; -#define UTI596_MUTEX 1 - - #define CMD_EOL 0x8000 /* The last command of the list, stop. */ #define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ #define CMD_INTR 0x2000 /* Interrupt after doing cmd. */ -#define CMD_FLEX 0x0008 /* Enable flexible memory model */ +#define CMD_FLEX 0x0008 /* Enable flexible memory model */ #define SCB_STAT_CX 0x8000 /* Cmd completes with 'I' bit set */ #define SCB_STAT_FR 0x4000 /* Frame Received */ @@ -72,7 +68,6 @@ struct enet_statistics{ #define SCB_CUS_SUSPENDED 0x0100 #define SCB_CUS_ACTIVE 0x0200 - #define STAT_C 0x8000 /* Set to 1 after execution */ #define STAT_B 0x4000 /* 1 : Cmd being executed, 0 : Cmd done. */ #define STAT_OK 0x2000 /* 1: Command executed ok 0 : Error */ @@ -87,8 +82,6 @@ struct enet_statistics{ #define STAT_S5 0x0020 #define STAT_MAX_COLLS 0x000F - - #define RBD_STAT_P 0x4000 /* prefetch */ #define RBD_STAT_F 0x4000 /* used */ @@ -105,17 +98,11 @@ struct enet_statistics{ #define RU_NO_RESOURCES 0x0020 #define RU_READY 0x0040 - -#define IO_ADDR 0x360 -#define PORT_ADDR IO_ADDR -#define CHAN_ATTN PORT_ADDR + 4 -#define NIC_ADDR PORT_ADDR + 8 - #define I596_NULL ( ( void * ) 0xffffffff) #define UTI_596_END_OF_FRAME 0x8000 -#define SIZE_MASK 0x3fff -struct i596_tbd; + +struct i596_tbd; /* necessary forward declaration */ enum commands { CmdNOp = 0, @@ -128,14 +115,100 @@ enum commands { CmdDiagnose = 7 }; +/* + * 82596 Dump Command Result + */ +typedef volatile struct i596_dump_result { + unsigned char bf; + unsigned char config_bytes[11]; + unsigned char reserved1[2]; + unsigned char ia_bytes[6]; + unsigned short last_tx_status; + unsigned short tx_crc_byte01; + unsigned short tx_crc_byte23; + unsigned short rx_crc_byte01; + unsigned short rx_crc_byte23; + unsigned short rx_temp_mem01; + unsigned short rx_temp_mem23; + unsigned short rx_temp_mem45; + unsigned short last_rx_status; + unsigned short hash_reg01; + unsigned short hash_reg23; + unsigned short hash_reg45; + unsigned short hash_reg67; + unsigned short slot_time_counter; + unsigned short wait_time_counter; + unsigned short rx_frame_length; + unsigned long reserved2; + unsigned long cb_in3; + unsigned long cb_in2; + unsigned long cb_in1; + unsigned long la_cb_addr; + unsigned long rdb_pointer; + unsigned long int_memory; + unsigned long rfd_size; + unsigned long tbd_pointer; + unsigned long base_addr; + unsigned long ru_temp_reg; + unsigned long tcb_count; + unsigned long next_rb_size; + unsigned long next_rb_addr; + unsigned long curr_rb_size; + unsigned long la_rbd_addr; + unsigned long next_rbd_addr; + unsigned long curr_rbd_addr; + unsigned long curr_rb_count; + unsigned long next_fd_addr; + unsigned long curr_fd_add; + unsigned long temp_cu_reg; + unsigned long next_tb_count; + unsigned long buffer_addr; + unsigned long la_tbd_addr; + unsigned long next_tbd_addr; + unsigned long cb_command; + unsigned long next_cb_addr; + unsigned long curr_cb_addr; + unsigned long scb_cmd_word; + unsigned long scb_pointer; + unsigned long cb_stat_word; + unsigned long mm_lfsr; + unsigned char micro_machine_bit_array[28]; + unsigned char cu_port[16]; + unsigned long mm_alu; + unsigned long reserved3; + unsigned long mm_temp_a_rr; + unsigned long mm_temp_a; + unsigned long tx_dma_b_cnt; + unsigned long mm_input_port_addr_reg; + unsigned long tx_dma_addr; + unsigned long mm_port_reg1; + unsigned long rx_dma_b_cnt; + unsigned long mm_port_reg2; + unsigned long rx_dma_addr; + unsigned long reserved4; + unsigned long bus_t_timers; + unsigned long diu_cntrl_reg; + unsigned long reserved5; + unsigned long sysbus; + unsigned long biu_cntrl_reg; + unsigned long mm_disp_reg; + unsigned long mm_status_reg; + unsigned short dump_status; +} i596_dump_result; + +typedef volatile struct i596_selftest { + unsigned long rom_signature; + unsigned long results; +} i596_selftest; + /* * Action commands * (big endian, linear mode) - */ + */ typedef volatile struct i596_cmd { - volatile unsigned short status; - volatile unsigned short command; - volatile struct i596_cmd *next; + unsigned short status; + unsigned short command; + struct i596_cmd *next; } i596_cmd; typedef volatile struct i596_nop { @@ -144,21 +217,21 @@ typedef volatile struct i596_nop { typedef volatile struct i596_set_add { i596_cmd cmd; - char data[8]; + char data[8]; } i596_set_add; typedef volatile struct i596_configure { i596_cmd cmd; - char data[16]; + char data[16]; } i596_configure; typedef volatile struct i596_tx { - i596_cmd cmd; - volatile struct i596_tbd *pTbd; - unsigned short count; - unsigned short pad; - char data[6]; - unsigned short length; + i596_cmd cmd; + struct i596_tbd *pTbd; + unsigned short count; + unsigned short pad; + char data[6]; + unsigned short length; } i596_tx; typedef volatile struct i596_tdr { @@ -168,17 +241,17 @@ typedef volatile struct i596_tdr { typedef volatile struct i596_dump { i596_cmd cmd; - char *pData; + char *pData; } i596_dump; /* * Transmit buffer descriptor */ typedef volatile struct i596_tbd { - unsigned short size; - unsigned short pad; - volatile struct i596_tbd *next; - char *data; + unsigned short size; + unsigned short pad; + struct i596_tbd *next; + char *data; } i596_tbd; /* @@ -186,113 +259,115 @@ typedef volatile struct i596_tbd { * (flexible memory structure) */ typedef volatile struct i596_rbd { - unsigned short count; - unsigned short offset; - volatile struct i596_rbd *next; - char *data; - unsigned short size; - unsigned short pad; + unsigned short count; + unsigned short offset; + struct i596_rbd *next; + char *data; + unsigned short size; + unsigned short pad; } i596_rbd; /* * Receive Frame Descriptor */ typedef volatile struct i596_rfd { - volatile unsigned short stat; - volatile unsigned short cmd; - volatile struct i596_rfd *next; - i596_rbd *pRbd; - unsigned short count; - unsigned short size; - char data [1532]; + unsigned short stat; + unsigned short cmd; + struct i596_rfd *next; + i596_rbd *pRbd; + unsigned short count; + unsigned short size; + char data [1532]; } i596_rfd; -#define RX_RING_SIZE 8 - /* * System Control Block */ typedef volatile struct i596_scb { - volatile unsigned short status; - volatile unsigned short command; - volatile unsigned long Cmd_val; - volatile unsigned long Rfd_val; - volatile unsigned long crc_err; - volatile unsigned long align_err; - volatile unsigned long resource_err; - volatile unsigned long over_err; - volatile unsigned long rcvdt_err; - volatile unsigned long short_err; - volatile unsigned short t_off; - volatile unsigned short t_on; - i596_cmd *pCmd; - i596_rfd *pRfd; + unsigned short status; + unsigned short command; + unsigned long cmd_pointer; + unsigned long rfd_pointer; + unsigned long crc_err; + unsigned long align_err; + unsigned long resource_err; + unsigned long over_err; + unsigned long rcvdt_err; + unsigned long short_err; + unsigned short t_off; + unsigned short t_on; + i596_cmd *pCmd; + i596_rfd *pRfd; } i596_scb; /* * Intermediate System Configuration Pointer */ typedef volatile struct i596_iscp { - volatile unsigned long stat; - volatile unsigned long scb_val; - i596_scb *scb; + unsigned8 null1; /* Always zero */ + unsigned8 busy; /* Busy byte */ + unsigned short scb_offset; /* Not used in linear mode */ + unsigned long scb_pointer; /* Swapped pointer to scb */ + i596_scb *scb; /* Real pointer to scb */ } i596_iscp; /* * System Configuration Pointer */ typedef volatile struct i596_scp { - unsigned long sysbus; - unsigned long pad; - unsigned long iscp_val; - i596_iscp *iscp; + unsigned long sysbus; /* Only low 8 bits are used */ + unsigned long pad; /* Must be zero */ + unsigned long iscp_pointer; /* Swapped pointer to iscp */ + i596_iscp *iscp; /* Real pointer to iscp */ } i596_scp; +/* + * Device Dependent Data Structure + */ typedef volatile struct uti596_softc { - struct arpcom arpcom; - i596_scp *pScp; - i596_iscp iscp; - i596_scb scb; - i596_set_add set_add; - i596_configure set_conf; - i596_tdr tdr; - i596_nop nop; - unsigned long stat; - i596_tx *pTxCmd; - i596_tbd *pTbd; - - int ioAddr; - - i596_rfd *pBeginRFA; - i596_rfd *pEndRFA; - i596_rfd *pLastUnkRFD; - i596_rbd *pLastUnkRBD; - i596_rfd *pEndSavedQueue; - i596_cmd *pCmdHead; - i596_cmd *pCmdTail; /* unneeded, as chaining not used, but implemented */ - - rtems_id rxDaemonTid; - rtems_id txDaemonTid; - rtems_id resetDaemonTid; + struct arpcom arpcom; + i596_scp *pScp; /* Block aligned on 16 byte boundary */ + i596_scp *base_scp; /* Unaligned block. Need for free() */ + i596_iscp iscp; + i596_scb scb; + i596_set_add set_add; + i596_configure set_conf; + i596_tdr tdr; + i596_nop nop; + i596_tx *pTxCmd; + i596_tbd *pTbd; + + i596_rfd *pBeginRFA; + i596_rfd *pEndRFA; + i596_rfd *pLastUnkRFD; + i596_rbd *pLastUnkRBD; + i596_rfd *pEndSavedQueue; + i596_cmd *pCmdHead; + i596_cmd *pCmdTail; /* unneeded, as chaining not used, but implemented */ + + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + rtems_id resetDaemonTid; struct enet_statistics stats; - int started; - unsigned long rxInterrupts; - unsigned long txInterrupts; - volatile int cmdOk; - int resetDone; - unsigned long txRawWait; - i596_rfd *pInboundFrameQueue; - short int rxBdCount; - short int txBdCount; - short int countRFD; - short int savedCount; - i596_rfd *pSavedRfdQueue; - rtems_name semaphore_name; - rtems_id semaphore_id; - char zeroes[64]; - unsigned long rawsndcnt; - int nic_reset; /* flag is for requesting that ISR issue a reset quest */ + int started; + unsigned long rxInterrupts; + unsigned long txInterrupts; + volatile int cmdOk; + unsigned short * pCurrent_command_status; + int resetDone; + unsigned long txRawWait; + i596_rfd *pInboundFrameQueue; + short int rxBdCount; + short int txBdCount; + short int countRFD; + short int savedCount; + i596_rfd *pSavedRfdQueue; + rtems_name semaphore_name; + rtems_id semaphore_id; + char zeroes[64]; + unsigned long rawsndcnt; + int nic_reset; /* flag for requesting that ISR issue a reset quest */ } uti596_softc_; #endif /* UTI596_H */ diff --git a/c/src/lib/libbsp/m68k/mvme167/start/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/start/Makefile.am index 012c72b1e4..afb2a158f7 100644 --- a/c/src/lib/libbsp/m68k/mvme167/start/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/start/Makefile.am @@ -1,6 +1,6 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 diff --git a/c/src/lib/libbsp/m68k/mvme167/startup/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/startup/Makefile.am index 0ae5078b6f..e5f1fdd3a6 100644 --- a/c/src/lib/libbsp/m68k/mvme167/startup/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/startup/Makefile.am @@ -1,6 +1,6 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 @@ -23,7 +23,6 @@ include $(top_srcdir)/../../../../../../automake/lib.am # # USE_INIT_FINI tells main.c what C++ help we need. - AM_CPPFLAGS += -DUSE_INIT_FINI $(PGM): $(OBJS) @@ -32,16 +31,12 @@ $(PGM): $(OBJS) $(PROJECT_RELEASE)/lib/linkcmds: linkcmds $(INSTALL_DATA) $< $@ -$(PROJECT_RELEASE)/lib/elflinkcmds: elflinkcmds - $(INSTALL_DATA) $< $@ - -TMPINSTALL_FILES += $(PROJECT_RELEASE)/lib/linkcmds \ - $(PROJECT_RELEASE)/lib/elflinkcmds +TMPINSTALL_FILES += $(PROJECT_RELEASE)/lib/linkcmds all-local: $(ARCH) $(OBJS) $(PGM) $(TMPINSTALL_FILES) .PRECIOUS: $(PGM) -EXTRA_DIST = bspclean.c bspstart.c elflinkcmds linkcmds page_table.c +EXTRA_DIST = bspclean.c bspstart.c linkcmds page_table.c include $(top_srcdir)/../../../../../../automake/local.am diff --git a/c/src/lib/libbsp/m68k/mvme167/startup/bspstart.c b/c/src/lib/libbsp/m68k/mvme167/startup/bspstart.c index f443a48153..05f78e0c85 100644 --- a/c/src/lib/libbsp/m68k/mvme167/startup/bspstart.c +++ b/c/src/lib/libbsp/m68k/mvme167/startup/bspstart.c @@ -79,15 +79,18 @@ void bsp_pretasking_hook(void); /* m68k version */ */ void bsp_start( void ) { - extern void *_WorkspaceBase; - extern m68k_isr_entry M68Kvec[]; - extern void *_WorkspaceBase; - void M68KFPSPInstallExceptionHandlers (void); + extern m68k_isr_entry M68Kvec[]; + extern void *_WorkspaceBase; + extern void *_RamSize; + extern unsigned long _M68k_Ramsize; + m68k_isr_entry *rom_monitor_vector_table; int index; + _M68k_Ramsize = (unsigned long)&_RamSize; /* RAM size set in linker script */ + /* * 167Bug Vectors are at 0xFFE00000 */ @@ -129,7 +132,8 @@ void bsp_start( void ) Cpu_table.pretasking_hook = bsp_pretasking_hook; /* init libc, etc. */ Cpu_table.postdriver_hook = bsp_postdriver_hook; Cpu_table.interrupt_vector_table = (m68k_isr_entry *) &M68Kvec; - Cpu_table.interrupt_stack_size = 4096; /* Must match value in start.s */ + /* Must match value in start.s */ + Cpu_table.interrupt_stack_size = CONFIGURE_INTERRUPT_STACK_MEMORY; /* * If the application has not overriden the default User_extension_table, @@ -147,19 +151,4 @@ void bsp_start( void ) * not malloc'ed. It is just "pulled from the air". */ BSP_Configuration.work_space_start = (void *)&_WorkspaceBase; - - /* - * Increase the number of semaphores that can be created on this node. The - * termios package requires one semaphore to protect the list of termios- - * capable terminals, and up to four semaphores per termios-capable - * terminal (add calls here as required). The maximum number of semaphores - * must be set before returning to boot_card(), which will call - * rtems_initialize_executive_early(). This latter function eventually - * calls _RTEMS_API_Initialize(), which in turn calls - * _Semaphore_Manager_initialization(), which allocates the space for the - * maximum number of semaphores in the object table. These calls occur - * before the call to the predriver hook and the calls to the device - * initialization callbacks. Hence, we must do this here. - */ - console_reserve_resources( &BSP_Configuration ); } diff --git a/c/src/lib/libbsp/m68k/mvme167/startup/linkcmds b/c/src/lib/libbsp/m68k/mvme167/startup/linkcmds index 9cbf889dd7..c22f578905 100644 --- a/c/src/lib/libbsp/m68k/mvme167/startup/linkcmds +++ b/c/src/lib/libbsp/m68k/mvme167/startup/linkcmds @@ -22,11 +22,11 @@ OUTPUT_ARCH(m68k) ENTRY(_start) /* - * Declare some sizes. + * Declare some sizes. Heap is sized at whatever ram space is left. */ -_RamBase = 0x00800000; +_RamBase = DEFINED(_RamBase) ? _RamBase : 0x00800000; _RamSize = DEFINED(_RamSize) ? _RamSize : 4M; -_HeapSize = DEFINED(_HeapSize) ? _HeapSize : 0x10000; +_HeapSize = DEFINED(_HeapSize) ? _HeapSize : 0; _StackSize = DEFINED(_StackSize) ? _StackSize : 0x1000; MEMORY @@ -42,103 +42,144 @@ MEMORY SECTIONS { - ram : { - . = .; - } >ram + /* + * Text, data and bss segments + */ + .text : { + *(.text) - /* - * Text, data and bss segments - */ - .text : { - *(.text) + /* + * C++ constructors/destructors + */ + *(.gnu.linkonce.t.*) - /* - * C++ constructors/destructors - */ - *(.gnu.linkonce.t.*) + /* + * Initialization and finalization code. + * + * Various files can provide initialization and finalization + * functions. crtbegin.o and crtend.o are two instances. The + * body of these functions are in .init and .fini sections. We + * accumulate the bodies here, and prepend function prologues + * from crti.o and function epilogues from crtn.o. crti.o must + * be linked first; crtn.o must be linked last. Because these + * are wildcards, it doesn't matter if the user does not + * actually link against crti.o and crtn.o; the linker won't + * look for a file to match a wildcard. The wildcard also + * means that it doesn't matter which directory crti.o and + * crtn.o are in. + */ + PROVIDE (_init = .); + *crti.o(.init) + *(.init) + *crtn.o(.init) + + PROVIDE (_fini = .); + *crti.o(.fini) + *(.fini) + *crtn.o(.fini) - /* - * Initialization and finalization code. - * - * Various files can provide initialization and finalization - * functions. crtbegin.o and crtend.o are two instances. The - * body of these functions are in .init and .fini sections. We - * accumulate the bodies here, and prepend function prologues - * from crti.o and function epilogues from crtn.o. crti.o must - * be linked first; crtn.o must be linked last. Because these - * are wildcards, it doesn't matter if the user does not - * actually link against crti.o and crtn.o; the linker won't - * look for a file to match a wildcard. The wildcard also - * means that it doesn't matter which directory crti.o and - * crtn.o are in. - */ - PROVIDE (_init = .); - *crti.o(.init) - *(.init) - *crtn.o(.init) - PROVIDE (_fini = .); - *crti.o(.fini) - *(.fini) - *crtn.o(.fini) + /* + * C++ constructors/destructors + * + * gcc uses crtbegin.o to find the start of the constructors + * and destructors so we make sure it is first. Because this + * is a wildcard, it doesn't matter if the user does not + * actually link against crtbegin.o; the linker won't look for + * a file to match a wildcard. The wildcard also means that + * it doesn't matter which directory crtbegin.o is in. The + * constructor and destructor list are terminated in + * crtend.o. The same comments apply to it. + */ + . = ALIGN (16); + *crtbegin.o(.ctors) + *(.ctors) + *crtend.o(.ctors) + + *crtbegin.o(.dtors) + *(.dtors) + *crtend.o(.dtors) - /* - * C++ constructors/destructors - * - * gcc uses crtbegin.o to find the start of the constructors - * and destructors so we make sure it is first. Because this - * is a wildcard, it doesn't matter if the user does not - * actually link against crtbegin.o; the linker won't look for - * a file to match a wildcard. The wildcard also means that - * it doesn't matter which directory crtbegin.o is in. The - * constructor and destructor list are terminated in - * crtend.o. The same comments apply to it. - */ - . = ALIGN (16); - *crtbegin.o(.ctors) - *(.ctors) - *crtend.o(.ctors) - *crtbegin.o(.dtors) - *(.dtors) - *crtend.o(.dtors) + /* + * Exception frame info + */ + . = ALIGN (16); + *(.eh_frame) - /* - * Exception frame info - */ - . = ALIGN (16); - *(.eh_frame) + /* + * Read-only data + */ + . = ALIGN (16); + PROVIDE(_rodata_start = . ); + *(.rodata) + *(.gnu.linkonce.r*) + PROVIDE(_erodata = . ); - /* - * Read-only data - */ - . = ALIGN (16); - _rodata_start = . ; - *(.rodata) - *(.gnu.linkonce.r*) + . = ALIGN (16); + PROVIDE (_etext = .); + } >ram + + .data : { + PROVIDE (_copy_start = .); + *(.data) + *(.gnu.linkonce.d*) + *(.gcc_except_table) + . = ALIGN (16); + PROVIDE (_edata = .); + PROVIDE (_copy_end = .); + } >ram + + .bss : { + _clear_start = .; + *(.bss) + *(COMMON) + . = ALIGN (16); + PROVIDE (end = .); - . = ALIGN (16); - PROVIDE (_etext = .); - } >ram - .data : { - PROVIDE (_copy_start = .); - *(.data) - *(.gnu.linkonce.d*) - *(.gcc_except_table) - . = ALIGN (16); - PROVIDE (_edata = .); - PROVIDE (_copy_end = .); - } >ram - .bss : { - _clear_start = .; - *(.bss) - *(COMMON) - . = ALIGN (16); - PROVIDE (end = .); + . += _StackSize; + . = ALIGN (16); + _stack_init = .; + _clear_end = .; - . += _StackSize; - . = ALIGN (16); - _stack_init = .; - _clear_end = .; + _WorkspaceBase = .; + } >ram - _WorkspaceBase = .; - } >ram + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ } diff --git a/c/src/lib/libbsp/m68k/mvme167/startup/page_table.c b/c/src/lib/libbsp/m68k/mvme167/startup/page_table.c index 5d44f3159b..ebbcc9739d 100644 --- a/c/src/lib/libbsp/m68k/mvme167/startup/page_table.c +++ b/c/src/lib/libbsp/m68k/mvme167/startup/page_table.c @@ -79,7 +79,7 @@ void page_table_init( * E = 0b1 enable address translation * S-Field = 0b1X ignore FC2 when matching * U1, U0 = 0b00 user page attributes not used - * CM = 0b01 cachable, writethrough + * CM = 0b01 cachable, copyback * W = 0b0 read/write access allowed */ dtt0 = 0x007FC020; diff --git a/c/src/lib/libbsp/m68k/mvme167/timer/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/timer/Makefile.am index c7692ccadc..c85ca86376 100644 --- a/c/src/lib/libbsp/m68k/mvme167/timer/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/timer/Makefile.am @@ -1,6 +1,6 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 diff --git a/c/src/lib/libbsp/m68k/mvme167/wrapup/Makefile.am b/c/src/lib/libbsp/m68k/mvme167/wrapup/Makefile.am index 90acf83471..cf6c8ecb38 100644 --- a/c/src/lib/libbsp/m68k/mvme167/wrapup/Makefile.am +++ b/c/src/lib/libbsp/m68k/mvme167/wrapup/Makefile.am @@ -1,15 +1,19 @@ -## +## ## $Id$ -## +## AUTOMAKE_OPTIONS = foreign 1.4 -BSP_PIECES = clock console fatal startup timer +# We only build the networking device driver if HAS_NETWORKING was defined +if HAS_NETWORKING +NETWORKING_DRIVER = network +endif + +BSP_PIECES = clock console fatal startup timer $(NETWORKING_DRIVER) # bummer; have to use $foreach since % pattern subst rules only replace 1x OBJS = $(foreach piece, $(BSP_PIECES), $(wildcard ../$(piece)/$(ARCH)/*.o)) \ - $(wildcard \ - ../../../../libcpu/$(RTEMS_CPU)/$(RTEMS_CPU_MODEL)/fpsp/$(ARCH)/fpsp.rel) + $(wildcard ../../../../libcpu/$(RTEMS_CPU)/$(RTEMS_CPU_MODEL)/fpsp/$(ARCH)/fpsp.rel) LIB = $(ARCH)/libbsp.a -- cgit v1.2.3