URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/ecos-2.0/packages/devs/eth/mips/upd985xx/v2_0
- from Rev 1254 to Rev 1765
- ↔ Reverse comparison
Rev 1254 → Rev 1765
/cdl/upd985xx_eth_drivers.cdl
0,0 → 1,205
# ==================================================================== |
# |
# 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 Red Hat, 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., |
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
## |
## This exception does not invalidate any other reasons why a work based on |
## this file might be covered by the GNU General Public License. |
## |
## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
## at http://sources.redhat.com/ecos/ecos-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 |
/include/upd985xx_eth.h
0,0 → 1,465
#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 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-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 |
/ChangeLog
0,0 → 1,265
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. |
|
//=========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//=========================================================================== |
/src/if_upd985xx.c
0,0 → 1,1621
//========================================================================== |
// |
// 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 Red Hat, 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., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####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, |
ð_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 *)ð_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 |