summaryrefslogtreecommitdiff
path: root/ecos/packages/devs/eth/mips/upd985xx/current
diff options
context:
space:
mode:
Diffstat (limited to 'ecos/packages/devs/eth/mips/upd985xx/current')
-rw-r--r--ecos/packages/devs/eth/mips/upd985xx/current/ChangeLog254
-rw-r--r--ecos/packages/devs/eth/mips/upd985xx/current/cdl/upd985xx_eth_drivers.cdl204
-rw-r--r--ecos/packages/devs/eth/mips/upd985xx/current/include/upd985xx_eth.h464
-rw-r--r--ecos/packages/devs/eth/mips/upd985xx/current/src/if_upd985xx.c1610
4 files changed, 2532 insertions, 0 deletions
diff --git a/ecos/packages/devs/eth/mips/upd985xx/current/ChangeLog b/ecos/packages/devs/eth/mips/upd985xx/current/ChangeLog
new file mode 100644
index 0000000..4ed1ef6
--- /dev/null
+++ b/ecos/packages/devs/eth/mips/upd985xx/current/ChangeLog
@@ -0,0 +1,254 @@
+2002-06-14 Gary Thomas <gary@chez-thomas.org>
+
+ * src/if_upd985xx.c:
+ Need to include <pkgconf/io_eth_drivers.h> for proper configuration
+ of stand-alone (polled) vs. system (interrupt driven) mode.
+
+2001-09-13 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (upd985xx_eth_upd985xx_init): Fake an ESA if
+ we see all ones from the EEPROM as well as all zeros.
+
+2001-08-30 Hugo Tyson <hmt@redhat.com>
+
+ * cdl/upd985xx_eth_drivers.cdl: Make the "..._E2ONLY" workaround
+ option on by default since this is how it will be used - the CPU
+ load does suffer somewhat if promisc mode is set in the hardware.
+ This should be unset to allow the workaround for E1 at 100Mbit.
+
+2001-08-30 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (PacketRxReady): Re-write the manual
+ implementation of ESA matching for workaround E1E2 when the device
+ is in promiscuous mode. It was having problems with the previous
+ version; this works better.
+
+2001-08-24 Hugo Tyson <hmt@redhat.com>
+
+ * cdl/upd985xx_eth_drivers.cdl: Configury for an alternate case
+ where we workaround hardware bug E2 only, as a subset of the E1E2
+ complete fix. Added more description to the options too.
+
+ * src/if_upd985xx.c (eth_upd985xx_configure): Handle an alternate
+ case where we workaround hardware bug E2 only. This means leaving
+ the device in normal mode (unless set to promisc) and doing MAC
+ address filtering by hand anyway.
+
+2001-08-20 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c: Guard all entrypoints that can mess with
+ hardware state by "active" check. If the net is included in an
+ app, but not used, it is init'd but not started - this can leave a
+ pending interrupt from RedBoot's use of the network to take us
+ completely by surprise. So init() acks and masks the interrupt,
+ can_send(), recv() and deliver() now demur if not active.
+ Also some additional STATIC's on entrypoint functions.
+
+2001-08-16 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (upd985xx_eth_upd985xx_init): If the EEPROM
+ contains nothing (or isn't fitted?) fake an ESA so we can get
+ RedBoot going on the board without special configury.
+
+2001-08-16 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (eth_upd985xx_configure): Use smaller numbers
+ for the Tx Fill Threshold [TX_FLTH] and DMA Tx Burst Size [DTBS]
+ because the hardware is even more broken than first throught -
+ this is new information on fault E4. I also tagged this with the
+ name of the option we would use if this were cdl controlled - but
+ since it's just setup I see no need to change it, so no CDL.
+
+2001-08-16 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (TxDone): Since it still wedged occasionally,
+ with an "out of rx buffers" status but nothing else, this is a
+ much simplified workaround for bug E8. If we see the suspect
+ transmit status, simply reset the whole subsystem there and then.
+ This leaves it in far more of a known state. It's neater anyway.
+
+2001-08-15 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (eth_upd985xx_send): Small hacks to recover
+ from various wedged states with bogus or unexpected ETH_ISR
+ values... 0x80000000: We detect this in the deliver routine and
+ totally reset the system. "out of rx buffers" with no "good rx":
+ we unmask and check for all these RX interrupts, not just "good
+ rx". Also PacketRxReady() shortcuts to resetting the receive
+ engine when it sees the problem. I suspect these might be caused
+ by the E8 workaround below, perhaps introducing some race
+ condition with turning off the receiver just when it rx'd - and of
+ course E1E2 means it receives far more packets.
+
+2001-08-07 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c: Workaround various bugs in the hardware;
+ these workarounds are conditionally compiled via CDL options named
+ CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_xxx in general; 'xxx'
+ is the reference for the mis-feature. All are enabled by default.
+
+ To summarize:
+ (eth_upd985xx_reset): xxx=S1: insert reads between writes to the
+ device to avoid a possible deadlock; macro FLUSH_WRITES().
+ (PacketRxReady): xxx=E1E2: we set the device in promiscuous mode
+ always, and implement ESA matching in code. The cost is small.
+ If promisc mode is set by the stack, we pass all packets.
+ (eth_upd985xx_send): xxx=E3: we copy any transmit that uses 3 or
+ more SGs into a static contiguous buffer and transmit from that
+ thus using only one buffer descriptor.
+ (eth_upd985xx_send):
+ (TxDone): xxx=E8: we make a note that a tx ended badly and when
+ starting the next tx, we disable and reset the transmitter.
+
+ * cdl/upd985xx_eth_drivers.cdl: New subcomponent for controlling
+ these workarounds: CYGPKG_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS.
+ "Workarounds for Ethernet Hardware bugs"
+
+2001-07-16 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (PacketRxReady): Test for, rather than assert,
+ packet size in range. The hardware can report a tiny packet as
+ AOK, with no bad in the status, despite the doc's reassurances.
+
+2001-07-13 Hugo Tyson <hmt@redhat.com>
+
+ * cdl/upd985xx_eth_drivers.cdl: Turn off the startup chatter.
+
+2001-07-13 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (TxDone): Test a few more bits for tx
+ complete; it turns out you can get tx underruns when the CPU us
+ heavily loaded, as in the tcp_echo tests with high load.
+
+2001-07-13 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (eth_upd985xx_send): Use HAL_DCACHE_STORE()
+ rather than syncing the whole of cache every sglist entry(=mbuf).
+ Turns out the cache op must be cache line aligned to work on the
+ 4120, boo, unlike other MIPS and unlike the doc, even.
+
+2001-07-12 Hugo Tyson <hmt@redhat.com>
+
+ * cdl/upd985xx_eth_drivers.cdl (CYGPKG_DEVS_ETH_MIPS_UPD985XX_ETH0):
+ Whole new section to address configuring the source of the MAC
+ address. Also allows configury of the device's name ("eth0") for
+ cohabitation with additional devices.
+
+ * src/if_upd985xx.c (upd985xx_eth_upd985xx_init): Pick up the ESA
+ from EEPROM if it's available, also support a fixed ESA from CDL
+ configuration land. A few minor changes to the structure
+ initialization to accommodate this; also pick up the interrupt
+ vector from struct init.
+ (eth_set_mac_address): New routine available via the ioctl()
+ entry, for use when neither a fixed nor EEPROM address is
+ available.
+
+2001-07-12 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (NUM_RXBUFS): Reduce NUM_RXBUFS to 8; IME
+ fewer results in lost rx's in typical systems. Enlarge rx buffers
+ slightly, to accommodate oversize VLAN packets. 128 bytes extra
+ should be enough. Implemented eth_upd985xx_configure() selection
+ of promiscuous mode and allow oversize packets - up to the allowed
+ oversize. Otherwise we would get confused if a packet ate more
+ than 1 rx buffer.
+
+2001-07-12 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c: Tidy up debug print defaults; make functions
+ static; add a few extra statistics to the device object; pass a
+ p_eth_upd985xx around more consistently for if we switch to
+ multiple devices in future; comment out mii_write(); handle
+ stopping the device with a tx pending; remove some commented-out
+ templates copied from another driver; and fill in SNMP statistics.
+ In other words, many minor changes.
+
+2001-07-11 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c (PacketRxReady): Recover from running out of
+ receive buffers. All very dodgy, but it seems to work.
+ Additional efforts are also made to reset the device, having
+ realized how hard it is to re-initialize the receive engine once
+ it has been awakened.
+
+2001-07-11 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c: Efficient Rx now essentially working, with a
+ simple circular buffer, always linked into a ring, and one entry
+ of which is always NULL,NULL to bring the rx machinery to a halt.
+ If it reaches thus far the rx mechanism seems to jam; will deal
+ with that next.
+
+2001-07-09 Hugo Tyson <hmt@redhat.com>
+
+ * src/if_upd985xx.c: Rejigged version of the rx buffer system;
+ still not working properly, still not a good match for the
+ hardware's elusive semantics. Committed anyway, to keep it around
+ for reference.
+ (eth_upd985xx_status): Also removed all the cruft about
+ renegotiating line status; it's not needed.
+
+2001-07-06 Hugo Tyson <hmt@redhat.com>
+
+ * include/upd985xx_eth.h (ETH_MADR_PHY_DEVICE_PHYS_ADDRESS):
+ Change name of PHY address symbol to generic not SEEQ.
+ Comment out the non-standard symbols for useful bits that the
+ previous PHY device supported.
+
+ * src/if_upd985xx.c (eth_upd985xx_reset): If there is a valid ESA
+ in the MAC already, run with it - it would have come from the
+ not-fitted serial EEPROM, via some different registers.
+ (upd985xx_eth_upd985xx_init): Moved the call to reset about to
+ accommodate this.
+ (eth_upd985xx_status): Omit renegotiation of link properties and
+ use the intersection of the capabilities bits to report what
+ speed, duplex, we are running at. More portable.
+ (mii_write):
+ (mii_read): Change name of PHY address symbol to generic not SEEQ
+ 'cos the board has changed.
+
+2001-07-06 Hugo Tyson <hmt@redhat.com>
+
+ * ChangeLog:
+ * cdl/upd985xx_eth_drivers.cdl:
+ * include/upd985xx_eth.h:
+ * src/if_upd985xx.c:
+ New files. Initial checkin of limping along version of
+ NEC upd985xx ethernet driver.
+
+ Limitations:
+ ESA is hard coded.
+ It talks to the PHY just to make sure - helped with debug anyway.
+ No SNMP data exported.
+ No ioctl() for promiscuous mode or VLAN mode.
+ Only one TX at once.
+ Only one RX buffer, so no RX until serviced.
+ It seems to loose interrupts - inevitably, for an eth device - and
+ there's no "catchup" defense against this yet.
+
+ It's oriented to the "old" (already) board - so the particular PHY
+ and GPIO layout.
+
+//===========================================================================
+// ####GPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc., 51 Franklin Street,
+// Fifth Floor, Boston, MA 02110-1301, USA.
+// -------------------------------------------
+// ####GPLCOPYRIGHTEND####
+//===========================================================================
diff --git a/ecos/packages/devs/eth/mips/upd985xx/current/cdl/upd985xx_eth_drivers.cdl b/ecos/packages/devs/eth/mips/upd985xx/current/cdl/upd985xx_eth_drivers.cdl
new file mode 100644
index 0000000..7357aca
--- /dev/null
+++ b/ecos/packages/devs/eth/mips/upd985xx/current/cdl/upd985xx_eth_drivers.cdl
@@ -0,0 +1,204 @@
+# ====================================================================
+#
+# upd985xx_eth_drivers.cdl
+#
+# Ethernet drivers
+# NEC uPD985xx device specific support
+#
+# ====================================================================
+## ####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later
+## version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with eCos; if not, write to the Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+##
+## As a special exception, if other files instantiate templates or use
+## macros or inline functions from this file, or you compile this file
+## and link it with other works to produce a work based on this file,
+## this file does not by itself cause the resulting work to be covered by
+## the GNU General Public License. However the source code for this file
+## must still be made available in accordance with section (3) of the GNU
+## General Public License v2.
+##
+## This exception does not invalidate any other reasons why a work based
+## on this file might be covered by the GNU General Public License.
+## -------------------------------------------
+## ####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): hmt
+# Original data: hmt
+# Contributors: gthomas
+# Date: 2001-06-28
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_ETH_MIPS_UPD985XX {
+ display "NEC uPD985xx ethernet driver"
+
+ parent CYGPKG_IO_ETH_DRIVERS
+ active_if CYGPKG_IO_ETH_DRIVERS
+ active_if CYGPKG_HAL_MIPS_UPD985XX
+
+ implements CYGHWR_NET_DRIVER_ETH0
+
+ implements CYGHWR_NET_DRIVERS
+ include_dir cyg/devs/eth
+
+ description "Ethernet driver for NEC uPD985xx devices."
+ compile -library=libextras.a if_upd985xx.c
+
+ cdl_option CYGDBG_DEVS_ETH_MIPS_UPD985XX_CHATTER {
+ display "Prints ethernet device status info during startup"
+ default_value 0
+ description "
+ The ethernet device initialization code can print lots of info
+ to confirm that it has booted correctly."
+ }
+
+ cdl_option CYGNUM_DEVS_ETH_MIPS_UPD985XX_DEV_COUNT {
+ display "Number of supported interfaces."
+ #legal_values 1
+ #default_value 1
+ calculated 1
+ flavor data
+ description "
+ This option selects the number of ethernet interfaces to
+ be supported by the driver."
+ }
+
+ cdl_component CYGPKG_DEVS_ETH_MIPS_UPD985XX_ETH0 {
+ display "Ethernet port 0 driver"
+ flavor bool
+ calculated 1
+ description "
+ This option includes the ethernet device driver for
+ port 0 - that is the only connector
+ depending on your particular hardware."
+
+
+ cdl_option CYGDAT_DEVS_ETH_UPD985XX_ETH0_NAME {
+ display "Device name for the ethernet port 0 driver"
+ flavor data
+ default_value {"\"eth0\""}
+ description "
+ This option sets the name of the ethernet device for the
+ ethernet port 0."
+ }
+
+ cdl_component CYGSEM_DEVS_ETH_UPD985XX_ETH0_SET_ESA {
+ display "Set the ethernet station address"
+ flavor bool
+ default_value false
+ requires !CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
+ description "Enabling this option will allow the ethernet
+ station address to be forced to the value set by the
+ configuration. This may be required if the hardware does
+ not include a serial EEPROM for the ESA."
+
+ cdl_option CYGDAT_DEVS_ETH_UPD985XX_ETH0_ESA {
+ display "The ethernet station address"
+ flavor data
+ default_value {"{0x00, 0xBA, 0xCA, 0xDD, 0x1E, 0xDD}"}
+ description "The ethernet station address"
+ }
+ }
+
+ cdl_option CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA {
+ display "Get the ethernet station address from EEPROM"
+ flavor bool
+ default_value !CYGSEM_DEVS_ETH_UPD985XX_ETH0_SET_ESA
+ requires !CYGSEM_DEVS_ETH_UPD985XX_ETH0_SET_ESA
+ description "Enabling this option will allow the ethernet
+ station address to be read from a serial EEPROM (such as 93C06,
+ 93C46...). If this is not valid, your application must set the
+ ESA manually via an ioctl() call or similar."
+ }
+ }
+
+ cdl_component CYGPKG_DEVS_ETH_MIPS_UPD985XX_OPTIONS {
+ display "NEC uPD985xx ethernet driver build options"
+ flavor none
+ no_define
+
+ cdl_option CYGPKG_DEVS_ETH_MIPS_UPD985XX_CFLAGS_ADD {
+ display "Additional compiler flags"
+ flavor data
+ no_define
+ default_value { "-D_KERNEL -D__ECOS" }
+ description "
+ This option modifies the set of compiler flags for
+ building the NEC uPD985xx ethernet driver
+ package. These flags are used in addition to the set of
+ global flags."
+ }
+ }
+
+ cdl_component CYGPKG_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS {
+ display "Workarounds for Ethernet Hardware bugs "
+ flavor bool
+ default_value 1
+ description "
+ This component controls whether code workarounds for the numerous
+ hardware bugs in the uPD98503 Ethernet device are included.
+ These might not all be necessary depending on the speed and mode in
+ which the interface is used. Please refer to the manufacturer's
+ Behaviour Analysis Report to make your decision about which of
+ these options to enable or disable.
+ The default is to enable all workarounds for best reliability."
+
+ cdl_option CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_S1 {
+ display "S1 - CPU to IBUS write restriction"
+ flavor bool
+ default_value 1
+ description "Enable a workaround for hardware bug S1"
+ }
+ cdl_component CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2 {
+ display "E1,E2 - Status queue corruption and MAC filtering"
+ flavor bool
+ default_value 1
+ description "Enable a workaround for hardware bugs E1 and/or E2."
+
+ cdl_option CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY {
+ display "Do not set device in promisc mode - solve E2 only"
+ flavor bool
+ default_value 1
+ description "Work around bug E2 only - do not set the device
+ in promiscuous mode by default.
+ Setting this option prevents the work around
+ for bug E1."
+ }
+ }
+ cdl_option CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3 {
+ display "E3 - Transmit descriptor error"
+ flavor bool
+ default_value 1
+ description "Enable a workaround for hardware bug E3"
+
+ }
+ cdl_option CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E8 {
+ display "E8 - Transmission error under abnormal conditions"
+ flavor bool
+ default_value 1
+ description "Enable a workaround for hardware bug E8"
+ }
+ }
+}
+
+# EOF upd985xx_eth_drivers.cdl
diff --git a/ecos/packages/devs/eth/mips/upd985xx/current/include/upd985xx_eth.h b/ecos/packages/devs/eth/mips/upd985xx/current/include/upd985xx_eth.h
new file mode 100644
index 0000000..398099f
--- /dev/null
+++ b/ecos/packages/devs/eth/mips/upd985xx/current/include/upd985xx_eth.h
@@ -0,0 +1,464 @@
+#ifndef CYGONCE_HAL_UPD985XX_ETH_H
+#define CYGONCE_HAL_UPD985XX_ETH_H
+//==========================================================================
+//
+// upd985xx_eth.h
+//
+// Architecture specific abstractions for the on-chip ethernet
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): hmt, nickg
+// Contributors: nickg
+// Date: 2001-06-28
+// Purpose: Define architecture abstractions
+// Description: This file contains any extra or modified definitions for
+// this variant of the architecture's ethernet controller.
+// Usage: #include <cyg/io/upd985xx_eth.h>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/hal/var_arch.h>
+
+// --------------------------------------------------------------------------
+// By default we use the definition of UPD985XX_SYSETH_REG( n ) from
+// var_arch.h - if we port to a KORVA with multiple ethernet controllers we
+// will have to vary this to account for the different base addresses.
+
+// (the noise at the end of these lines is the default value)
+//
+// Table 5-2. MAC Control Register Map
+//
+#define ETH_MACC1 UPD985XX_SYSETH_REG( 0x000) // MAC configuration register 1 R/W 0000_0000H
+#define ETH_MACC2 UPD985XX_SYSETH_REG( 0x004) // MAC configuration register 2 R/W 0000_0000H
+#define ETH_IPGT UPD985XX_SYSETH_REG( 0x008) // Back-to-Back IPG register R/W 0000_0013H
+#define ETH_IPGR UPD985XX_SYSETH_REG( 0x00C) // Non Back-to-Back IPG register R/W 0000_0E13H
+#define ETH_CLRT UPD985XX_SYSETH_REG( 0x010) // Collision register R/W 0000_370FH
+#define ETH_LMAX UPD985XX_SYSETH_REG( 0x014) // Max packet length register R/W 0000_0600H
+// N/A UPD985XX_SYSETH_REG( 0x018) // Reserved for future use - -
+#define ETH_RETX UPD985XX_SYSETH_REG( 0x020) // Retry count register R/W 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x024) // Reserved for future use - -
+#define ETH_LSA2 UPD985XX_SYSETH_REG( 0x054) // Station Address register 2 R/W 0000_0000H
+#define ETH_LSA1 UPD985XX_SYSETH_REG( 0x058) // Station Address register 1 R/W 0000_0000H
+#define ETH_PTVR UPD985XX_SYSETH_REG( 0x05C) // Pause timer value read register R 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x060) // Reserved for future use - -
+#define ETH_VLTP UPD985XX_SYSETH_REG( 0x064) // VLAN type register R/W 0000_0000H
+#define ETH_MIIC UPD985XX_SYSETH_REG( 0x080) // MII configuration register R/W 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x084) // Reserved for future use - -
+#define ETH_MCMD UPD985XX_SYSETH_REG( 0x094) // MII command register W 0000_0000H
+#define ETH_MADR UPD985XX_SYSETH_REG( 0x098) // MII address register R/W 0000_0000H
+#define ETH_MWTD UPD985XX_SYSETH_REG( 0x09C) // MII write data register R/W 0000_0000H
+#define ETH_MRDD UPD985XX_SYSETH_REG( 0x0A0) // MII read data register R 0000_0000H
+#define ETH_MIND UPD985XX_SYSETH_REG( 0x0A4) // MII indicator register R 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x0A8) // Reserved for future use - -
+#define ETH_AFR UPD985XX_SYSETH_REG( 0x0C8) // Address Filtering register R/W 0000_0000H
+#define ETH_HT1 UPD985XX_SYSETH_REG( 0x0CC) // Hash table register 1 R/W 0000_0000H
+#define ETH_HT2 UPD985XX_SYSETH_REG( 0x0D0) // Hash table register 2 R/W 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x0D4) // Reserved for future use - -
+#define ETH_CAR1 UPD985XX_SYSETH_REG( 0x0DC) // Carry register 1 R/W 0000_0000H
+#define ETH_CAR2 UPD985XX_SYSETH_REG( 0x0E0) // Carry register 2 R/W 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x0E4) // Reserved for future use - -
+#define ETH_CAM1 UPD985XX_SYSETH_REG( 0x130) // Carry mask register 1 R/W 0000_0000H
+#define ETH_CAM2 UPD985XX_SYSETH_REG( 0x134) // Carry mask register 2 R/W 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x138) // Reserved for future use - -
+//
+// Table 5-3. Statistics Counter Register Map
+//
+#define ETH_RBYT UPD985XX_SYSETH_REG( 0x140) // Receive Byte Counter R/W
+#define ETH_RPKT UPD985XX_SYSETH_REG( 0x144) // Receive Packet Counter R/W
+#define ETH_RFCS UPD985XX_SYSETH_REG( 0x148) // Receive FCS Error Counter R/W
+#define ETH_RMCA UPD985XX_SYSETH_REG( 0x14C) // Receive Multicast Packet Counter R/W
+#define ETH_RBCA UPD985XX_SYSETH_REG( 0x150) // Receive Broadcast Packet Counter R/W
+#define ETH_RXCF UPD985XX_SYSETH_REG( 0x154) // Receive Control Frame Packet Counter R/W
+#define ETH_RXPF UPD985XX_SYSETH_REG( 0x158) // Receive PAUSE Frame Packet Counter R/W
+#define ETH_RXUO UPD985XX_SYSETH_REG( 0x15C) // Receive Unknown OP code Counter R/W
+#define ETH_RALN UPD985XX_SYSETH_REG( 0x160) // Receive Alignment Error Counter R/W
+#define ETH_RFLR UPD985XX_SYSETH_REG( 0x164) // Receive Frame Length Out of Range Counter R/W
+#define ETH_RCDE UPD985XX_SYSETH_REG( 0x168) // Receive Code Error Counter R/W
+#define ETH_RFCR UPD985XX_SYSETH_REG( 0x16C) // Receive False Carrier Counter R/W
+#define ETH_RUND UPD985XX_SYSETH_REG( 0x170) // Receive Undersize Packet Counter R/W
+#define ETH_ROVR UPD985XX_SYSETH_REG( 0x174) // Receive Oversize Packet Counter R/W
+#define ETH_RFRG UPD985XX_SYSETH_REG( 0x178) // Receive Error Undersize Packet Counter R/W
+#define ETH_RJBR UPD985XX_SYSETH_REG( 0x17C) // Receive Error Oversize Packet Counter R/W
+#define ETH_R64 UPD985XX_SYSETH_REG( 0x180) // Receive 64 Byte Frame Counter R/W
+#define ETH_R127 UPD985XX_SYSETH_REG( 0x184) // Receive 65 to 127 Byte Frame Counter R/W
+#define ETH_R255 UPD985XX_SYSETH_REG( 0x188) // Receive 128 to 255 Byte Frame Counter R/W
+#define ETH_R511 UPD985XX_SYSETH_REG( 0x18C) // Receive 256 to 511 Byte Frame Counter R/W
+#define ETH_R1K UPD985XX_SYSETH_REG( 0x190) // Receive 512 to 1023 Byte Frame Counter R/W
+#define ETH_RMAX UPD985XX_SYSETH_REG( 0x194) // Receive Over 1023 Byte Frame Counter R/W
+#define ETH_RVBT UPD985XX_SYSETH_REG( 0x198) // Receive Valid Byte Counter R/W
+#define ETH_TBYT UPD985XX_SYSETH_REG( 0x1C0) // Transmit Byte Counter R/W
+#define ETH_TPCT UPD985XX_SYSETH_REG( 0x1C4) // Transmit Packet Counter R/W
+#define ETH_TFCS UPD985XX_SYSETH_REG( 0x1C8) // Transmit CRC Error Packet Counter R/W
+#define ETH_TMCA UPD985XX_SYSETH_REG( 0x1CC) // Transmit Multicast Packet Counter R/W
+#define ETH_TBCA UPD985XX_SYSETH_REG( 0x1D0) // Transmit Broadcast Packet Counter R/W
+#define ETH_TUCA UPD985XX_SYSETH_REG( 0x1D4) // Transmit Unicast Packet Counter R/W
+#define ETH_TXPF UPD985XX_SYSETH_REG( 0x1D8) // Transmit PAUSE control Frame Counter R/W
+#define ETH_TDFR UPD985XX_SYSETH_REG( 0x1DC) // Transmit Single Deferral Packet Counter R/W
+#define ETH_TXDF UPD985XX_SYSETH_REG( 0x1E0) // Transmit Excessive Deferral Packet Counter R/W
+#define ETH_TSCL UPD985XX_SYSETH_REG( 0x1E4) // Transmit Single Collision Packet Counter R/W
+#define ETH_TMCL UPD985XX_SYSETH_REG( 0x1E8) // Transmit Multiple collision Packet Counter R/W
+#define ETH_TLCL UPD985XX_SYSETH_REG( 0x1EC) // Transmit Late Collision Packet Counter R/W
+#define ETH_TXCL UPD985XX_SYSETH_REG( 0x1F0) // Transmit Excessive Collision Packet Counter R/W
+#define ETH_TNCL UPD985XX_SYSETH_REG( 0x1F4) // Transmit Total Collision Counter R/W
+#define ETH_TCSE UPD985XX_SYSETH_REG( 0x1F8) // Transmit Carrier Sense Error Counter R/W
+#define ETH_TIME UPD985XX_SYSETH_REG( 0x1FC) // Transmit Internal MAC Error Counter R/W
+//
+// Table 5-4. DMA and FIFO Management Registers Map
+//
+#define ETH_TXCR UPD985XX_SYSETH_REG( 0x200) // Transmit Configuration Register R/W 0000_0000H
+#define ETH_TXFCR UPD985XX_SYSETH_REG( 0x204) // Transmit FIFO Control Register R/W FFFF_40C0H
+#define ETH_TXDTR UPD985XX_SYSETH_REG( 0x208) // Transmit Data Register W 0000_0000H
+#define ETH_TXSR UPD985XX_SYSETH_REG( 0x20C) // Transmit Status Register R 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x210) // Reserved for future use - -
+#define ETH_TXDPR UPD985XX_SYSETH_REG( 0x214) // Transmit Descriptor Pointer R/W 0000_0000H
+#define ETH_RXCR UPD985XX_SYSETH_REG( 0x218) // Receive Configuration Register R/W 0000_0000H
+#define ETH_RXFCR UPD985XX_SYSETH_REG( 0x21C) // Receive FIFO Control Register R/W C040_0040H
+#define ETH_RXDTR UPD985XX_SYSETH_REG( 0x220) // Receive Data Register R 0000_0000H
+#define ETH_RXSR UPD985XX_SYSETH_REG( 0x224) // Receive Status Register R 0000_0000H
+// N/A UPD985XX_SYSETH_REG( 0x228) // Reserved for future use - -
+#define ETH_RXDPR UPD985XX_SYSETH_REG( 0x22C) // Receive Descriptor Pointer R/W 0000_0000H
+#define ETH_RXPDR UPD985XX_SYSETH_REG( 0x230) // Receive Pool Descriptor Register R/W 0000_0000H
+//
+// Table 5-5. Interrupt and Configuration Registers Map
+//
+#define ETH_CCR UPD985XX_SYSETH_REG( 0x234) // Configuration Register R/W 0000_0000H
+#define ETH_ISR UPD985XX_SYSETH_REG( 0x238) // Interrupt Service Register R 0000_0000H
+#define ETH_MSR UPD985XX_SYSETH_REG( 0x23C) // Mask Serves Register R/W 0000_0000H
+
+// --------------------------------------------------------------------------
+// Now the fields within all those registers...
+//
+// Table 5-2. MAC Control Register Map
+//
+// ETH_MACC1 0x000 MAC configuration register 1 R/W 0000_0000H
+#define ETH_MACC1_MACLB (1<<14) // MAC loopback: 0
+#define ETH_MACC1_TXFC (1<<11) // Transmit flow control enable: 0
+#define ETH_MACC1_RXFC (1<<10) // Receive flow control enable: 0
+#define ETH_MACC1_SRXEN (1<< 9) // Receive enable: 0
+#define ETH_MACC1_PARF (1<< 8) // Control packet pass: 0
+#define ETH_MACC1_PUREP (1<< 7) // Pure preamble: 0
+#define ETH_MACC1_FLCHT (1<< 6) // Length field check: 0
+#define ETH_MACC1_NOBO (1<< 5) // No Back Off: 0
+#define ETH_MACC1_CRCEN (1<< 3) // CRC append enable: 0
+#define ETH_MACC1_PADEN (1<< 2) // PAD append enable: 0
+#define ETH_MACC1_FDX (1<< 1) // Full duplex enable: 0
+#define ETH_MACC1_HUGEN (1<< 0) // Large packet enable: 0
+// ETH_MACC2 0x004 MAC configuration register 2 R/W 0000_0000H
+#define ETH_MACC2_MCRST (1<<10) // MAC Control Block software reset: 0
+#define ETH_MACC2_RFRST (1<< 9) // Receive Function Block software reset: 0
+#define ETH_MACC2_TFRST (1<< 8) // Transmit Function Block software reset: 0
+#define ETH_MACC2_BPNB (1<< 6) // Back Pressure No Back Off: 0
+#define ETH_MACC2_APD (1<< 5) // Auto VLAN PAD: 0
+#define ETH_MACC2_VPD (1<< 4) // VLAN PAD mode: 0
+
+// ETH_IPGT 0x008 Back-to-Back IPG register R/W 0000_0013H
+// ETH_IPGR 0x00C Non Back-to-Back IPG register R/W 0000_0E13H
+// ETH_CLRT 0x010 Collision register R/W 0000_370FH
+// ETH_LMAX 0x014 Max packet length register R/W 0000_0600H
+// N/A 0x018 Reserved for future use - -
+// ETH_RETX 0x020 Retry count register R/W 0000_0000H
+// N/A 0x024 Reserved for future use - -
+// ETH_LSA2 0x054 Station Address register 2 R/W 0000_0000H
+// ETH_LSA1 0x058 Station Address register 1 R/W 0000_0000H
+// ETH_PTVR 0x05C Pause timer value read register R 0000_0000H
+// N/A 0x060 Reserved for future use - -
+// ETH_VLTP 0x064 VLAN type register R/W 0000_0000H
+#define ETH_VLTP_VLTP (0x00008100) // magic number from example
+// ETH_MIIC 0x080 MII configuration register R/W 0000_0000H
+#define ETH_MIIC_MIRST (1<<15) // MII Management Interface Block software reset
+#define ETH_MIIC_CLKS (0x0C) // 3:2 CLKS Select frequency range:
+#define ETH_MIIC_25 (0x00) // 00: HCLK is equal to 25 MHz
+#define ETH_MIIC_33 (0x04) // 01: HCLK is less than or equal to 33 MHz
+#define ETH_MIIC_50 (0x08) // 10: HCLK is less than or equal to 50 MHz
+#define ETH_MIIC_66 (0x0C) // 11: HCLK is less than or equal to 66 MHz
+// ETH_MCMD 0x094 MII command register W 0000_0000H
+#define ETH_MCMD_SCANC (1<< 1) // SCAN command: 0
+#define ETH_MCMD_RSTAT (1<< 0) // MII management read: 0
+// ETH_MADR 0x098 MII address register R/W 0000_0000H
+#define ETH_MADR_PHY_ADDR_SHIFT (8)
+// ETH_MWTD 0x09C MII write data register R/W 0000_0000H
+// ETH_MRDD 0x0A0 MII read data register R 0000_0000H
+// ETH_MIND 0x0A4 MII indicator register R 0000_0000H
+#define ETH_MIND_NVALID (1<< 2) // SCAN command start status: 0
+#define ETH_MIND_SCANA (1<< 1) // SCAN command active: 0
+#define ETH_MIND_BUSY (1<< 0) // BUSY: 0
+// ETH_AFR 0x0C8 Address Filtering register R/W 0000_0000H
+#define ETH_AFR_PRO (1<< 3) // Promiscuous mode: 0
+#define ETH_AFR_PRM (1<< 2) // Accept Multicast: 0
+#define ETH_AFR_AMC (1<< 1) // Accept Multicast ( qualified ): 0
+#define ETH_AFR_ABC (1<< 0) // Accept Broadcast: 0
+// ETH_HT1 0x0CC Hash table register 1 R/W 0000_0000H
+// ETH_HT2 0x0D0 Hash table register 2 R/W 0000_0000H
+// ETH_CAR1 0x0DC Carry register 1 R/W 0000_0000H
+// ETH_CAR2 0x0E0 Carry register 2 R/W 0000_0000H
+// ETH_CAM1 0x130 Carry mask register 1 R/W 0000_0000H
+// ETH_CAM2 0x134 Carry mask register 2 R/W 0000_0000H
+//
+// Table 5-3. Statistics Counter Register Map
+// <snip>
+//
+// Table 5-4. DMA and FIFO Management Registers Map
+//
+// ETH_TXCR 0x200 Transmit Configuration Register R/W 0000_0000H
+#define ETH_TXCR_TXE (1<<31) // Transmit Enable:
+#define ETH_TXCR_DTBS_SHIFT (16) // 18:16 DMA Transmit Burst Size:
+#define ETH_TXCR_DTBS (0x70000) // 18:16 DMA Transmit Burst Size:
+#define ETH_TXCR_DTBS_1 (0x00000) // 000: 1 Word (4 bytes)
+#define ETH_TXCR_DTBS_2 (0x10000) // 001: 2 Word (8 bytes)
+#define ETH_TXCR_DTBS_4 (0x20000) // 010: 4 Word (16 bytes)
+#define ETH_TXCR_DTBS_8 (0x30000) // 011: 8 Word (32 bytes)
+#define ETH_TXCR_DTBS_16 (0x40000) // 100: 16 Word (64 bytes)
+#define ETH_TXCR_DTBS_32 (0x50000) // 101: 32 Word (128 bytes)
+#define ETH_TXCR_DTBS_64 (0x60000) // 110: 64 Word (256 bytes)
+#define ETH_TXCR_AFCE (1<< 0) // Auto Flow Control Enable:
+// ETH_TXFCR 0x204 Transmit FIFO Control Register R/W FFFF_40C0H
+#define ETH_TXFCR_TPTV_SHIFT (16) // 31:16 Transmit Pause Timer Value: FFFFH
+#define ETH_TXFCR_TPTV (0xffff0000) // 31:16 Transmit Pause Timer Value: FFFFH
+#define ETH_TXFCR_TX_DRTH_SHIFT (10) // 15:10 Transmit Drain Threshold Level: 10H
+#define ETH_TXFCR_TX_DRTH (0x0000fc00) // 15:10 Transmit Drain Threshold Level: 10H
+#define ETH_TXFCR_TX_FLTH_SHIFT (2) // 7:2 Transmit Fill Threshold Level: 03H
+#define ETH_TXFCR_TX_FLTH (0x000000fc) // 7:2 Transmit Fill Threshold Level: 03H
+#define ETH_TXFCR_TPTV_DEFAULT (0x10000000) // default 0x1000 slot time (1slot:512bit)
+#define ETH_TXFCR_TX_DRTH_DEFAULT (0x00002000) // 001000b (8long, 32byte)
+#define ETH_TXFCR_TX_FLTH_DEFAULT (0x000000c0) // default 110000b (48word, 192byte)
+// ETH_TXDTR 0x208 Transmit Data Register W 0000_0000H
+// ETH_TXSR 0x20C Transmit Status Register R 0000_0000H
+#define ETH_TXSR_CSE (1<<31) // Carrier lost was detected during the transmission 0
+#define ETH_TXSR_TBP (1<<30) // Back pressure occurred when the packet was received 0
+#define ETH_TXSR_TPP (1<<29) // A packet request during the PAUSE operation was transmitted 0
+#define ETH_TXSR_TPCF (1<<28) // A PAUSE control frame was transmitted 0
+#define ETH_TXSR_TCFR (1<<27) // A control frame was transmitted 0
+#define ETH_TXSR_TUDR (1<<26) // The TPUR pin was set high and aborted. Note 2 0
+#define ETH_TXSR_TGNT (1<<25) // A huge packet was transmitted and aborted. 0
+#define ETH_TXSR_LCOL (1<<24) // Collision occurred
+#define ETH_TXSR_ECOL (1<<23) // Excess collisions
+#define ETH_TXSR_TEDFR (1<<22) // Excess deferred
+#define ETH_TXSR_TDFR (1<<21) // Transmission deferral occurred
+#define ETH_TXSR_TBRO (1<<20) // A broadcast packet was transmitted. 0
+#define ETH_TXSR_TMUL (1<<19) // A multicast packet was transmitted. 0
+#define ETH_TXSR_TDONE (1<<18) // Transmission was completed. 0
+#define ETH_TXSR_TFLOR (1<<17) // Value of the length field was huge
+#define ETH_TXSR_TFLER (1<<16) // Value of the length field didn~t match the actual data count
+#define ETH_TXSR_TCRCE (1<<15) // Attached CRC didn~t match the internal generated CRC
+
+#define ETH_TXSR_TCBC_SHIFT (11) // 14:11 collisions for the previous transmission
+#define ETH_TXSR_TCBC (0x7800) // 14:11 collisions for the previous transmission
+#define ETH_TXSR_TBYT_SHIFT (0) // 10:0 transmitted bytes not including collided bytes
+#define ETH_TXSR_TBYT (0x07FF) // 10:0 transmitted bytes not including collided bytes
+
+// ETH_RXCR UPD985XX_SYSETH_REG( 0x218) // Receive Configuration Register R/W 0000_0000H
+#define ETH_RXCR_RXE (1<<31) // Receive Enable:
+#define ETH_RXCR_DRBS_SHIFT (16) // 18:16 DRBS DMA Transmit Burst Size: 0
+#define ETH_RXCR_DRBS (0x70000) //
+#define ETH_RXCR_DRBS_1 (0x00000) // 000: 1 Word (4 bytes)
+#define ETH_RXCR_DRBS_2 (0x10000) // 001: 2 Word (8 bytes)
+#define ETH_RXCR_DRBS_4 (0x20000) // 010: 4 Word (16 bytes)
+#define ETH_RXCR_DRBS_8 (0x30000) // 011: 8 Word (32 bytes)
+#define ETH_RXCR_DRBS_16 (0x40000) // 100: 16 Word (64 bytes)
+#define ETH_RXCR_DRBS_32 (0x50000) // 101: 32 Word (128 bytes)
+#define ETH_RXCR_DRBS_64 (0x60000) // 110: 64 Word (256 bytes)
+
+// ETH_RXFCR 0x21C Receive FIFO Control Register R/W C040_0040H
+#define ETH_RXFCR_UWM (0xfc000000) // 31:26 Upper Water Mark: 30H
+#define ETH_RXFCR_UWM_SHIFT (26) // 31:26 Upper Water Mark: 30H
+#define ETH_RXFCR_LWM (0x00fc0000) // 23:18 Lower Water Mark: 10H
+#define ETH_RXFCR_LWM_SHIFT (18) // 23:18 Lower Water Mark: 10H
+#define ETH_RXFCR_RX_DRTH (0x000000fc) // 7: 2 Receive Drain Threshold Level 10H
+#define ETH_RXFCR_RX_DRTH_SHIFT (2) // 7: 2 Receive Drain Threshold Level 10H
+#define ETH_RXFCR_UWM_DEFAULT (0xE0000000) // default 110000b ( 48word, 192byte )
+#define ETH_RXFCR_LWM_DEFAULT (0x00400000) // default 010000b (16word, 64byte)
+#define ETH_RXFCR_DRTH16W (0x00000040) // default 010000b (16word, 64byte)
+
+// ETH_RXDTR 0x220 Receive Data Register R 0000_0000H
+// ETH_RXSR 0x224 Receive Status Register R 0000_0000H
+#define ETH_RXSR_RLENE (1<<31) // A toosmall or toolarge packet was received.
+#define ETH_RXSR_VLAN (1<<30) // A VLAN was received.
+#define ETH_RXSR_USOP (1<<29) // A control frame containing an unknown OP code was received.
+#define ETH_RXSR_PRCF (1<<28) // A control frame containing the PAUSE OP code was received.
+#define ETH_RXSR_RCFR (1<<27) // A control frame was received.
+#define ETH_RXSR_DBNB (1<<26) // An alignment error occurred.
+#define ETH_RXSR_RBRO (1<<25) // A broadcast packet was received. 0
+#define ETH_RXSR_RMUL (1<<24) // A multicast packet was received. 0
+#define ETH_RXSR_RXOK (1<<23) // A good packet was received.
+#define ETH_RXSR_RLOR (1<<22) // The value of the length field was huge
+#define ETH_RXSR_RLER (1<<21) // The value of the length field didn~t match
+#define ETH_RXSR_RCRCE (1<<20) // A CRC error occurred. 0
+#define ETH_RXSR_RCV (1<<19) // RXER was detected. 0
+#define ETH_RXSR_CEPS (1<<18) // A False Carrier was detected. 0
+#define ETH_RXSR_REPS (1<<17) // A packet which had a preamble and SFD only or one data nibble
+#define ETH_RXSR_PAIG (1<<16) //
+#define ETH_RXSR_RBYT (0xffff) // 15:0 The received byte count 0
+#define ETH_RXSR_RBYT_SHIFT (0) // 15:0 The received byte count 0
+// ETH_RXDPR 0x22C Receive Descriptor Register R/W 0000_0000H
+// ETH_RXPDR 0x230 Receive Pool Descriptor Register R/W 0000_0000H
+#define ETH_RXPDR_AL (0x70000000) // 30:28 AL[2:0] Alert Level 0H
+#define ETH_RXPDR_AL_SHIFT (28)
+#define ETH_RXPDR_RNOD (0xffff) // 15:0 Remaining Number of Descriptor 0H
+#define ETH_RXPDR_RNOD_SHIFT (0)
+//
+// Table 5-5. Interrupt and Configuration Registers Map
+//
+// ETH_CCR 0x234 Configuration Register R/W 0000_0000H
+#define ETH_CCR_SRT (1) // Software Reset (cleared automatically to '0')
+// ETH_ISR 0x238 Interrupt Service Register R 0000_0000H
+#define ETH_ISR_XMTDN (1<<15) // Transmit Done
+#define ETH_ISR_TBDR (1<<14) // Transmit Buffer Descriptor Request at Null
+#define ETH_ISR_TFLE (1<<13) // Transmit Frame Length Exceed
+#define ETH_ISR_UR (1<<12) // Underrun
+#define ETH_ISR_TABR (1<<11) // Transmit Aborted
+#define ETH_ISR_TCFRI (1<<10) // Control Frame Transmit
+#define ETH_ISR_RCVDN (1<<7 ) // Receive Done
+#define ETH_ISR_RBDRS (1<<6 ) // Receive Buffer Descriptor Request at alert level
+#define ETH_ISR_RBDRU (1<<5 ) // Receive Buffer Descriptor Request at zero
+#define ETH_ISR_OF (1<<4 ) // Overflow
+#define ETH_ISR_LFAL (1<<3 ) // Link Failed
+#define ETH_ISR_CARRY (1<<0 ) // Carry Flag:
+// ETH_MSR 0x23C Mask Serves Register R/W 0000_0000H
+// As above
+
+// --------------------------------------------------------------------------
+// And the "buffer descriptor" control structures in RAM...
+
+
+#define ETH_BUF_LAST (1<<31) // Last Descriptor
+#define ETH_BUF_D_L (1<<30) // Data Buffer / Link Pointer
+#define ETH_BUF_D_L_DATA (1<<30) // Data Buffer / Link Pointer
+#define ETH_BUF_D_L_LINK (0<<30) // Data Buffer / Link Pointer
+#define ETH_BUF_OWN (1<<29) // Owner 1:Ethernet Controller 0: VR4120A
+#define ETH_BUF_OWN_ETH (1<<29)
+#define ETH_BUF_OWN_CPU (0<<29)
+
+#define ETH_BUF_DBRWE (1<<28) // Buffer Access Error
+#define ETH_BUF_OK (1<<16) // Tx or Rx OK
+#define ETH_BUF_SIZE (0xffff) // Byte Count
+
+#define ETH_BUF_TX_TUDR (1<<27) // Transmit Underrun Error
+#define ETH_BUF_TX_CSE (1<<26) // Carrier Sense Lost Error
+#define ETH_BUF_TX_LCOL (1<<25) // Late Collision
+#define ETH_BUF_TX_ECOL (1<<24) // Excessive Collision
+#define ETH_BUF_TX_EDFR (1<<23) // Excessive Deferral
+#define ETH_BUF_TX_TGNT (1<<18) // Transmit Giant Frame
+#define ETH_BUF_TX_HBF (1<<17) // Heart Beat Fail for ENDEC mode
+
+#define ETH_BUF_RX_OVRN (1<<24) // Overrun Error
+#define ETH_BUF_RX_RUNT (1<<23) // Runt packet
+#define ETH_BUF_RX_FRGE (1<<22) // Fragment Error
+#define ETH_BUF_RX_RCV (1<<21) // Detects RXER
+#define ETH_BUF_RX_FC (1<<20) // False Carrier
+#define ETH_BUF_RX_CRCE (1<<19) // CRC Error
+#define ETH_BUF_RX_FAE (1<<18) // Frame Alignment Error
+#define ETH_BUF_RX_RFLE (1<<17) // Receive Frame Length Error
+
+#define ETH_BUF_RX_FTYP (0x0e000000) // 27:25 Frame Type[2:0]
+#define ETH_BUF_RX_FTYP_SHIFT (25) // 27:25 Frame Type[2:0]
+// I don't think we need to know these...
+// 000 Broadcast Frame
+// 001 Multicast Frame
+// 010 Unicast Frame
+// 011 VLAN Frame
+// 100 PAUSE control frame
+// 101 Control Frame (except pause)
+// 11x Reserved for future use
+
+
+// --------------------------------------------------------------------------
+// MII stuff for talking to the separate PHY
+// Initially this was a SEEQ NQ80225 but now it is a LU3X31T-T64.
+
+//#define SEEQ_DEVICE_PHYS_ADDRESS (1) // this from the board documentation
+#define LU3X31T_DEVICE_PHYS_ADDRESS (2)
+
+#define ETH_MADR_PHY_DEVICE_PHYS_ADDRESS \
+ (LU3X31T_DEVICE_PHYS_ADDRESS << ETH_MADR_PHY_ADDR_SHIFT)
+
+// I don't know how much they have in common, but I think MII is pretty
+// standard, and the "mandated" registers ought to be common.
+
+#define PHY_CONTROL_REG (0)
+#define PHY_STATUS_REG (1)
+#define PHY_ID_ONE (2)
+#define PHY_ID_TWO (3)
+#define PHY_AUTONEG_ADVERT (4)
+#define PHY_AUTONEG_REMOTE (5)
+#define PHY_STATUS_DETECT_REG (18)
+
+#define PHY_CONTROL_RESET (1<<15)
+#define PHY_CONTROL_LOOPBACK (1<<14)
+#define PHY_CONTROL_SPEED100 (1<<13)
+#define PHY_CONTROL_AUTONEG_EN (1<<12)
+#define PHY_CONTROL_POWERDOWN (1<<11)
+#define PHY_CONTROL_MII_DIS (1<<10)
+#define PHY_CONTROL_AUTONEG_RST (1<< 9)
+#define PHY_CONTROL_DPLX_FULL (1<< 8)
+#define PHY_CONTROL_COLLTEST (1<< 7)
+
+#define PHY_STATUS_CAP_T4 (1<<15)
+#define PHY_STATUS_CAP_100TXF (1<<14)
+#define PHY_STATUS_CAP_100TXH (1<<13)
+#define PHY_STATUS_CAP_10TF (1<<12)
+#define PHY_STATUS_CAP_10TH (1<<11)
+#define PHY_STATUS_CAP_SUPR (1<< 6)
+#define PHY_STATUS_AUTONEG_ACK (1<< 5)
+#define PHY_STATUS_REMOTEFAULT (1<< 4)
+#define PHY_STATUS_CAP_AUTONEG (1<< 3)
+#define PHY_STATUS_LINK_OK (1<< 2)
+#define PHY_STATUS_JABBER (1<< 1)
+#define PHY_STATUS_EXTREGS (1<< 0)
+
+// These are the same for both AUTONEG registers
+#define PHY_AUTONEG_NEXT (1<<15)
+#define PHY_AUTONEG_ACK (1<<14)
+#define PHY_AUTONEG_REMOTEFAULT (1<<13)
+#define PHY_AUTONEG_100BASET4 (1<< 9)
+#define PHY_AUTONEG_100BASETX_FDX (1<< 8)
+#define PHY_AUTONEG_100BASETX_HDX (1<< 7)
+#define PHY_AUTONEG_10BASET_FDX (1<< 6)
+#define PHY_AUTONEG_10BASET_HDX (1<< 5)
+#define PHY_AUTONEG_CSMA_802_3 (1<< 0)
+
+#if 0
+// Others are undocumented
+#define PHY_STATUS_DETECT_SPEED100 (1<< 7)
+#define PHY_STATUS_DETECT_DPLX_FULL (1<< 6)
+#endif
+
+// Phew!
+// --------------------------------------------------------------------------
+#endif // CYGONCE_HAL_UPD985XX_ETH_H
+// End of upd985xx_eth.h
diff --git a/ecos/packages/devs/eth/mips/upd985xx/current/src/if_upd985xx.c b/ecos/packages/devs/eth/mips/upd985xx/current/src/if_upd985xx.c
new file mode 100644
index 0000000..b9c92b3
--- /dev/null
+++ b/ecos/packages/devs/eth/mips/upd985xx/current/src/if_upd985xx.c
@@ -0,0 +1,1610 @@
+//==========================================================================
+//
+// if_upd985xx.c
+//
+// Ethernet drivers
+// NEC UPD985XX device ethernet specific support
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): hmt, gthomas
+// Contributors:
+// Date: 2001-06-28
+// Purpose:
+// Description: hardware driver for uPD985xx ethernet devices
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/devs_eth_mips_upd985xx.h>
+#include <pkgconf/io_eth_drivers.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/io/eth/netdev.h>
+#include <cyg/io/eth/eth_drv.h>
+
+#ifdef CYGPKG_NET
+#include <pkgconf/net.h>
+#include <net/if.h> /* Needed for struct ifnet */
+#else
+#include <cyg/hal/hal_if.h>
+#endif
+
+#include <cyg/devs/eth/upd985xx_eth.h>
+
+#include <cyg/io/eth/eth_drv_stats.h>
+
+// ------------------------------------------------------------------------
+
+#ifdef CYGDBG_DEVS_ETH_MIPS_UPD985XX_CHATTER
+#define nDEBUG_TRAFFIC // This one prints stuff as packets come and go
+#define nDEBUG_IOCTL // ioctl() call printing
+#define DEBUG // Startup printing mainly
+#endif
+
+#define os_printf diag_printf
+#define db_printf diag_printf
+
+#define STATIC static
+
+// ------------------------------------------------------------------------
+// I/O access macros as inlines for later changes to >1 device?
+//
+// (If we need to do this, then these macros would *assume* the
+// presence of a valid p_eth_upd985xx just like we always have)
+
+static inline void OUTL( volatile cyg_uint32 *io_address, cyg_uint32 value )
+{ *io_address = value; }
+
+static inline cyg_uint32 INL( volatile cyg_uint32 *io_address )
+{ return *io_address; }
+
+// These map cachable addresses to uncachable ones and vice versa.
+// This is all fixed on MIPS. 8-9xxxxxxx uncachable, A-Bxxxxxxx cachable.
+#define VIRT_TO_BUS( _x_ ) virt_to_bus((cyg_uint32)(_x_))
+static inline cyg_uint8 *virt_to_bus(cyg_uint32 p_memory)
+{
+ return (cyg_uint8 *)(0xa0000000u + (p_memory & ~0xe0000000u));
+}
+#define BUS_TO_VIRT( _x_ ) bus_to_virt((cyg_uint32)(_x_))
+static inline cyg_uint8 *bus_to_virt(cyg_uint32 p_memory)
+{
+ return (cyg_uint8 *)(0x80000000u + (p_memory & ~0xe0000000u));
+}
+
+
+// ------------------------------------------------------------------------
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_S1
+#define FLUSH_WRITES() CYG_MACRO_START \
+ (void) INL( ETH_RXSR ); \
+CYG_MACRO_END
+#else
+#define FLUSH_WRITES() CYG_EMPTY_STATEMENT
+#endif
+
+// ------------------------------------------------------------------------
+//
+// DEVICES AND PACKET QUEUES
+//
+// ------------------------------------------------------------------------
+
+// 128 bytes extra for VLAN packets should be enough; AFAICT usually the
+// encapsulation is only 4 or 10 bytes extra.
+#define MAX_ETHERNET_PACKET_SIZE 1536 // Ethernet Rx packet size
+#define MAX_OVERSIZE_PACKET_SIZE 1664 // VLAN Rx packet size
+#define MAX_RX_PACKET_SIZE MAX_OVERSIZE_PACKET_SIZE
+
+#define NUM_RXBUFS (8)
+
+// This one is the hardware definition.
+struct bufdesc {
+ volatile cyg_uint32 attr;
+ cyg_uint8 *ptr;
+};
+
+// Rx databuffer.
+STATIC cyg_uint8 rx_databuf[ NUM_RXBUFS ] [ MAX_RX_PACKET_SIZE ];
+
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3
+// Tx databuffer
+STATIC cyg_uint8 tx_databuf[ MAX_RX_PACKET_SIZE ];
+#endif
+
+struct eth_upd985xx {
+ cyg_uint8 active, index, tx_busy, mac_addr_ok;
+ cyg_uint8 vector; // interrupt numbers are small
+ cyg_uint8 phy_status; // from PHY_STATUS_ flags below
+ cyg_uint8 hardwired_esa;
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2
+ cyg_uint8 promisc;
+#endif
+ cyg_uint8 mac_address[6];
+
+ cyg_handle_t interrupt_handle;
+ cyg_interrupt interrupt_object;
+
+ struct cyg_netdevtab_entry *ndp;
+
+ // these shall hold uncached addresses of the structures following...
+ volatile struct bufdesc *txring;
+ volatile struct bufdesc *rxring_active;
+ volatile struct bufdesc *rxring_next;
+ int rxring_active_index;
+ int rxring_next_index;
+ cyg_uint32 intrs;
+ cyg_uint32 tx_keys[1];
+
+ // -----------------------------------------------------------------
+ // Statistics counters
+ cyg_uint32 count_rx_resource;
+ cyg_uint32 count_rx_restart;
+ cyg_uint32 count_interrupts;
+ cyg_uint32 count_bad_isr_restarts;
+ cyg_uint32 count_bad_tx_completion;
+
+ // -----------------------------------------------------------------
+ // DO NOT ACCESS THESE DIRECTLY - THE DEVICE HAS TO SEE THEM UNCACHED
+
+ // Initially, enough for one whole transmission to be described in one go,
+ // plus a null link on the end.
+ struct bufdesc tx_bufdesc[ MAX_ETH_DRV_SG + 2 ];
+
+ // Pending rx buffers, of full size.
+ struct bufdesc rx_bufdesc[ NUM_RXBUFS+1 ];
+
+ // -----------------------------------------------------------------
+};
+
+struct eth_upd985xx eth_upd985xx[CYGNUM_DEVS_ETH_MIPS_UPD985XX_DEV_COUNT] = {
+ {
+ index: 0,
+ vector: CYGNUM_HAL_INTERRUPT_ETHER,
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2
+ promisc: 0,
+#endif
+#ifdef CYGSEM_DEVS_ETH_UPD985XX_ETH0_SET_ESA
+ hardwired_esa: 1,
+ mac_address: CYGDAT_DEVS_ETH_UPD985XX_ETH0_ESA,
+ mac_addr_ok: 1,
+#else
+ hardwired_esa: 0,
+ mac_addr_ok: 0,
+#endif
+ }
+};
+
+// eth0
+
+ETH_DRV_SC(upd985xx_sc0,
+ &eth_upd985xx[0], // Driver specific data
+ CYGDAT_DEVS_ETH_UPD985XX_ETH0_NAME, // name for this interface
+ eth_upd985xx_start,
+ eth_upd985xx_stop,
+ eth_upd985xx_ioctl,
+ eth_upd985xx_can_send,
+ eth_upd985xx_send,
+ eth_upd985xx_recv,
+ eth_upd985xx_deliver,
+ eth_upd985xx_poll,
+ eth_upd985xx_int_vector
+ );
+
+NETDEVTAB_ENTRY(upd985xx_netdev0,
+ "upd985xx-" CYGDAT_DEVS_ETH_UPD985XX_ETH0_NAME,
+ upd985xx_eth_upd985xx_init,
+ &upd985xx_sc0);
+
+
+// This is in a macro so that if more devices arrive it can easily be changed
+#define CHECK_NDP_SC_LINK() CYG_MACRO_START \
+ CYG_ASSERT( ((void *)ndp == (void *)&upd985xx_netdev0), "Bad ndp" ); \
+ CYG_ASSERT( ((void *)sc == (void *)&upd985xx_sc0), "Bad sc" ); \
+ CYG_ASSERT( (void *)p_eth_upd985xx == sc->driver_private, \
+ "sc pointer bad" ); \
+ CYG_ASSERT( (void *)p_eth_upd985xx == (void *)&eth_upd985xx[0], \
+ "bad p_eth_upd985x" ); \
+CYG_MACRO_END
+
+#define NUM_ELEMENTS( _x_ ) (sizeof( (_x_) ) / sizeof( (_x_[0]) ) )
+
+// ------------------------------------------------------------------------
+//
+// FUNCTION PROTOTYPES
+//
+// ------------------------------------------------------------------------
+STATIC void InitRxRing(struct eth_upd985xx* p_eth_upd985xx);
+STATIC void NextRxRing(struct eth_upd985xx* p_eth_upd985xx);
+STATIC void InitTxRing(struct eth_upd985xx* p_eth_upd985xx);
+STATIC void ResetTxRing(struct eth_upd985xx* p_eth_upd985xx);
+
+#ifdef CYGPKG_NET
+STATIC int eth_upd985xx_configure(struct eth_upd985xx* p_eth_upd985xx,
+ int promisc, int oversized);
+#endif
+
+STATIC void PacketRxReady(struct eth_upd985xx* p_eth_upd985xx);
+STATIC void TxDone(struct eth_upd985xx* p_eth_upd985xx);
+
+#define PHY_STATUS_LINK (1)
+#define PHY_STATUS_FDX (2)
+#define PHY_STATUS_100MBPS (4)
+STATIC int eth_upd985xx_status( struct eth_upd985xx *p_eth_upd985xx );
+STATIC int eth_set_mac_address( struct eth_upd985xx *p_eth_upd985xx, void *data );
+
+// ------------------------------------------------------------------------
+//
+// MII ACCESS TO PHY DEVICE
+//
+// ------------------------------------------------------------------------
+
+STATIC cyg_bool mii_read( cyg_uint32 reg, cyg_uint32 *pvalue,
+ struct eth_upd985xx *p_eth_upd985xx )
+{
+ int i = 1000;
+ // wait a bit for it to be idle
+ while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
+ & INL(ETH_MIND)) )
+ if ( --i < 0 )
+ return false;
+ // Tell it the register address and PHY address
+ OUTL( ETH_MADR, ETH_MADR_PHY_DEVICE_PHYS_ADDRESS | reg );
+ OUTL( ETH_MCMD, ETH_MCMD_RSTAT ); // "do a read"
+ // wait for the read to complete
+ while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
+ & INL(ETH_MIND)) )
+ if ( --i < 0 )
+ return false;
+ // so get the data
+ *pvalue = INL( ETH_MRDD );
+ return true;
+}
+
+#if 0
+STATIC cyg_bool mii_write( cyg_uint32 reg, cyg_uint32 value,
+ struct eth_upd985xx *p_eth_upd985xx )
+{
+ int i = 1000;
+ // wait a bit for it to be idle
+ while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
+ & INL(ETH_MIND)) )
+ if ( --i < 0 )
+ return false;
+ // Tell it the register address and PHY address
+ OUTL( ETH_MADR, ETH_MADR_PHY_DEVICE_PHYS_ADDRESS | reg );
+ // And write the data:
+ OUTL( ETH_MWTD, value );
+ // wait a bit for it to be idle
+ while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
+ & INL(ETH_MIND)) )
+ if ( --i < 0 )
+ return false;
+ return true;
+}
+#endif
+
+// ------------------------------------------------------------------------
+//
+// INTERRUPT HANDLERS
+//
+// ------------------------------------------------------------------------
+
+STATIC cyg_uint32 eth_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+ cyg_drv_interrupt_mask( vector );
+
+ return CYG_ISR_CALL_DSR; // schedule DSR
+}
+
+// ------------------------------------------------------------------------
+// This is a callback from the higher level thread in consequence of the DSR
+STATIC void
+eth_upd985xx_deliver(struct eth_drv_sc *sc)
+{
+ register int intrs;
+ struct eth_upd985xx *p_eth_upd985xx;
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+ p_eth_upd985xx->count_interrupts++;
+
+ intrs = INL( ETH_ISR ); // Read-clear
+ // Acknowledge once at the start anyway to prevent an interrupt loop in
+ // case of a transient - interrupts latch in the interrupt controller
+ // as well as in the ethernet device.
+ cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
+
+#ifdef DEBUG_TRAFFIC
+ os_printf("\n[[[[[[[ Deliver intrs = %x\n", intrs );
+#endif
+
+ // Guard possible external entry points
+ if ( ! p_eth_upd985xx->active )
+ return; // without unmasking the interrupt
+
+ while ( intrs ) {
+ if ( 0xffff0000 & intrs ) {
+ // Then something very bad has happened
+ p_eth_upd985xx->count_bad_isr_restarts++;
+ CYG_ASSERT ( p_eth_upd985xx->active, "Device not active!" );
+ eth_upd985xx_stop( sc );
+ eth_upd985xx_start( sc, NULL, 0 );
+ intrs = INL( ETH_ISR ); // Read-clear
+ }
+ p_eth_upd985xx->intrs = intrs;
+ if ( ( ETH_ISR_XMTDN | ETH_ISR_TABR ) & intrs ) {
+ // Scan for completed Txen and inform the stack
+ TxDone(p_eth_upd985xx);
+ }
+ if ( ( ETH_ISR_RCVDN | ETH_ISR_RBDRS | ETH_ISR_RBDRU ) & intrs ) {
+ // Pass any rx data up the stack
+ PacketRxReady(p_eth_upd985xx);
+ }
+ // Now we have made the interrupt causes go away, acknowledge and
+ // *then* read the ISR again. That way the race can result in a
+ // spurious interrupt rather than a lost interrupt.
+ cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
+ intrs = INL( ETH_ISR ); // Read-clear
+#ifdef DEBUG_TRAFFIC
+ if ( intrs )
+ os_printf("------- Again intrs = %x\n", intrs );
+#endif
+ }
+#ifdef DEBUG_TRAFFIC
+ os_printf("]]]]]]]] Done intrs = %x\n\n", intrs );
+#endif
+
+ cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
+}
+
+// ------------------------------------------------------------------------
+// Device table entry to operate the chip in a polled mode.
+// Only diddle the interface we were asked to!
+
+STATIC void
+eth_upd985xx_poll(struct eth_drv_sc *sc)
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+ // As it happens, this driver always requests the DSR to be called:
+ (void)eth_isr( p_eth_upd985xx->vector, (cyg_addrword_t)sc );
+ eth_upd985xx_deliver( sc );
+}
+
+// ------------------------------------------------------------------------
+// Determine interrupt vector used by a device - for attaching GDB stubs
+// packet handler.
+STATIC int
+eth_upd985xx_int_vector(struct eth_drv_sc *sc)
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+ return (p_eth_upd985xx->vector);
+}
+
+// ------------------------------------------------------------------------
+
+STATIC int
+eth_set_mac_address( struct eth_upd985xx *p_eth_upd985xx, void *data )
+{
+ cyg_uint8 *p = (cyg_uint8 *)data;
+ cyg_uint8 *mac_address;
+
+ mac_address = &p_eth_upd985xx->mac_address[0];
+
+ mac_address[5] = p[5];
+ mac_address[4] = p[4];
+ mac_address[3] = p[3];
+ mac_address[2] = p[2];
+ mac_address[1] = p[1];
+ mac_address[0] = p[0];
+
+ p_eth_upd985xx->mac_addr_ok = 1;
+
+ // Set the ESA in the device regs
+ OUTL( ETH_LSA2,
+ (p_eth_upd985xx->mac_address[1]) |
+ (p_eth_upd985xx->mac_address[0] << 8 ) );
+ OUTL( ETH_LSA1,
+ (p_eth_upd985xx->mac_address[5]) |
+ (p_eth_upd985xx->mac_address[4] << 8 ) |
+ (p_eth_upd985xx->mac_address[3] << 16 ) |
+ (p_eth_upd985xx->mac_address[2] << 24) );
+
+ return 0; // OK
+}
+
+// ------------------------------------------------------------------------
+
+STATIC void
+eth_upd985xx_reset( struct eth_upd985xx *p_eth_upd985xx )
+{
+ int i;
+
+ // Reset whole device: Software Reset (clears automatically)
+ OUTL( ETH_CCR, ETH_CCR_SRT );
+ for ( i = 0; i < 10000; i++ ) /* nothing */;
+ // Reset internal units
+ OUTL( ETH_MACC2, ETH_MACC2_MCRST | ETH_MACC2_RFRST | ETH_MACC2_TFRST );
+ for ( i = 0; i < 10000; i++ ) /* nothing */;
+ FLUSH_WRITES();
+ OUTL( ETH_MACC2, 0 ); // (and release reset)
+ // Enable CRC adding, padding
+ FLUSH_WRITES();
+ OUTL( ETH_MACC1,
+ ETH_MACC1_CRCEN | ETH_MACC1_PADEN |
+ ETH_MACC1_TXFC | ETH_MACC1_RXFC | ETH_MACC1_PARF );
+ FLUSH_WRITES();
+ OUTL( ETH_MACC2, ETH_MACC2_APD ); // Auto VLAN pad
+ FLUSH_WRITES();
+ OUTL( ETH_HT1, 0 );
+ FLUSH_WRITES();
+ OUTL( ETH_HT2, 0 );
+
+ // Enable rx of broadcasts, multicasts, but not promiscuous...
+ FLUSH_WRITES();
+#if defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2 ) && \
+ !defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY )
+ // Unless we are faking it.
+ OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM | ETH_AFR_PRO );
+#else
+ OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM );
+#endif
+
+ FLUSH_WRITES();
+ OUTL( ETH_IPGT, 0x00000013 );
+ FLUSH_WRITES();
+ OUTL( ETH_IPGR, 0x00000e13 );
+ FLUSH_WRITES();
+ OUTL( ETH_CLRT, 0x0000380f );
+ FLUSH_WRITES();
+ OUTL( ETH_LMAX, MAX_ETHERNET_PACKET_SIZE );
+
+ // Select a clock for the MII
+ FLUSH_WRITES();
+ OUTL( ETH_MIIC, ETH_MIIC_66 ); // Example code sets to 66.
+ // Set VLAN type reg
+ FLUSH_WRITES();
+ OUTL( ETH_VLTP, ETH_VLTP_VLTP );
+
+ // Set the ESA in the device regs
+ if ( p_eth_upd985xx->mac_addr_ok ) {
+ FLUSH_WRITES();
+ OUTL( ETH_LSA2,
+ (p_eth_upd985xx->mac_address[1]) |
+ (p_eth_upd985xx->mac_address[0] << 8 ) );
+ FLUSH_WRITES();
+ OUTL( ETH_LSA1,
+ (p_eth_upd985xx->mac_address[5]) |
+ (p_eth_upd985xx->mac_address[4] << 8 ) |
+ (p_eth_upd985xx->mac_address[3] << 16 ) |
+ (p_eth_upd985xx->mac_address[2] << 24) );
+ }
+
+ FLUSH_WRITES();
+ OUTL( ETH_RXFCR, ETH_RXFCR_UWM_DEFAULT |
+ ETH_RXFCR_LWM_DEFAULT | ETH_RXFCR_DRTH16W );
+
+ FLUSH_WRITES();
+ // Fault E4 - use only 32 for FLTH, not the previously recommended 48 (words)
+ // Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E4
+ // but no config opt is provided.
+ OUTL( ETH_TXFCR, ETH_TXFCR_TPTV_DEFAULT |
+ ETH_TXFCR_TX_DRTH_DEFAULT | (32 << ETH_TXFCR_TX_FLTH_SHIFT) );
+
+ // Transmit and receive config regs we hit when enabling those
+ // functions separately, and the wet string end of the receiver
+ // which is controlled by MACC1 |= ETH_MACC1_SRXEN;
+
+ // Tx and Rx interrupts enabled internally;
+ // Tx done/aborted, and rx OK.
+ FLUSH_WRITES();
+ OUTL( ETH_MSR, ETH_ISR_XMTDN | ETH_ISR_TABR |
+ ETH_ISR_RCVDN | ETH_ISR_RBDRS | ETH_ISR_RBDRU );
+ FLUSH_WRITES();
+}
+
+// ------------------------------------------------------------------------
+//
+// NETWORK INTERFACE INITIALIZATION
+//
+// ------------------------------------------------------------------------
+STATIC bool
+upd985xx_eth_upd985xx_init(struct cyg_netdevtab_entry * ndp)
+{
+ struct eth_drv_sc *sc;
+ cyg_uint8 *mac_address;
+ struct eth_upd985xx *p_eth_upd985xx;
+
+#ifdef DEBUG
+ db_printf("upd985xx_eth_upd985xx_init\n");
+#endif
+
+ sc = (struct eth_drv_sc *)(ndp->device_instance);
+ p_eth_upd985xx = (struct eth_upd985xx *)(sc->driver_private);
+
+ CHECK_NDP_SC_LINK();
+
+ p_eth_upd985xx->tx_busy = 0;
+
+ // record the net dev pointer
+ p_eth_upd985xx->ndp = (void *)ndp;
+
+ mac_address = &p_eth_upd985xx->mac_address[0];
+
+#ifdef CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
+ if ( ! p_eth_upd985xx->hardwired_esa ) {
+ cyg_uint8 *p;
+ union macar {
+ struct {
+ cyg_uint32 macar1, macar2, macar3;
+ } integers;
+ cyg_uint8 bytes[12];
+ } eeprom;
+
+ eeprom.integers.macar1 = INL( MACAR1 ); // MAC Address Register 1
+ eeprom.integers.macar2 = INL( MACAR2 ); // MAC Address Register 2
+ eeprom.integers.macar3 = INL( MACAR3 ); // MAC Address Register 3
+
+ if ( (0 != eeprom.integers.macar1 ||
+ 0 != eeprom.integers.macar2 ||
+ 0 != eeprom.integers.macar3 )
+ &&
+ (0xffffffff != eeprom.integers.macar1 ||
+ 0xffffffff != eeprom.integers.macar2 ||
+ 0xffffffff != eeprom.integers.macar3 ) ) {
+ // Then we have good data in the EEPROM
+#ifdef DEBUG
+ os_printf( "EEPROM data %08x %08x %08x\n",
+ eeprom.integers.macar1,
+ eeprom.integers.macar2,
+ eeprom.integers.macar3 );
+#endif
+ p = &eeprom.bytes[0]; // pick up either set of ESA info
+ if ( 1 == p_eth_upd985xx->index )
+ p += 6;
+
+ mac_address[5] = p[5];
+ mac_address[4] = p[4];
+ mac_address[3] = p[3];
+ mac_address[2] = p[2];
+ mac_address[1] = p[1];
+ mac_address[0] = p[0];
+ p_eth_upd985xx->mac_addr_ok = 1;
+ }
+ else {
+ // Fake it so we can get RedBoot going on a board with no EEPROM
+ mac_address[0] = 0;
+ mac_address[1] = 0xBA;
+ mac_address[2] = 0xD0;
+ mac_address[3] = 0xEE;
+ mac_address[4] = 0x00;
+ mac_address[5] = p_eth_upd985xx->index;
+ p_eth_upd985xx->mac_addr_ok = 1;
+ }
+ }
+#endif // CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
+
+ // Init the underlying hardware and insert the ESA:
+ eth_upd985xx_reset(p_eth_upd985xx);
+
+#ifdef DEBUG
+ os_printf("MAC Address %s, ESA = %02X %02X %02X %02X %02X %02X\n",
+ p_eth_upd985xx->mac_addr_ok ? "OK" : "**BAD**",
+ mac_address[0], mac_address[1], mac_address[2], mac_address[3],
+ mac_address[4], mac_address[5]);
+#endif
+
+ // Set up the pointers to data structures
+ InitTxRing(p_eth_upd985xx);
+
+ // Construct the interrupt handler
+ p_eth_upd985xx->active = 0;
+ cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
+ cyg_drv_interrupt_mask(p_eth_upd985xx->vector);
+ cyg_drv_interrupt_create(
+ p_eth_upd985xx->vector,
+ 0, // Priority - unused
+ (CYG_ADDRWORD)sc, // Data item passed to ISR & DSR
+ eth_isr, // ISR
+ eth_drv_dsr, // DSR (generic)
+ &p_eth_upd985xx->interrupt_handle, // handle to intr obj
+ &p_eth_upd985xx->interrupt_object ); // space for int obj
+
+ cyg_drv_interrupt_attach(p_eth_upd985xx->interrupt_handle);
+
+ // Initialize upper level driver
+ if ( p_eth_upd985xx->mac_addr_ok )
+ (sc->funs->eth_drv->init)(sc, &(p_eth_upd985xx->mac_address[0]) );
+ else
+ (sc->funs->eth_drv->init)(sc, 0 );
+
+ return (1);
+}
+
+// ------------------------------------------------------------------------
+//
+// Function : eth_upd985xx_start
+//
+// ------------------------------------------------------------------------
+STATIC void
+eth_upd985xx_start( struct eth_drv_sc *sc,
+ unsigned char *enaddr, int flags )
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+ cyg_uint32 ss;
+#ifdef CYGPKG_NET
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+#endif
+
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+#ifdef DEBUG
+ os_printf("eth_upd985xx_start %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );
+#endif
+
+ if ( p_eth_upd985xx->active )
+ eth_upd985xx_stop( sc );
+
+ p_eth_upd985xx->active = 1;
+
+#ifdef CYGPKG_NET
+ /* Enable promiscuous mode if requested, reception of oversized frames always.
+ * The latter is needed for VLAN support and shouldn't hurt even if we're not
+ * using VLANs.
+ */
+ eth_upd985xx_configure(p_eth_upd985xx, !!(ifp->if_flags & IFF_PROMISC), 1);
+#endif
+
+ // renegotiate link status
+ p_eth_upd985xx->phy_status = eth_upd985xx_status( p_eth_upd985xx );
+
+ if ( p_eth_upd985xx->phy_status & PHY_STATUS_FDX ) {
+ cyg_uint32 ss;
+ // then enable full duplex in the MAC
+ ss = INL( ETH_MACC1 );
+ ss |= ETH_MACC1_FDX;
+ OUTL( ETH_MACC1, ss );
+ }
+
+#ifdef DEBUG
+ {
+ int status = p_eth_upd985xx->phy_status;
+ os_printf("eth_upd985xx_start %d Link = %s, %s Mbps, %s Duplex\n",
+ p_eth_upd985xx->index,
+ status & PHY_STATUS_LINK ? "Up" : "Down",
+ status & PHY_STATUS_100MBPS ? "100" : "10",
+ status & PHY_STATUS_FDX ? "Full" : "Half"
+ );
+ }
+#endif
+
+
+ // Start the receive engine
+ p_eth_upd985xx->count_rx_restart++;
+ // Initialize all but one buffer: [B0,B1,B2,...Bx,NULL,LINK]
+ InitRxRing( p_eth_upd985xx );
+ // Point the hardware at the list of buffers
+ OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );
+ // Tell it about the buffers via the rx descriptor count
+ OUTL( ETH_RXPDR, ETH_RXPDR_AL | (NUM_RXBUFS-1) );
+ // Ack any pending interrupts from the system
+ p_eth_upd985xx->intrs = INL( ETH_ISR ); // Read-clear
+ // Start the rx.
+ OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );
+
+ // Enable the wet string end of the receiver
+ ss = INL( ETH_MACC1 );
+ ss |= ETH_MACC1_SRXEN;
+ OUTL( ETH_MACC1, ss );
+
+ // And unmask the interrupt
+ cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
+ cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
+}
+
+// ------------------------------------------------------------------------
+//
+// Function : eth_upd985xx_status; 10/100 and Full/Half Duplex (FDX/HDX)
+//
+// ------------------------------------------------------------------------
+STATIC int eth_upd985xx_status( struct eth_upd985xx *p_eth_upd985xx )
+{
+ int status;
+ int i, j;
+ // Some of these bits latch and only reflect "the truth" on a 2nd reading.
+ // So read and discard.
+ mii_read( PHY_CONTROL_REG, &i, p_eth_upd985xx );
+ mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx );
+ // Use the "and" of the local and remote capabilities words to infer
+ // what is selected:
+ status = 0;
+ if ( mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx ) ) {
+ if ( PHY_STATUS_LINK_OK & i )
+ status |= PHY_STATUS_LINK;
+ }
+ if ( mii_read( PHY_AUTONEG_ADVERT, &j, p_eth_upd985xx ) &&
+ mii_read( PHY_AUTONEG_REMOTE, &i, p_eth_upd985xx ) ) {
+#if defined( DEBUG_TRAFFIC ) || defined( DEBUG_IOCTL )
+ os_printf( "MII: capabilities are %04x, %04x; common %04x\n",
+ i, j, i & j );
+#endif
+ j &= i; // select only common capabilities
+
+ if ( (PHY_AUTONEG_100BASET4 |
+ PHY_AUTONEG_100BASETX_FDX |
+ PHY_AUTONEG_100BASETX_HDX) & j )
+ status |= PHY_STATUS_100MBPS;
+ if ( (PHY_AUTONEG_100BASETX_FDX | PHY_AUTONEG_10BASET_FDX) & j )
+ status |= PHY_STATUS_FDX;
+ }
+ return status;
+}
+
+// ------------------------------------------------------------------------
+//
+// Function : eth_upd985xx_stop
+//
+// ------------------------------------------------------------------------
+
+STATIC void eth_upd985xx_stop( struct eth_drv_sc *sc )
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+ // No more interrupts
+ cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
+ cyg_drv_interrupt_mask(p_eth_upd985xx->vector);
+
+#ifdef DEBUG
+ os_printf("eth_upd985xx_stop %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );
+#endif
+
+ p_eth_upd985xx->active = 0; // stop people tormenting it
+
+ if ( p_eth_upd985xx->tx_busy ) {
+ // Then it is finshed now, by force:
+ cyg_uint32 key = p_eth_upd985xx->tx_keys[ 0 ];
+ // Turn off the transmitter (before the callback to the stack).
+ OUTL( ETH_TXCR, 0 );
+#ifdef DEBUG_TRAFFIC
+ os_printf("Stop: tidying up TX, KEY %x\n", key );
+#endif
+ // Leave tx_busy true so no recursion can occur here.
+ // Then tell the stack we are done:
+ if ( key ) {
+ (sc->funs->eth_drv->tx_done)( sc, key, 0 );
+ }
+ }
+ p_eth_upd985xx->tx_keys[ 0 ] = 0;
+ p_eth_upd985xx->tx_busy = p_eth_upd985xx->active = 0;
+
+ eth_upd985xx_reset(p_eth_upd985xx);
+
+ ResetTxRing( p_eth_upd985xx );
+}
+
+
+// ------------------------------------------------------------------------
+//
+// Function : InitRxRing
+//
+// ------------------------------------------------------------------------
+STATIC void InitRxRing(struct eth_upd985xx* p_eth_upd985xx)
+{
+ int i;
+ struct bufdesc *bp;
+
+ // first just blat the various flags and addresses: the first N
+ // bufdescs point to data buffers, the last one is NULL.
+ bp = (struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[0] );
+ // Record the initial active buffer:
+ p_eth_upd985xx->rxring_active = bp;
+ p_eth_upd985xx->rxring_active_index = 0;
+ for ( i = 0; i < NUM_RXBUFS - 1; i++, bp++ ) {
+ bp->ptr = VIRT_TO_BUS( &rx_databuf[i][0] );
+ bp->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU
+ | (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );
+ }
+ CYG_ASSERT( i == NUM_RXBUFS-1, "Penultimate rx buffer index mismatch" );
+ CYG_ASSERT( (cyg_uint8 *)bp ==
+ VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS-1] ),
+ "Penultimate rx buffer address mismatch" );
+
+ // NULL out the penultimate one
+ bp->ptr = NULL;
+ bp->attr = 0;
+ // And record it as next one to use
+ p_eth_upd985xx->rxring_next = bp;
+ p_eth_upd985xx->rxring_next_index = NUM_RXBUFS-1;
+
+ // Step on to the extra entry at the end which makes a ring:
+ bp++;
+ CYG_ASSERT( (cyg_uint8 *)bp ==
+ VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS] ),
+ "Ultimate rx buffer address mismatch" );
+
+ // Link the Ultimate back to the start
+ bp->ptr = (cyg_uint8 *)p_eth_upd985xx->rxring_active; // Zeroth entry
+ bp->attr = ETH_BUF_D_L_LINK;
+
+ // All done.
+}
+
+
+// ------------------------------------------------------------------------
+//
+// Function : NextRxRing
+//
+// ------------------------------------------------------------------------
+
+STATIC void NextRxRing(struct eth_upd985xx* p_eth_upd985xx )
+{
+ volatile struct bufdesc *next, *dead;
+ int iactive;
+ int inext;
+
+ iactive = p_eth_upd985xx->rxring_active_index;
+ inext = p_eth_upd985xx->rxring_next_index;
+
+ // Preconditions:
+ CYG_ASSERT( 0 <= inext && inext < NUM_RXBUFS, "Bad inext" );
+ CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );
+ CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )
+ == (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );
+ CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )
+ == (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );
+ CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );
+ CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );
+ CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );
+ CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==
+ p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );
+ CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),
+ "Chasing pointers mismatch" );
+
+ // Select the new bufdesc to be active - ie. next to scan for reception:
+ if ( ++iactive >= NUM_RXBUFS )
+ iactive = 0;
+ dead = p_eth_upd985xx->rxring_active; // the one that just died
+ // Step ahead the new active buffer:
+ p_eth_upd985xx->rxring_active = (volatile struct bufdesc *)
+ VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] );
+ p_eth_upd985xx->rxring_active_index = iactive;
+
+ // Blow away the currently active entry; we have dealt with it already
+ // and it is needed for an end stop to the ring:
+ dead->ptr = NULL;
+ dead->attr = 0;
+
+ // Select the next bufdesc to enliven
+ next = p_eth_upd985xx->rxring_next;
+ next->ptr = VIRT_TO_BUS( &rx_databuf[inext][0] );
+ next->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU
+ | (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );
+
+ // And update the external info to reflect this:
+ if ( ++inext >= NUM_RXBUFS )
+ inext = 0;
+ next = (volatile struct bufdesc *)
+ VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] );
+
+ p_eth_upd985xx->rxring_next = next;
+ p_eth_upd985xx->rxring_next_index = inext;
+
+ // Postconditions:
+ CYG_ASSERT( 0 <= inext && inext < NUM_RXBUFS, "Bad inext" );
+ CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );
+ CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )
+ == (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );
+ CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )
+ == (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );
+ CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );
+ CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );
+ CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );
+ CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==
+ p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );
+ CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),
+ "Chasing pointers mismatch" );
+}
+
+// ------------------------------------------------------------------------
+//
+// Function : PacketRxReady (Called from delivery thread)
+//
+// ------------------------------------------------------------------------
+STATIC void PacketRxReady(struct eth_upd985xx* p_eth_upd985xx)
+{
+ struct cyg_netdevtab_entry *ndp;
+ struct eth_drv_sc *sc;
+ cyg_uint32 ss, length;
+ cyg_bool reset_required = 0;
+
+ ndp = (struct cyg_netdevtab_entry *)(p_eth_upd985xx->ndp);
+ sc = (struct eth_drv_sc *)(ndp->device_instance);
+
+ CHECK_NDP_SC_LINK();
+
+#ifdef DEBUG_TRAFFIC
+ ss = INL( ETH_RXSR );
+ os_printf("PacketRxReady: RXSR %x\n", ss );
+#endif
+
+ if ( ETH_ISR_RBDRU & p_eth_upd985xx->intrs )
+ reset_required = 1; // Out of buffers
+ if ( ! ETH_ISR_RCVDN & p_eth_upd985xx->intrs )
+ reset_required = 1; // or if no reception completed, reset anyway
+
+ // For all ready rx blocks...
+ do {
+ volatile struct bufdesc *bp;
+
+ bp = p_eth_upd985xx->rxring_active; // Current rx candidate
+
+ ss = bp->attr;
+#ifdef DEBUG_TRAFFIC
+ os_printf("PacketRxReady attr %x at %x\n", ss, bp );
+#endif
+ if ( ETH_BUF_OWN_CPU == (ETH_BUF_OWN & ss) ) {
+ // Then the packet is untouched...
+ break;
+ }
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2
+ // Perform address recognition by hand, hardware is in promisc mode
+ // (we have settable "software" promisc mode too of course)
+ if ( ETH_BUF_OK & ss ) {
+ cyg_uint8 *esa = (cyg_uint8 *)bp->ptr; // (this is a non-cachable address)
+ int ok = 0;
+ if ( p_eth_upd985xx->promisc )
+ ok = 1; // accept the packet
+ else
+ if ( p_eth_upd985xx->mac_address[0] == esa[0] &&
+ p_eth_upd985xx->mac_address[1] == esa[1] &&
+ p_eth_upd985xx->mac_address[2] == esa[2] &&
+ p_eth_upd985xx->mac_address[3] == esa[3] &&
+ p_eth_upd985xx->mac_address[4] == esa[4] &&
+ p_eth_upd985xx->mac_address[5] == esa[5] )
+ ok = 1; // Then they are equal - accept
+ else
+ if ( 0xff == esa[0] &&
+ 0xff == esa[1] &&
+ 0xff == esa[2] &&
+ 0xff == esa[3] &&
+ 0xff == esa[4] &&
+ 0xff == esa[5] )
+ ok = 1; // Then they are equal - accept
+
+ if ( !ok )
+ ss = 0; // Easiest way...
+ }
+#endif
+ if ( ETH_BUF_OK & ss ) {
+ length = ETH_BUF_SIZE & ss;
+#ifdef DEBUG_TRAFFIC
+ os_printf("PacketRxReady found a packet size %d attr %x\n", length, ss );
+#endif
+ // Asserts for the length in-range can fire, with good status
+ // in the block, so be defensive here instead. Belt and braces.
+ if ( 63 < length && length <= MAX_RX_PACKET_SIZE ) {
+ CYG_ASSERT( ETH_BUF_D_L_DATA == (ETH_BUF_D_L & ss), "Not data buffer" );
+ CYG_ASSERT( length > 63, "Tiny packet" );
+ CYG_ASSERT( length <= MAX_RX_PACKET_SIZE, "Too big packet" );
+ CYG_ASSERT( ETH_BUF_LAST & ss, "Not last buffer" );
+ (sc->funs->eth_drv->recv)( sc, length );
+ } // Else drop it on the floor.
+ }
+
+ // Step along to the next buffer descriptor...
+ NextRxRing( p_eth_upd985xx );
+ if ( ! reset_required ) {
+ // And tell the device it can have a biscuit:
+ OUTL( ETH_RXPDR, ETH_RXPDR_AL | 1 );
+
+ // Now, before moving on to the next packet, find out if receptions
+ // had caught up with us before adding that new buffer:
+ ss = INL( ETH_RXPDR );
+ ss &= ETH_RXPDR_RNOD;
+ ss >>= ETH_RXPDR_RNOD_SHIFT;
+ if ( 1 >= ss ) {
+ // Then it was zero before. So the rx engine is stopped.
+#ifdef DEBUG_TRAFFIC
+ os_printf( "***ZERO rx buffers were left\n" );
+#endif
+ reset_required = 1;
+ }
+ // Otherwise we carry on as usual.
+ }
+ } while ( 1 );
+
+ if ( reset_required ) {
+ p_eth_upd985xx->count_rx_resource++;
+ // Disable the wet string end of the receiver
+ ss = INL( ETH_MACC1 );
+ ss &=~ETH_MACC1_SRXEN;
+ OUTL( ETH_MACC1, ss );
+ // Disable the DMA engine
+ OUTL( ETH_RXCR, 0 );
+ // Reset the RxRing from scratch
+ InitRxRing( p_eth_upd985xx );
+ // Point the hardware at the list of buffers
+ OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );
+ // Tell it about the buffers via the rx descriptor count:
+ ss = INL( ETH_RXPDR );
+ ss &= ETH_RXPDR_RNOD;
+ ss >>= ETH_RXPDR_RNOD_SHIFT;
+ // This awful register *increments* by what you write, even if the
+ // machinery is halted. Vile filthy evil rubbish.
+ OUTL( ETH_RXPDR, ETH_RXPDR_AL | ((NUM_RXBUFS-1) - ss) );
+ ss = INL( ETH_RXPDR );
+ CYG_ASSERT( (ETH_RXPDR_AL | (NUM_RXBUFS-1)) == ss, "RXPDR not right" );
+ // Start the rx.
+ OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );
+ // Enable the wet string end of the receiver
+ ss = INL( ETH_MACC1 );
+ ss |= ETH_MACC1_SRXEN;
+ OUTL( ETH_MACC1, ss );
+ // All done.
+#ifdef DEBUG_TRAFFIC
+ os_printf( "***Rx Machine restarted\n" );
+#endif
+ }
+}
+
+// and the callback function
+
+STATIC void
+eth_upd985xx_recv( struct eth_drv_sc *sc,
+ struct eth_drv_sg *sg_list, int sg_len )
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+ int total_len;
+ struct eth_drv_sg *last_sg;
+ cyg_uint8 *from_p;
+ volatile struct bufdesc *bp;
+
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+ // Guard possible external entry points
+ if ( ! p_eth_upd985xx->active )
+ return;
+
+ bp = p_eth_upd985xx->rxring_active; // Current rx candidate
+
+#ifdef DEBUG_TRAFFIC
+ os_printf("Rx status %x\n", bp->attr );
+#endif
+
+ if ( 0 == (ETH_BUF_OK & bp->attr) )
+ return;
+
+ total_len = ETH_BUF_SIZE & bp->attr;
+
+#ifdef DEBUG_TRAFFIC
+ os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n",
+ p_eth_upd985xx->index, (int)p_eth_upd985xx,
+ bp->attr,
+ sg_len, total_len);
+#endif
+
+ // Copy the data to the network stack
+ from_p = bp->ptr; // (this is a non-cachable address)
+
+ // check we have memory to copy into; we would be called even if
+ // caller was out of memory in order to maintain our state.
+ if ( 0 == sg_len || 0 == sg_list )
+ return; // caller was out of mbufs
+
+ CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
+ CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );
+
+ for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
+ cyg_uint8 *to_p;
+ int l;
+
+ to_p = (cyg_uint8 *)(sg_list->buf);
+ l = sg_list->len;
+
+ CYG_ASSERT( 0 <= l, "sg length -ve" );
+
+ if ( 0 >= l || 0 == to_p )
+ return; // caller was out of mbufs
+
+ if ( l > total_len )
+ l = total_len;
+
+ memcpy( to_p, from_p, l );
+ from_p += l;
+ total_len -= l;
+ }
+
+ CYG_ASSERT( 0 == total_len, "total_len mismatch in rx" );
+ CYG_ASSERT( last_sg == sg_list, "sg count mismatch in rx" );
+ CYG_ASSERT( bp->ptr < from_p, "from_p wild in rx" );
+ CYG_ASSERT( bp->ptr + MAX_RX_PACKET_SIZE >= from_p,
+ "from_p overflow in rx" );
+}
+
+
+// ------------------------------------------------------------------------
+//
+// Function : InitTxRing
+//
+// ------------------------------------------------------------------------
+STATIC void InitTxRing(struct eth_upd985xx* p_eth_upd985xx)
+{
+ int i;
+ volatile struct bufdesc *bp;
+
+ p_eth_upd985xx->txring =
+ (struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->tx_bufdesc[0] );
+
+ bp = p_eth_upd985xx->txring;
+
+ for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ); i++, bp++ ) {
+ bp->ptr = NULL;
+ bp->attr = 0;
+ }
+ // Last one is a NULL link
+ bp--;
+ bp->ptr = NULL;
+ bp->attr = ETH_BUF_D_L_LINK;
+
+ ResetTxRing(p_eth_upd985xx);
+}
+
+// ------------------------------------------------------------------------
+//
+// Function : ResetTxRing
+//
+// ------------------------------------------------------------------------
+STATIC void ResetTxRing(struct eth_upd985xx* p_eth_upd985xx)
+{
+ int i;
+ volatile struct bufdesc *bp;
+ bp = p_eth_upd985xx->txring;
+ for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ) - 1; i++, bp++ ) {
+ bp->attr =
+ ETH_BUF_LAST |
+ ETH_BUF_D_L_DATA |
+ ETH_BUF_OWN_CPU |
+ (ETH_BUF_SIZE & 0);
+ }
+}
+
+// ------------------------------------------------------------------------
+//
+// Function : TxDone (Called from delivery thread)
+//
+// This returns Tx's from the Tx Machine to the stack (ie. reports
+// completion) - allowing for missed interrupts, and so on.
+// ------------------------------------------------------------------------
+
+STATIC void TxDone(struct eth_upd985xx* p_eth_upd985xx)
+{
+ struct cyg_netdevtab_entry *ndp;
+ struct eth_drv_sc *sc;
+
+ ndp = (struct cyg_netdevtab_entry *)(p_eth_upd985xx->ndp);
+ sc = (struct eth_drv_sc *)(ndp->device_instance);
+
+ CHECK_NDP_SC_LINK();
+
+ if ( p_eth_upd985xx->tx_busy ) {
+ cyg_uint32 ss;
+
+ ss = INL( ETH_TXSR ); // Get tx status
+ if ( ss & (ETH_TXSR_CSE |
+ ETH_TXSR_TUDR |
+ ETH_TXSR_TGNT |
+ ETH_TXSR_LCOL |
+ ETH_TXSR_ECOL |
+ ETH_TXSR_TEDFR |
+ ETH_TXSR_TDFR |
+ ETH_TXSR_TBRO |
+ ETH_TXSR_TMUL |
+ ETH_TXSR_TDONE ) ) {
+ // Then it finished; somehow...
+ cyg_uint32 key = p_eth_upd985xx->tx_keys[ 0 ];
+
+ // Turn off the transmitter (before the callback to the stack).
+ OUTL( ETH_TXCR, 0 );
+
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E8
+ // Must take action after certain types of tx failure:
+ if ( ss & (ETH_TXSR_TUDR |
+ ETH_TXSR_LCOL |
+ ETH_TXSR_ECOL) ) {
+ p_eth_upd985xx->count_bad_tx_completion++;
+ CYG_ASSERT ( p_eth_upd985xx->active, "Device not active!" );
+ eth_upd985xx_stop( sc );
+ eth_upd985xx_start( sc, NULL, 0 );
+ key = 0; // Important! Stop above already fed it back.
+ }
+#endif
+
+#ifdef DEBUG_TRAFFIC
+ os_printf("TxDone %d %x: KEY %x\n",
+ p_eth_upd985xx->index, (int)p_eth_upd985xx, key );
+#endif
+ // Finished, ready for the next one
+ p_eth_upd985xx->tx_keys[ 0 ] = 0;
+ p_eth_upd985xx->tx_busy = 0;
+ // Then tell the stack we are done:
+ if (key) {
+ (sc->funs->eth_drv->tx_done)( sc, key,
+ 0 == (p_eth_upd985xx->intrs & ETH_ISR_TABR) );
+ }
+ }
+ }
+}
+
+
+// ------------------------------------------------------------------------
+//
+// Function : eth_upd985xx_can_send
+//
+// ------------------------------------------------------------------------
+
+STATIC int
+eth_upd985xx_can_send(struct eth_drv_sc *sc)
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+ // Guard possible external entry points
+ if ( ! p_eth_upd985xx->active )
+ return 0;
+
+ return ! p_eth_upd985xx->tx_busy;
+}
+
+// ------------------------------------------------------------------------
+//
+// Function : eth_upd985xx_send
+//
+// ------------------------------------------------------------------------
+
+STATIC void
+eth_upd985xx_send(struct eth_drv_sc *sc,
+ struct eth_drv_sg *sg_list, int sg_len, int total_len,
+ unsigned long key)
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+ struct eth_drv_sg *last_sg;
+ volatile struct bufdesc *bp;
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3
+ struct eth_drv_sg local_sg[2];
+#endif
+
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+#ifdef DEBUG_TRAFFIC
+ os_printf("Tx %d %x: %d sg's, %d bytes, KEY %x\n",
+ p_eth_upd985xx->index, (int)p_eth_upd985xx, sg_len, total_len, key );
+#endif
+
+ if ( ! p_eth_upd985xx->active )
+ return; // device inactive, no return
+
+ CYG_ASSERT( ! p_eth_upd985xx->tx_busy, "Can't send when busy!" );
+
+ p_eth_upd985xx->tx_busy++;
+
+ p_eth_upd985xx->tx_keys[0] = key;
+ bp = &p_eth_upd985xx->txring[0]; // Current free tx
+ CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
+ CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );
+
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3
+ // We must copy any Tx that is more than two SGs into just one buffer.
+ if ( sg_len > 2 ) {
+ cyg_uint8 *from_p, *to_p;
+ to_p = &tx_databuf[0]; // normal cached address
+ if ( sizeof( tx_databuf ) < total_len )
+ total_len = sizeof( tx_databuf );
+ for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
+ int l;
+
+ from_p = (cyg_uint8 *)(sg_list->buf); // normal cached address
+ l = sg_list->len;
+
+ if ( l > total_len )
+ l = total_len;
+
+ memcpy( to_p, from_p, l ); // All in cached memory
+ to_p += l;
+ total_len -= l;
+
+ if ( 0 > total_len )
+ break; // Should exit via sg_last normally
+ }
+
+ // Set up SGs describing the single tx buffer
+ total_len = to_p - &tx_databuf[0];
+ local_sg[0].buf = (CYG_ADDRESS)&tx_databuf[0];
+ local_sg[0].len = (CYG_ADDRWORD)total_len;
+ local_sg[1].buf = (CYG_ADDRESS)0;
+ local_sg[1].len = (CYG_ADDRWORD)0;
+
+ // And make the subsequent code use it.
+ sg_len = 1;
+ sg_list = &local_sg[0];
+ }
+#endif
+
+ for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
+ cyg_uint8 *from_p;
+ int l;
+
+ from_p = (cyg_uint8 *)(sg_list->buf); // normal cached address
+ l = sg_list->len;
+
+ if ( l > total_len )
+ l = total_len;
+
+ // Ensure the mbuf contents really is in RAM where DMA can see it.
+ // (Must round to cache lines apparantly for 4120)
+ HAL_DCACHE_STORE( ((CYG_ADDRESS)from_p) &~(HAL_DCACHE_LINE_SIZE-1),
+ l + HAL_DCACHE_LINE_SIZE );
+
+ bp->ptr = VIRT_TO_BUS( from_p ); // uncached real RAM address
+ bp->attr &=~(ETH_BUF_LAST | ETH_BUF_SIZE);
+ bp->attr |= ETH_BUF_SIZE & l;
+ bp->attr |= ETH_BUF_D_L_DATA;
+
+ total_len -= l;
+ bp++;
+
+ if ( 0 > total_len )
+ break; // Should exit via sg_last normally
+ }
+
+ CYG_ASSERT( bp > &p_eth_upd985xx->txring[0], "bp underflow" );
+ CYG_ASSERT( bp < &p_eth_upd985xx->txring[
+ NUM_ELEMENTS(p_eth_upd985xx->tx_bufdesc)
+ ], "bp underflow" );
+
+ bp--;
+ bp->attr |= ETH_BUF_LAST;
+
+ // Make the rest be null links
+ for ( bp++; bp <
+ &p_eth_upd985xx->txring[NUM_ELEMENTS(p_eth_upd985xx->tx_bufdesc)];
+ bp++ ) {
+ bp->attr = ETH_BUF_D_L_LINK;
+ bp->ptr = NULL;
+ }
+
+ CYG_ASSERT( 0 == total_len, "length mismatch in tx" );
+ CYG_ASSERT( last_sg == sg_list, "sg count mismatch in tx" );
+
+ // And start off the tx system
+
+ // Point the hardware at the list of buffers
+ OUTL( ETH_TXDPR, (cyg_uint32)p_eth_upd985xx->txring );
+ // and start the tx.
+
+ // Fault E4 - use only 8 for DTBS, not the previously recommended 16.
+ // Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E4
+ // but no config opt is provided.
+
+ // Fault E7: ETH_TXCR_AFCE must not be used.
+ // Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E7
+ // but no config opt is provided.
+
+ OUTL( ETH_TXCR, ETH_TXCR_TXE | ETH_TXCR_DTBS_8 /* | ETH_TXCR_AFCE */ );
+}
+
+#ifdef CYGPKG_NET
+// ------------------------------------------------------------------------
+//
+// Function : eth_upd985xx_configure
+//
+// Return : 0 = It worked.
+// non0 = It failed.
+// ------------------------------------------------------------------------
+
+STATIC int
+eth_upd985xx_configure(struct eth_upd985xx* p_eth_upd985xx, int promisc, int oversized)
+{
+ int ss;
+
+ // We implement permission of oversize packets by changing LMAX (rather
+ // than enabling HUGEN in ETH_MACC1) because we rely on only one
+ // reception per rx descriptor. General oversize packets could eat
+ // many rx descriptors and we would become ...confused.
+
+ // Sanity check the numbers we're about to use.
+ CYG_ASSERT( sizeof( rx_databuf[0] ) >= MAX_OVERSIZE_PACKET_SIZE,
+ "Oversize packet would overflow rx buffer" );
+ CYG_ASSERT( sizeof( rx_databuf[0] ) >= MAX_ETHERNET_PACKET_SIZE,
+ "Ethernet packet would overflow rx buffer" );
+ if ( oversized )
+ OUTL( ETH_LMAX, MAX_OVERSIZE_PACKET_SIZE );
+ else
+ OUTL( ETH_LMAX, MAX_ETHERNET_PACKET_SIZE );
+
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2
+ ss = promisc ? 1 : 0; // avoid unused var warning
+ p_eth_upd985xx->promisc = ss;
+#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY
+ // Then we must also set the mode in the chip
+ ss = INL( ETH_AFR );
+ if ( promisc )
+ ss |= ETH_AFR_PRO;
+ else
+ ss &=~ETH_AFR_PRO;
+ OUTL( ETH_AFR, ss );
+#endif // CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY
+#else
+ ss = INL( ETH_AFR );
+ if ( promisc )
+ ss |= ETH_AFR_PRO;
+ else
+ ss &=~ETH_AFR_PRO;
+ OUTL( ETH_AFR, ss );
+#endif
+ return 0; // OK
+}
+#endif
+
+// ------------------------------------------------------------------------
+//
+// Function : eth_upd985xx_ioctl
+//
+// ------------------------------------------------------------------------
+STATIC int
+eth_upd985xx_ioctl(struct eth_drv_sc *sc, unsigned long key,
+ void *data, int data_length)
+{
+ struct eth_upd985xx *p_eth_upd985xx;
+
+ p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
+
+#ifdef DEBUG_IOCTL
+ db_printf( "eth_upd985xx_ioctl: device eth%d at %x; key is 0x%x, data at %x[%d]\n",
+ p_eth_upd985xx->index, p_eth_upd985xx, key, data, data_length );
+#endif
+
+ // DO NOT guard possible external entry points - want to be able eg. to
+ // set a mac address of a down interface before bringing it up!
+
+ switch ( key ) {
+
+#ifdef ETH_DRV_SET_MAC_ADDRESS
+ case ETH_DRV_SET_MAC_ADDRESS:
+ if ( 6 != data_length )
+ return -2;
+ return eth_set_mac_address( p_eth_upd985xx, data );
+#endif
+
+#ifdef ETH_DRV_GET_IF_STATS_UD
+ case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
+#endif
+ // drop through
+#ifdef ETH_DRV_GET_IF_STATS
+ case ETH_DRV_GET_IF_STATS:
+#endif
+#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
+ {
+ struct ether_drv_stats *p = (struct ether_drv_stats *)data;
+ int i;
+
+ // Chipset entry is no longer supported; RFC1573.
+ for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
+ p->snmp_chipset[i] = 0;
+
+ // This perhaps should be a config opt, so you can make up your own
+ // description, or supply it from the instantiation.
+ strcpy( p->description, "NEC uPD985xx on-chip ethernet (CANDY)" );
+ // CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
+
+ i = eth_upd985xx_status( p_eth_upd985xx );
+
+ if ( !( i & PHY_STATUS_LINK) ) {
+ p->operational = 2; // LINK DOWN
+ p->duplex = 1; // UNKNOWN
+ p->speed = 0;
+ }
+ else {
+ p->operational = 3; // LINK UP
+ p->duplex = (i & PHY_STATUS_FDX) ? 3 : 2; // 2 = SIMPLEX, 3 = DUPLEX
+ p->speed = ((i & PHY_STATUS_100MBPS) ? 100 : 10) * 1000000;
+ }
+
+ // Admit to it...
+ p->supports_dot3 = true;
+
+ // Those commented out are not available on this chip.
+ p->tx_good = INL( ETH_TPCT ) ;
+ p->tx_max_collisions = INL( ETH_TXCL ) ;
+ p->tx_late_collisions = INL( ETH_TLCL ) ;
+ //p->tx_underrun = INL( ) ;
+ p->tx_carrier_loss = INL( ETH_TCSE ) ;
+ p->tx_deferred = INL( ETH_TDFR ) +
+ INL( ETH_TXDF ) ;
+ //p->tx_sqetesterrors = INL( ) ;
+ p->tx_single_collisions = INL( ETH_TSCL ) ;
+ p->tx_mult_collisions = INL( ETH_TMCL ) ;
+ p->tx_total_collisions = INL( ETH_TSCL ) +
+ INL( ETH_TMCL ) +
+ INL( ETH_TLCL ) +
+ INL( ETH_TXCL ) ;
+ p->rx_good = INL( ETH_RPKT ) ;
+ p->rx_crc_errors = INL( ETH_RFCS ) ;
+ p->rx_align_errors = INL( ETH_RALN ) ;
+ p->rx_resource_errors = p_eth_upd985xx->count_rx_resource;
+ //p->rx_overrun_errors = INL( ) ;
+ //p->rx_collisions = INL( ) ;
+ p->rx_short_frames = INL( ETH_RUND ) ;
+ p->rx_too_long_frames = INL( ETH_ROVR ) ;
+ p->rx_symbol_errors = INL( ETH_RXUO ) ;
+
+ p->interrupts = p_eth_upd985xx->count_interrupts;
+ p->rx_count = INL( ETH_RBYT ) ;
+ p->rx_deliver = INL( ETH_RPKT ) ;
+ p->rx_resource = p_eth_upd985xx->count_rx_resource;
+ p->rx_restart = p_eth_upd985xx->count_rx_resource +
+ p_eth_upd985xx->count_rx_restart;
+ p->tx_count = INL( ETH_TBYT ) ;
+ p->tx_complete = INL( ETH_TPCT ) ;
+ p->tx_dropped = INL( ETH_TNCL ) ;
+
+ p->tx_queue_len = 1;
+
+ return 0; // OK
+ }
+#endif
+
+ default:
+ break;
+ }
+ return -1;
+}
+
+// ------------------------------------------------------------------------
+
+// EOF if_upd985xx.c