OpenCores
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,
&eth_upd985xx[0], // Driver specific data
CYGDAT_DEVS_ETH_UPD985XX_ETH0_NAME, // name for this interface
eth_upd985xx_start,
eth_upd985xx_stop,
eth_upd985xx_ioctl,
eth_upd985xx_can_send,
eth_upd985xx_send,
eth_upd985xx_recv,
eth_upd985xx_deliver,
eth_upd985xx_poll,
eth_upd985xx_int_vector
);
 
NETDEVTAB_ENTRY(upd985xx_netdev0,
"upd985xx-" CYGDAT_DEVS_ETH_UPD985XX_ETH0_NAME,
upd985xx_eth_upd985xx_init,
&upd985xx_sc0);
 
 
// This is in a macro so that if more devices arrive it can easily be changed
#define CHECK_NDP_SC_LINK() CYG_MACRO_START \
CYG_ASSERT( ((void *)ndp == (void *)&upd985xx_netdev0), "Bad ndp" ); \
CYG_ASSERT( ((void *)sc == (void *)&upd985xx_sc0), "Bad sc" ); \
CYG_ASSERT( (void *)p_eth_upd985xx == sc->driver_private, \
"sc pointer bad" ); \
CYG_ASSERT( (void *)p_eth_upd985xx == (void *)&eth_upd985xx[0], \
"bad p_eth_upd985x" ); \
CYG_MACRO_END
 
#define NUM_ELEMENTS( _x_ ) (sizeof( (_x_) ) / sizeof( (_x_[0]) ) )
 
// ------------------------------------------------------------------------
//
// FUNCTION PROTOTYPES
//
// ------------------------------------------------------------------------
STATIC void InitRxRing(struct eth_upd985xx* p_eth_upd985xx);
STATIC void NextRxRing(struct eth_upd985xx* p_eth_upd985xx);
STATIC void InitTxRing(struct eth_upd985xx* p_eth_upd985xx);
STATIC void ResetTxRing(struct eth_upd985xx* p_eth_upd985xx);
 
#ifdef CYGPKG_NET
STATIC int eth_upd985xx_configure(struct eth_upd985xx* p_eth_upd985xx,
int promisc, int oversized);
#endif
 
STATIC void PacketRxReady(struct eth_upd985xx* p_eth_upd985xx);
STATIC void TxDone(struct eth_upd985xx* p_eth_upd985xx);
 
#define PHY_STATUS_LINK (1)
#define PHY_STATUS_FDX (2)
#define PHY_STATUS_100MBPS (4)
STATIC int eth_upd985xx_status( struct eth_upd985xx *p_eth_upd985xx );
STATIC int eth_set_mac_address( struct eth_upd985xx *p_eth_upd985xx, void *data );
 
// ------------------------------------------------------------------------
//
// MII ACCESS TO PHY DEVICE
//
// ------------------------------------------------------------------------
 
STATIC cyg_bool mii_read( cyg_uint32 reg, cyg_uint32 *pvalue,
struct eth_upd985xx *p_eth_upd985xx )
{
int i = 1000;
// wait a bit for it to be idle
while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
& INL(ETH_MIND)) )
if ( --i < 0 )
return false;
// Tell it the register address and PHY address
OUTL( ETH_MADR, ETH_MADR_PHY_DEVICE_PHYS_ADDRESS | reg );
OUTL( ETH_MCMD, ETH_MCMD_RSTAT ); // "do a read"
// wait for the read to complete
while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
& INL(ETH_MIND)) )
if ( --i < 0 )
return false;
// so get the data
*pvalue = INL( ETH_MRDD );
return true;
}
 
#if 0
STATIC cyg_bool mii_write( cyg_uint32 reg, cyg_uint32 value,
struct eth_upd985xx *p_eth_upd985xx )
{
int i = 1000;
// wait a bit for it to be idle
while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
& INL(ETH_MIND)) )
if ( --i < 0 )
return false;
// Tell it the register address and PHY address
OUTL( ETH_MADR, ETH_MADR_PHY_DEVICE_PHYS_ADDRESS | reg );
// And write the data:
OUTL( ETH_MWTD, value );
// wait a bit for it to be idle
while ( 0 != ((ETH_MIND_NVALID | ETH_MIND_SCANA | ETH_MIND_BUSY)
& INL(ETH_MIND)) )
if ( --i < 0 )
return false;
return true;
}
#endif
 
// ------------------------------------------------------------------------
//
// INTERRUPT HANDLERS
//
// ------------------------------------------------------------------------
 
STATIC cyg_uint32 eth_isr(cyg_vector_t vector, cyg_addrword_t data)
{
cyg_drv_interrupt_mask( vector );
 
return CYG_ISR_CALL_DSR; // schedule DSR
}
 
// ------------------------------------------------------------------------
// This is a callback from the higher level thread in consequence of the DSR
STATIC void
eth_upd985xx_deliver(struct eth_drv_sc *sc)
{
register int intrs;
struct eth_upd985xx *p_eth_upd985xx;
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
 
p_eth_upd985xx->count_interrupts++;
 
intrs = INL( ETH_ISR ); // Read-clear
// Acknowledge once at the start anyway to prevent an interrupt loop in
// case of a transient - interrupts latch in the interrupt controller
// as well as in the ethernet device.
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
 
#ifdef DEBUG_TRAFFIC
os_printf("\n[[[[[[[ Deliver intrs = %x\n", intrs );
#endif
 
// Guard possible external entry points
if ( ! p_eth_upd985xx->active )
return; // without unmasking the interrupt
 
while ( intrs ) {
if ( 0xffff0000 & intrs ) {
// Then something very bad has happened
p_eth_upd985xx->count_bad_isr_restarts++;
CYG_ASSERT ( p_eth_upd985xx->active, "Device not active!" );
eth_upd985xx_stop( sc );
eth_upd985xx_start( sc, NULL, 0 );
intrs = INL( ETH_ISR ); // Read-clear
}
p_eth_upd985xx->intrs = intrs;
if ( ( ETH_ISR_XMTDN | ETH_ISR_TABR ) & intrs ) {
// Scan for completed Txen and inform the stack
TxDone(p_eth_upd985xx);
}
if ( ( ETH_ISR_RCVDN | ETH_ISR_RBDRS | ETH_ISR_RBDRU ) & intrs ) {
// Pass any rx data up the stack
PacketRxReady(p_eth_upd985xx);
}
// Now we have made the interrupt causes go away, acknowledge and
// *then* read the ISR again. That way the race can result in a
// spurious interrupt rather than a lost interrupt.
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
intrs = INL( ETH_ISR ); // Read-clear
#ifdef DEBUG_TRAFFIC
if ( intrs )
os_printf("------- Again intrs = %x\n", intrs );
#endif
}
#ifdef DEBUG_TRAFFIC
os_printf("]]]]]]]] Done intrs = %x\n\n", intrs );
#endif
 
cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
}
 
// ------------------------------------------------------------------------
// Device table entry to operate the chip in a polled mode.
// Only diddle the interface we were asked to!
 
STATIC void
eth_upd985xx_poll(struct eth_drv_sc *sc)
{
struct eth_upd985xx *p_eth_upd985xx;
 
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
 
// As it happens, this driver always requests the DSR to be called:
(void)eth_isr( p_eth_upd985xx->vector, (cyg_addrword_t)sc );
eth_upd985xx_deliver( sc );
}
 
// ------------------------------------------------------------------------
// Determine interrupt vector used by a device - for attaching GDB stubs
// packet handler.
STATIC int
eth_upd985xx_int_vector(struct eth_drv_sc *sc)
{
struct eth_upd985xx *p_eth_upd985xx;
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
return (p_eth_upd985xx->vector);
}
 
// ------------------------------------------------------------------------
 
STATIC int
eth_set_mac_address( struct eth_upd985xx *p_eth_upd985xx, void *data )
{
cyg_uint8 *p = (cyg_uint8 *)data;
cyg_uint8 *mac_address;
 
mac_address = &p_eth_upd985xx->mac_address[0];
 
mac_address[5] = p[5];
mac_address[4] = p[4];
mac_address[3] = p[3];
mac_address[2] = p[2];
mac_address[1] = p[1];
mac_address[0] = p[0];
 
p_eth_upd985xx->mac_addr_ok = 1;
 
// Set the ESA in the device regs
OUTL( ETH_LSA2,
(p_eth_upd985xx->mac_address[1]) |
(p_eth_upd985xx->mac_address[0] << 8 ) );
OUTL( ETH_LSA1,
(p_eth_upd985xx->mac_address[5]) |
(p_eth_upd985xx->mac_address[4] << 8 ) |
(p_eth_upd985xx->mac_address[3] << 16 ) |
(p_eth_upd985xx->mac_address[2] << 24) );
 
return 0; // OK
}
 
// ------------------------------------------------------------------------
 
STATIC void
eth_upd985xx_reset( struct eth_upd985xx *p_eth_upd985xx )
{
int i;
 
// Reset whole device: Software Reset (clears automatically)
OUTL( ETH_CCR, ETH_CCR_SRT );
for ( i = 0; i < 10000; i++ ) /* nothing */;
// Reset internal units
OUTL( ETH_MACC2, ETH_MACC2_MCRST | ETH_MACC2_RFRST | ETH_MACC2_TFRST );
for ( i = 0; i < 10000; i++ ) /* nothing */;
FLUSH_WRITES();
OUTL( ETH_MACC2, 0 ); // (and release reset)
// Enable CRC adding, padding
FLUSH_WRITES();
OUTL( ETH_MACC1,
ETH_MACC1_CRCEN | ETH_MACC1_PADEN |
ETH_MACC1_TXFC | ETH_MACC1_RXFC | ETH_MACC1_PARF );
FLUSH_WRITES();
OUTL( ETH_MACC2, ETH_MACC2_APD ); // Auto VLAN pad
FLUSH_WRITES();
OUTL( ETH_HT1, 0 );
FLUSH_WRITES();
OUTL( ETH_HT2, 0 );
 
// Enable rx of broadcasts, multicasts, but not promiscuous...
FLUSH_WRITES();
#if defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2 ) && \
!defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY )
// Unless we are faking it.
OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM | ETH_AFR_PRO );
#else
OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM );
#endif
 
FLUSH_WRITES();
OUTL( ETH_IPGT, 0x00000013 );
FLUSH_WRITES();
OUTL( ETH_IPGR, 0x00000e13 );
FLUSH_WRITES();
OUTL( ETH_CLRT, 0x0000380f );
FLUSH_WRITES();
OUTL( ETH_LMAX, MAX_ETHERNET_PACKET_SIZE );
 
// Select a clock for the MII
FLUSH_WRITES();
OUTL( ETH_MIIC, ETH_MIIC_66 ); // Example code sets to 66.
// Set VLAN type reg
FLUSH_WRITES();
OUTL( ETH_VLTP, ETH_VLTP_VLTP );
 
// Set the ESA in the device regs
if ( p_eth_upd985xx->mac_addr_ok ) {
FLUSH_WRITES();
OUTL( ETH_LSA2,
(p_eth_upd985xx->mac_address[1]) |
(p_eth_upd985xx->mac_address[0] << 8 ) );
FLUSH_WRITES();
OUTL( ETH_LSA1,
(p_eth_upd985xx->mac_address[5]) |
(p_eth_upd985xx->mac_address[4] << 8 ) |
(p_eth_upd985xx->mac_address[3] << 16 ) |
(p_eth_upd985xx->mac_address[2] << 24) );
}
 
FLUSH_WRITES();
OUTL( ETH_RXFCR, ETH_RXFCR_UWM_DEFAULT |
ETH_RXFCR_LWM_DEFAULT | ETH_RXFCR_DRTH16W );
 
FLUSH_WRITES();
// Fault E4 - use only 32 for FLTH, not the previously recommended 48 (words)
// Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E4
// but no config opt is provided.
OUTL( ETH_TXFCR, ETH_TXFCR_TPTV_DEFAULT |
ETH_TXFCR_TX_DRTH_DEFAULT | (32 << ETH_TXFCR_TX_FLTH_SHIFT) );
 
// Transmit and receive config regs we hit when enabling those
// functions separately, and the wet string end of the receiver
// which is controlled by MACC1 |= ETH_MACC1_SRXEN;
 
// Tx and Rx interrupts enabled internally;
// Tx done/aborted, and rx OK.
FLUSH_WRITES();
OUTL( ETH_MSR, ETH_ISR_XMTDN | ETH_ISR_TABR |
ETH_ISR_RCVDN | ETH_ISR_RBDRS | ETH_ISR_RBDRU );
FLUSH_WRITES();
}
 
// ------------------------------------------------------------------------
//
// NETWORK INTERFACE INITIALIZATION
//
// ------------------------------------------------------------------------
STATIC bool
upd985xx_eth_upd985xx_init(struct cyg_netdevtab_entry * ndp)
{
struct eth_drv_sc *sc;
cyg_uint8 *mac_address;
struct eth_upd985xx *p_eth_upd985xx;
 
#ifdef DEBUG
db_printf("upd985xx_eth_upd985xx_init\n");
#endif
 
sc = (struct eth_drv_sc *)(ndp->device_instance);
p_eth_upd985xx = (struct eth_upd985xx *)(sc->driver_private);
 
CHECK_NDP_SC_LINK();
 
p_eth_upd985xx->tx_busy = 0;
 
// record the net dev pointer
p_eth_upd985xx->ndp = (void *)ndp;
 
mac_address = &p_eth_upd985xx->mac_address[0];
 
#ifdef CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
if ( ! p_eth_upd985xx->hardwired_esa ) {
cyg_uint8 *p;
union macar {
struct {
cyg_uint32 macar1, macar2, macar3;
} integers;
cyg_uint8 bytes[12];
} eeprom;
 
eeprom.integers.macar1 = INL( MACAR1 ); // MAC Address Register 1
eeprom.integers.macar2 = INL( MACAR2 ); // MAC Address Register 2
eeprom.integers.macar3 = INL( MACAR3 ); // MAC Address Register 3
 
if ( (0 != eeprom.integers.macar1 ||
0 != eeprom.integers.macar2 ||
0 != eeprom.integers.macar3 )
&&
(0xffffffff != eeprom.integers.macar1 ||
0xffffffff != eeprom.integers.macar2 ||
0xffffffff != eeprom.integers.macar3 ) ) {
// Then we have good data in the EEPROM
#ifdef DEBUG
os_printf( "EEPROM data %08x %08x %08x\n",
eeprom.integers.macar1,
eeprom.integers.macar2,
eeprom.integers.macar3 );
#endif
p = &eeprom.bytes[0]; // pick up either set of ESA info
if ( 1 == p_eth_upd985xx->index )
p += 6;
 
mac_address[5] = p[5];
mac_address[4] = p[4];
mac_address[3] = p[3];
mac_address[2] = p[2];
mac_address[1] = p[1];
mac_address[0] = p[0];
p_eth_upd985xx->mac_addr_ok = 1;
}
else {
// Fake it so we can get RedBoot going on a board with no EEPROM
mac_address[0] = 0;
mac_address[1] = 0xBA;
mac_address[2] = 0xD0;
mac_address[3] = 0xEE;
mac_address[4] = 0x00;
mac_address[5] = p_eth_upd985xx->index;
p_eth_upd985xx->mac_addr_ok = 1;
}
}
#endif // CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
// Init the underlying hardware and insert the ESA:
eth_upd985xx_reset(p_eth_upd985xx);
 
#ifdef DEBUG
os_printf("MAC Address %s, ESA = %02X %02X %02X %02X %02X %02X\n",
p_eth_upd985xx->mac_addr_ok ? "OK" : "**BAD**",
mac_address[0], mac_address[1], mac_address[2], mac_address[3],
mac_address[4], mac_address[5]);
#endif
 
// Set up the pointers to data structures
InitTxRing(p_eth_upd985xx);
 
// Construct the interrupt handler
p_eth_upd985xx->active = 0;
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
cyg_drv_interrupt_mask(p_eth_upd985xx->vector);
cyg_drv_interrupt_create(
p_eth_upd985xx->vector,
0, // Priority - unused
(CYG_ADDRWORD)sc, // Data item passed to ISR & DSR
eth_isr, // ISR
eth_drv_dsr, // DSR (generic)
&p_eth_upd985xx->interrupt_handle, // handle to intr obj
&p_eth_upd985xx->interrupt_object ); // space for int obj
 
cyg_drv_interrupt_attach(p_eth_upd985xx->interrupt_handle);
 
// Initialize upper level driver
if ( p_eth_upd985xx->mac_addr_ok )
(sc->funs->eth_drv->init)(sc, &(p_eth_upd985xx->mac_address[0]) );
else
(sc->funs->eth_drv->init)(sc, 0 );
return (1);
}
 
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_start
//
// ------------------------------------------------------------------------
STATIC void
eth_upd985xx_start( struct eth_drv_sc *sc,
unsigned char *enaddr, int flags )
{
struct eth_upd985xx *p_eth_upd985xx;
cyg_uint32 ss;
#ifdef CYGPKG_NET
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif
 
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
 
#ifdef DEBUG
os_printf("eth_upd985xx_start %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );
#endif
 
if ( p_eth_upd985xx->active )
eth_upd985xx_stop( sc );
 
p_eth_upd985xx->active = 1;
#ifdef CYGPKG_NET
/* Enable promiscuous mode if requested, reception of oversized frames always.
* The latter is needed for VLAN support and shouldn't hurt even if we're not
* using VLANs.
*/
eth_upd985xx_configure(p_eth_upd985xx, !!(ifp->if_flags & IFF_PROMISC), 1);
#endif
 
// renegotiate link status
p_eth_upd985xx->phy_status = eth_upd985xx_status( p_eth_upd985xx );
 
if ( p_eth_upd985xx->phy_status & PHY_STATUS_FDX ) {
cyg_uint32 ss;
// then enable full duplex in the MAC
ss = INL( ETH_MACC1 );
ss |= ETH_MACC1_FDX;
OUTL( ETH_MACC1, ss );
}
 
#ifdef DEBUG
{
int status = p_eth_upd985xx->phy_status;
os_printf("eth_upd985xx_start %d Link = %s, %s Mbps, %s Duplex\n",
p_eth_upd985xx->index,
status & PHY_STATUS_LINK ? "Up" : "Down",
status & PHY_STATUS_100MBPS ? "100" : "10",
status & PHY_STATUS_FDX ? "Full" : "Half"
);
}
#endif
 
 
// Start the receive engine
p_eth_upd985xx->count_rx_restart++;
// Initialize all but one buffer: [B0,B1,B2,...Bx,NULL,LINK]
InitRxRing( p_eth_upd985xx );
// Point the hardware at the list of buffers
OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );
// Tell it about the buffers via the rx descriptor count
OUTL( ETH_RXPDR, ETH_RXPDR_AL | (NUM_RXBUFS-1) );
// Ack any pending interrupts from the system
p_eth_upd985xx->intrs = INL( ETH_ISR ); // Read-clear
// Start the rx.
OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );
 
// Enable the wet string end of the receiver
ss = INL( ETH_MACC1 );
ss |= ETH_MACC1_SRXEN;
OUTL( ETH_MACC1, ss );
 
// And unmask the interrupt
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
}
 
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_status; 10/100 and Full/Half Duplex (FDX/HDX)
//
// ------------------------------------------------------------------------
STATIC int eth_upd985xx_status( struct eth_upd985xx *p_eth_upd985xx )
{
int status;
int i, j;
// Some of these bits latch and only reflect "the truth" on a 2nd reading.
// So read and discard.
mii_read( PHY_CONTROL_REG, &i, p_eth_upd985xx );
mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx );
// Use the "and" of the local and remote capabilities words to infer
// what is selected:
status = 0;
if ( mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx ) ) {
if ( PHY_STATUS_LINK_OK & i )
status |= PHY_STATUS_LINK;
}
if ( mii_read( PHY_AUTONEG_ADVERT, &j, p_eth_upd985xx ) &&
mii_read( PHY_AUTONEG_REMOTE, &i, p_eth_upd985xx ) ) {
#if defined( DEBUG_TRAFFIC ) || defined( DEBUG_IOCTL )
os_printf( "MII: capabilities are %04x, %04x; common %04x\n",
i, j, i & j );
#endif
j &= i; // select only common capabilities
 
if ( (PHY_AUTONEG_100BASET4 |
PHY_AUTONEG_100BASETX_FDX |
PHY_AUTONEG_100BASETX_HDX) & j )
status |= PHY_STATUS_100MBPS;
if ( (PHY_AUTONEG_100BASETX_FDX | PHY_AUTONEG_10BASET_FDX) & j )
status |= PHY_STATUS_FDX;
}
return status;
}
 
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_stop
//
// ------------------------------------------------------------------------
 
STATIC void eth_upd985xx_stop( struct eth_drv_sc *sc )
{
struct eth_upd985xx *p_eth_upd985xx;
 
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
 
// No more interrupts
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
cyg_drv_interrupt_mask(p_eth_upd985xx->vector);
 
#ifdef DEBUG
os_printf("eth_upd985xx_stop %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );
#endif
 
p_eth_upd985xx->active = 0; // stop people tormenting it
 
if ( p_eth_upd985xx->tx_busy ) {
// Then it is finshed now, by force:
cyg_uint32 key = p_eth_upd985xx->tx_keys[ 0 ];
// Turn off the transmitter (before the callback to the stack).
OUTL( ETH_TXCR, 0 );
#ifdef DEBUG_TRAFFIC
os_printf("Stop: tidying up TX, KEY %x\n", key );
#endif
// Leave tx_busy true so no recursion can occur here.
// Then tell the stack we are done:
if ( key ) {
(sc->funs->eth_drv->tx_done)( sc, key, 0 );
}
}
p_eth_upd985xx->tx_keys[ 0 ] = 0;
p_eth_upd985xx->tx_busy = p_eth_upd985xx->active = 0;
 
eth_upd985xx_reset(p_eth_upd985xx);
 
ResetTxRing( p_eth_upd985xx );
}
 
 
// ------------------------------------------------------------------------
//
// Function : InitRxRing
//
// ------------------------------------------------------------------------
STATIC void InitRxRing(struct eth_upd985xx* p_eth_upd985xx)
{
int i;
struct bufdesc *bp;
 
// first just blat the various flags and addresses: the first N
// bufdescs point to data buffers, the last one is NULL.
bp = (struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[0] );
// Record the initial active buffer:
p_eth_upd985xx->rxring_active = bp;
p_eth_upd985xx->rxring_active_index = 0;
for ( i = 0; i < NUM_RXBUFS - 1; i++, bp++ ) {
bp->ptr = VIRT_TO_BUS( &rx_databuf[i][0] );
bp->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU
| (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );
}
CYG_ASSERT( i == NUM_RXBUFS-1, "Penultimate rx buffer index mismatch" );
CYG_ASSERT( (cyg_uint8 *)bp ==
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS-1] ),
"Penultimate rx buffer address mismatch" );
 
// NULL out the penultimate one
bp->ptr = NULL;
bp->attr = 0;
// And record it as next one to use
p_eth_upd985xx->rxring_next = bp;
p_eth_upd985xx->rxring_next_index = NUM_RXBUFS-1;
 
// Step on to the extra entry at the end which makes a ring:
bp++;
CYG_ASSERT( (cyg_uint8 *)bp ==
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS] ),
"Ultimate rx buffer address mismatch" );
 
// Link the Ultimate back to the start
bp->ptr = (cyg_uint8 *)p_eth_upd985xx->rxring_active; // Zeroth entry
bp->attr = ETH_BUF_D_L_LINK;
 
// All done.
}
 
 
// ------------------------------------------------------------------------
//
// Function : NextRxRing
//
// ------------------------------------------------------------------------
 
STATIC void NextRxRing(struct eth_upd985xx* p_eth_upd985xx )
{
volatile struct bufdesc *next, *dead;
int iactive;
int inext;
 
iactive = p_eth_upd985xx->rxring_active_index;
inext = p_eth_upd985xx->rxring_next_index;
 
// Preconditions:
CYG_ASSERT( 0 <= inext && inext < NUM_RXBUFS, "Bad inext" );
CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );
CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );
CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );
CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );
CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==
p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );
CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),
"Chasing pointers mismatch" );
 
// Select the new bufdesc to be active - ie. next to scan for reception:
if ( ++iactive >= NUM_RXBUFS )
iactive = 0;
dead = p_eth_upd985xx->rxring_active; // the one that just died
// Step ahead the new active buffer:
p_eth_upd985xx->rxring_active = (volatile struct bufdesc *)
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] );
p_eth_upd985xx->rxring_active_index = iactive;
 
// Blow away the currently active entry; we have dealt with it already
// and it is needed for an end stop to the ring:
dead->ptr = NULL;
dead->attr = 0;
// Select the next bufdesc to enliven
next = p_eth_upd985xx->rxring_next;
next->ptr = VIRT_TO_BUS( &rx_databuf[inext][0] );
next->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU
| (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );
 
// And update the external info to reflect this:
if ( ++inext >= NUM_RXBUFS )
inext = 0;
next = (volatile struct bufdesc *)
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] );
 
p_eth_upd985xx->rxring_next = next;
p_eth_upd985xx->rxring_next_index = inext;
 
// Postconditions:
CYG_ASSERT( 0 <= inext && inext < NUM_RXBUFS, "Bad inext" );
CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );
CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );
CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );
CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );
CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==
p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );
CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),
"Chasing pointers mismatch" );
}
 
// ------------------------------------------------------------------------
//
// Function : PacketRxReady (Called from delivery thread)
//
// ------------------------------------------------------------------------
STATIC void PacketRxReady(struct eth_upd985xx* p_eth_upd985xx)
{
struct cyg_netdevtab_entry *ndp;
struct eth_drv_sc *sc;
cyg_uint32 ss, length;
cyg_bool reset_required = 0;
 
ndp = (struct cyg_netdevtab_entry *)(p_eth_upd985xx->ndp);
sc = (struct eth_drv_sc *)(ndp->device_instance);
 
CHECK_NDP_SC_LINK();
 
#ifdef DEBUG_TRAFFIC
ss = INL( ETH_RXSR );
os_printf("PacketRxReady: RXSR %x\n", ss );
#endif
 
if ( ETH_ISR_RBDRU & p_eth_upd985xx->intrs )
reset_required = 1; // Out of buffers
if ( ! ETH_ISR_RCVDN & p_eth_upd985xx->intrs )
reset_required = 1; // or if no reception completed, reset anyway
 
// For all ready rx blocks...
do {
volatile struct bufdesc *bp;
 
bp = p_eth_upd985xx->rxring_active; // Current rx candidate
 
ss = bp->attr;
#ifdef DEBUG_TRAFFIC
os_printf("PacketRxReady attr %x at %x\n", ss, bp );
#endif
if ( ETH_BUF_OWN_CPU == (ETH_BUF_OWN & ss) ) {
// Then the packet is untouched...
break;
}
#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2
// Perform address recognition by hand, hardware is in promisc mode
// (we have settable "software" promisc mode too of course)
if ( ETH_BUF_OK & ss ) {
cyg_uint8 *esa = (cyg_uint8 *)bp->ptr; // (this is a non-cachable address)
int ok = 0;
if ( p_eth_upd985xx->promisc )
ok = 1; // accept the packet
else
if ( p_eth_upd985xx->mac_address[0] == esa[0] &&
p_eth_upd985xx->mac_address[1] == esa[1] &&
p_eth_upd985xx->mac_address[2] == esa[2] &&
p_eth_upd985xx->mac_address[3] == esa[3] &&
p_eth_upd985xx->mac_address[4] == esa[4] &&
p_eth_upd985xx->mac_address[5] == esa[5] )
ok = 1; // Then they are equal - accept
else
if ( 0xff == esa[0] &&
0xff == esa[1] &&
0xff == esa[2] &&
0xff == esa[3] &&
0xff == esa[4] &&
0xff == esa[5] )
ok = 1; // Then they are equal - accept
 
if ( !ok )
ss = 0; // Easiest way...
}
#endif
if ( ETH_BUF_OK & ss ) {
length = ETH_BUF_SIZE & ss;
#ifdef DEBUG_TRAFFIC
os_printf("PacketRxReady found a packet size %d attr %x\n", length, ss );
#endif
// Asserts for the length in-range can fire, with good status
// in the block, so be defensive here instead. Belt and braces.
if ( 63 < length && length <= MAX_RX_PACKET_SIZE ) {
CYG_ASSERT( ETH_BUF_D_L_DATA == (ETH_BUF_D_L & ss), "Not data buffer" );
CYG_ASSERT( length > 63, "Tiny packet" );
CYG_ASSERT( length <= MAX_RX_PACKET_SIZE, "Too big packet" );
CYG_ASSERT( ETH_BUF_LAST & ss, "Not last buffer" );
(sc->funs->eth_drv->recv)( sc, length );
} // Else drop it on the floor.
}
 
// Step along to the next buffer descriptor...
NextRxRing( p_eth_upd985xx );
if ( ! reset_required ) {
// And tell the device it can have a biscuit:
OUTL( ETH_RXPDR, ETH_RXPDR_AL | 1 );
 
// Now, before moving on to the next packet, find out if receptions
// had caught up with us before adding that new buffer:
ss = INL( ETH_RXPDR );
ss &= ETH_RXPDR_RNOD;
ss >>= ETH_RXPDR_RNOD_SHIFT;
if ( 1 >= ss ) {
// Then it was zero before. So the rx engine is stopped.
#ifdef DEBUG_TRAFFIC
os_printf( "***ZERO rx buffers were left\n" );
#endif
reset_required = 1;
}
// Otherwise we carry on as usual.
}
} while ( 1 );
 
if ( reset_required ) {
p_eth_upd985xx->count_rx_resource++;
// Disable the wet string end of the receiver
ss = INL( ETH_MACC1 );
ss &=~ETH_MACC1_SRXEN;
OUTL( ETH_MACC1, ss );
// Disable the DMA engine
OUTL( ETH_RXCR, 0 );
// Reset the RxRing from scratch
InitRxRing( p_eth_upd985xx );
// Point the hardware at the list of buffers
OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );
// Tell it about the buffers via the rx descriptor count:
ss = INL( ETH_RXPDR );
ss &= ETH_RXPDR_RNOD;
ss >>= ETH_RXPDR_RNOD_SHIFT;
// This awful register *increments* by what you write, even if the
// machinery is halted. Vile filthy evil rubbish.
OUTL( ETH_RXPDR, ETH_RXPDR_AL | ((NUM_RXBUFS-1) - ss) );
ss = INL( ETH_RXPDR );
CYG_ASSERT( (ETH_RXPDR_AL | (NUM_RXBUFS-1)) == ss, "RXPDR not right" );
// Start the rx.
OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );
// Enable the wet string end of the receiver
ss = INL( ETH_MACC1 );
ss |= ETH_MACC1_SRXEN;
OUTL( ETH_MACC1, ss );
// All done.
#ifdef DEBUG_TRAFFIC
os_printf( "***Rx Machine restarted\n" );
#endif
}
}
 
// and the callback function
 
STATIC void
eth_upd985xx_recv( struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list, int sg_len )
{
struct eth_upd985xx *p_eth_upd985xx;
int total_len;
struct eth_drv_sg *last_sg;
cyg_uint8 *from_p;
volatile struct bufdesc *bp;
 
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
// Guard possible external entry points
if ( ! p_eth_upd985xx->active )
return;
 
bp = p_eth_upd985xx->rxring_active; // Current rx candidate
 
#ifdef DEBUG_TRAFFIC
os_printf("Rx status %x\n", bp->attr );
#endif
 
if ( 0 == (ETH_BUF_OK & bp->attr) )
return;
total_len = ETH_BUF_SIZE & bp->attr;
#ifdef DEBUG_TRAFFIC
os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n",
p_eth_upd985xx->index, (int)p_eth_upd985xx,
bp->attr,
sg_len, total_len);
#endif
 
// Copy the data to the network stack
from_p = bp->ptr; // (this is a non-cachable address)
 
// check we have memory to copy into; we would be called even if
// caller was out of memory in order to maintain our state.
if ( 0 == sg_len || 0 == sg_list )
return; // caller was out of mbufs
 
CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );
 
for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
cyg_uint8 *to_p;
int l;
to_p = (cyg_uint8 *)(sg_list->buf);
l = sg_list->len;
 
CYG_ASSERT( 0 <= l, "sg length -ve" );
 
if ( 0 >= l || 0 == to_p )
return; // caller was out of mbufs
 
if ( l > total_len )
l = total_len;
 
memcpy( to_p, from_p, l );
from_p += l;
total_len -= l;
}
 
CYG_ASSERT( 0 == total_len, "total_len mismatch in rx" );
CYG_ASSERT( last_sg == sg_list, "sg count mismatch in rx" );
CYG_ASSERT( bp->ptr < from_p, "from_p wild in rx" );
CYG_ASSERT( bp->ptr + MAX_RX_PACKET_SIZE >= from_p,
"from_p overflow in rx" );
}
 
 
// ------------------------------------------------------------------------
//
// Function : InitTxRing
//
// ------------------------------------------------------------------------
STATIC void InitTxRing(struct eth_upd985xx* p_eth_upd985xx)
{
int i;
volatile struct bufdesc *bp;
p_eth_upd985xx->txring =
(struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->tx_bufdesc[0] );
 
bp = p_eth_upd985xx->txring;
 
for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ); i++, bp++ ) {
bp->ptr = NULL;
bp->attr = 0;
}
// Last one is a NULL link
bp--;
bp->ptr = NULL;
bp->attr = ETH_BUF_D_L_LINK;
 
ResetTxRing(p_eth_upd985xx);
}
 
// ------------------------------------------------------------------------
//
// Function : ResetTxRing
//
// ------------------------------------------------------------------------
STATIC void ResetTxRing(struct eth_upd985xx* p_eth_upd985xx)
{
int i;
volatile struct bufdesc *bp;
bp = p_eth_upd985xx->txring;
for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ) - 1; i++, bp++ ) {
bp->attr =
ETH_BUF_LAST |
ETH_BUF_D_L_DATA |
ETH_BUF_OWN_CPU |
(ETH_BUF_SIZE & 0);
}
}
 
// ------------------------------------------------------------------------
//
// Function : TxDone (Called from delivery thread)
//
// This returns Tx's from the Tx Machine to the stack (ie. reports
// completion) - allowing for missed interrupts, and so on.
// ------------------------------------------------------------------------
 
STATIC void TxDone(struct eth_upd985xx* p_eth_upd985xx)
{
struct cyg_netdevtab_entry *ndp;
struct eth_drv_sc *sc;
 
ndp = (struct cyg_netdevtab_entry *)(p_eth_upd985xx->ndp);
sc = (struct eth_drv_sc *)(ndp->device_instance);
 
CHECK_NDP_SC_LINK();
 
if ( p_eth_upd985xx->tx_busy ) {
cyg_uint32 ss;
 
ss = INL( ETH_TXSR ); // Get tx status
if ( ss & (ETH_TXSR_CSE |
ETH_TXSR_TUDR |
ETH_TXSR_TGNT |
ETH_TXSR_LCOL |
ETH_TXSR_ECOL |
ETH_TXSR_TEDFR |
ETH_TXSR_TDFR |
ETH_TXSR_TBRO |
ETH_TXSR_TMUL |
ETH_TXSR_TDONE ) ) {
// Then it finished; somehow...
cyg_uint32 key = p_eth_upd985xx->tx_keys[ 0 ];
// Turn off the transmitter (before the callback to the stack).
OUTL( ETH_TXCR, 0 );
 
#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E8
// Must take action after certain types of tx failure:
if ( ss & (ETH_TXSR_TUDR |
ETH_TXSR_LCOL |
ETH_TXSR_ECOL) ) {
p_eth_upd985xx->count_bad_tx_completion++;
CYG_ASSERT ( p_eth_upd985xx->active, "Device not active!" );
eth_upd985xx_stop( sc );
eth_upd985xx_start( sc, NULL, 0 );
key = 0; // Important! Stop above already fed it back.
}
#endif
 
#ifdef DEBUG_TRAFFIC
os_printf("TxDone %d %x: KEY %x\n",
p_eth_upd985xx->index, (int)p_eth_upd985xx, key );
#endif
// Finished, ready for the next one
p_eth_upd985xx->tx_keys[ 0 ] = 0;
p_eth_upd985xx->tx_busy = 0;
// Then tell the stack we are done:
if (key) {
(sc->funs->eth_drv->tx_done)( sc, key,
0 == (p_eth_upd985xx->intrs & ETH_ISR_TABR) );
}
}
}
}
 
 
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_can_send
//
// ------------------------------------------------------------------------
 
STATIC int
eth_upd985xx_can_send(struct eth_drv_sc *sc)
{
struct eth_upd985xx *p_eth_upd985xx;
 
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
 
// Guard possible external entry points
if ( ! p_eth_upd985xx->active )
return 0;
 
return ! p_eth_upd985xx->tx_busy;
}
 
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_send
//
// ------------------------------------------------------------------------
 
STATIC void
eth_upd985xx_send(struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list, int sg_len, int total_len,
unsigned long key)
{
struct eth_upd985xx *p_eth_upd985xx;
struct eth_drv_sg *last_sg;
volatile struct bufdesc *bp;
#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3
struct eth_drv_sg local_sg[2];
#endif
 
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
 
#ifdef DEBUG_TRAFFIC
os_printf("Tx %d %x: %d sg's, %d bytes, KEY %x\n",
p_eth_upd985xx->index, (int)p_eth_upd985xx, sg_len, total_len, key );
#endif
 
if ( ! p_eth_upd985xx->active )
return; // device inactive, no return
CYG_ASSERT( ! p_eth_upd985xx->tx_busy, "Can't send when busy!" );
 
p_eth_upd985xx->tx_busy++;
 
p_eth_upd985xx->tx_keys[0] = key;
bp = &p_eth_upd985xx->txring[0]; // Current free tx
CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );
 
#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3
// We must copy any Tx that is more than two SGs into just one buffer.
if ( sg_len > 2 ) {
cyg_uint8 *from_p, *to_p;
to_p = &tx_databuf[0]; // normal cached address
if ( sizeof( tx_databuf ) < total_len )
total_len = sizeof( tx_databuf );
for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
int l;
 
from_p = (cyg_uint8 *)(sg_list->buf); // normal cached address
l = sg_list->len;
if ( l > total_len )
l = total_len;
 
memcpy( to_p, from_p, l ); // All in cached memory
to_p += l;
total_len -= l;
 
if ( 0 > total_len )
break; // Should exit via sg_last normally
}
 
// Set up SGs describing the single tx buffer
total_len = to_p - &tx_databuf[0];
local_sg[0].buf = (CYG_ADDRESS)&tx_databuf[0];
local_sg[0].len = (CYG_ADDRWORD)total_len;
local_sg[1].buf = (CYG_ADDRESS)0;
local_sg[1].len = (CYG_ADDRWORD)0;
 
// And make the subsequent code use it.
sg_len = 1;
sg_list = &local_sg[0];
}
#endif
 
for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
cyg_uint8 *from_p;
int l;
from_p = (cyg_uint8 *)(sg_list->buf); // normal cached address
l = sg_list->len;
 
if ( l > total_len )
l = total_len;
 
// Ensure the mbuf contents really is in RAM where DMA can see it.
// (Must round to cache lines apparantly for 4120)
HAL_DCACHE_STORE( ((CYG_ADDRESS)from_p) &~(HAL_DCACHE_LINE_SIZE-1),
l + HAL_DCACHE_LINE_SIZE );
bp->ptr = VIRT_TO_BUS( from_p ); // uncached real RAM address
bp->attr &=~(ETH_BUF_LAST | ETH_BUF_SIZE);
bp->attr |= ETH_BUF_SIZE & l;
bp->attr |= ETH_BUF_D_L_DATA;
 
total_len -= l;
bp++;
 
if ( 0 > total_len )
break; // Should exit via sg_last normally
}
 
CYG_ASSERT( bp > &p_eth_upd985xx->txring[0], "bp underflow" );
CYG_ASSERT( bp < &p_eth_upd985xx->txring[
NUM_ELEMENTS(p_eth_upd985xx->tx_bufdesc)
], "bp underflow" );
 
bp--;
bp->attr |= ETH_BUF_LAST;
 
// Make the rest be null links
for ( bp++; bp <
&p_eth_upd985xx->txring[NUM_ELEMENTS(p_eth_upd985xx->tx_bufdesc)];
bp++ ) {
bp->attr = ETH_BUF_D_L_LINK;
bp->ptr = NULL;
}
 
CYG_ASSERT( 0 == total_len, "length mismatch in tx" );
CYG_ASSERT( last_sg == sg_list, "sg count mismatch in tx" );
 
// And start off the tx system
 
// Point the hardware at the list of buffers
OUTL( ETH_TXDPR, (cyg_uint32)p_eth_upd985xx->txring );
// and start the tx.
 
// Fault E4 - use only 8 for DTBS, not the previously recommended 16.
// Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E4
// but no config opt is provided.
 
// Fault E7: ETH_TXCR_AFCE must not be used.
// Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E7
// but no config opt is provided.
 
OUTL( ETH_TXCR, ETH_TXCR_TXE | ETH_TXCR_DTBS_8 /* | ETH_TXCR_AFCE */ );
}
 
#ifdef CYGPKG_NET
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_configure
//
// Return : 0 = It worked.
// non0 = It failed.
// ------------------------------------------------------------------------
 
STATIC int
eth_upd985xx_configure(struct eth_upd985xx* p_eth_upd985xx, int promisc, int oversized)
{
int ss;
 
// We implement permission of oversize packets by changing LMAX (rather
// than enabling HUGEN in ETH_MACC1) because we rely on only one
// reception per rx descriptor. General oversize packets could eat
// many rx descriptors and we would become ...confused.
 
// Sanity check the numbers we're about to use.
CYG_ASSERT( sizeof( rx_databuf[0] ) >= MAX_OVERSIZE_PACKET_SIZE,
"Oversize packet would overflow rx buffer" );
CYG_ASSERT( sizeof( rx_databuf[0] ) >= MAX_ETHERNET_PACKET_SIZE,
"Ethernet packet would overflow rx buffer" );
if ( oversized )
OUTL( ETH_LMAX, MAX_OVERSIZE_PACKET_SIZE );
else
OUTL( ETH_LMAX, MAX_ETHERNET_PACKET_SIZE );
 
#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2
ss = promisc ? 1 : 0; // avoid unused var warning
p_eth_upd985xx->promisc = ss;
#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY
// Then we must also set the mode in the chip
ss = INL( ETH_AFR );
if ( promisc )
ss |= ETH_AFR_PRO;
else
ss &=~ETH_AFR_PRO;
OUTL( ETH_AFR, ss );
#endif // CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY
#else
ss = INL( ETH_AFR );
if ( promisc )
ss |= ETH_AFR_PRO;
else
ss &=~ETH_AFR_PRO;
OUTL( ETH_AFR, ss );
#endif
return 0; // OK
}
#endif
 
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_ioctl
//
// ------------------------------------------------------------------------
STATIC int
eth_upd985xx_ioctl(struct eth_drv_sc *sc, unsigned long key,
void *data, int data_length)
{
struct eth_upd985xx *p_eth_upd985xx;
 
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
 
#ifdef DEBUG_IOCTL
db_printf( "eth_upd985xx_ioctl: device eth%d at %x; key is 0x%x, data at %x[%d]\n",
p_eth_upd985xx->index, p_eth_upd985xx, key, data, data_length );
#endif
 
// DO NOT guard possible external entry points - want to be able eg. to
// set a mac address of a down interface before bringing it up!
 
switch ( key ) {
 
#ifdef ETH_DRV_SET_MAC_ADDRESS
case ETH_DRV_SET_MAC_ADDRESS:
if ( 6 != data_length )
return -2;
return eth_set_mac_address( p_eth_upd985xx, data );
#endif
 
#ifdef ETH_DRV_GET_IF_STATS_UD
case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
#endif
// drop through
#ifdef ETH_DRV_GET_IF_STATS
case ETH_DRV_GET_IF_STATS:
#endif
#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
{
struct ether_drv_stats *p = (struct ether_drv_stats *)data;
int i;
 
// Chipset entry is no longer supported; RFC1573.
for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
p->snmp_chipset[i] = 0;
 
// This perhaps should be a config opt, so you can make up your own
// description, or supply it from the instantiation.
strcpy( p->description, "NEC uPD985xx on-chip ethernet (CANDY)" );
// CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
 
i = eth_upd985xx_status( p_eth_upd985xx );
 
if ( !( i & PHY_STATUS_LINK) ) {
p->operational = 2; // LINK DOWN
p->duplex = 1; // UNKNOWN
p->speed = 0;
}
else {
p->operational = 3; // LINK UP
p->duplex = (i & PHY_STATUS_FDX) ? 3 : 2; // 2 = SIMPLEX, 3 = DUPLEX
p->speed = ((i & PHY_STATUS_100MBPS) ? 100 : 10) * 1000000;
}
 
// Admit to it...
p->supports_dot3 = true;
 
// Those commented out are not available on this chip.
p->tx_good = INL( ETH_TPCT ) ;
p->tx_max_collisions = INL( ETH_TXCL ) ;
p->tx_late_collisions = INL( ETH_TLCL ) ;
//p->tx_underrun = INL( ) ;
p->tx_carrier_loss = INL( ETH_TCSE ) ;
p->tx_deferred = INL( ETH_TDFR ) +
INL( ETH_TXDF ) ;
//p->tx_sqetesterrors = INL( ) ;
p->tx_single_collisions = INL( ETH_TSCL ) ;
p->tx_mult_collisions = INL( ETH_TMCL ) ;
p->tx_total_collisions = INL( ETH_TSCL ) +
INL( ETH_TMCL ) +
INL( ETH_TLCL ) +
INL( ETH_TXCL ) ;
p->rx_good = INL( ETH_RPKT ) ;
p->rx_crc_errors = INL( ETH_RFCS ) ;
p->rx_align_errors = INL( ETH_RALN ) ;
p->rx_resource_errors = p_eth_upd985xx->count_rx_resource;
//p->rx_overrun_errors = INL( ) ;
//p->rx_collisions = INL( ) ;
p->rx_short_frames = INL( ETH_RUND ) ;
p->rx_too_long_frames = INL( ETH_ROVR ) ;
p->rx_symbol_errors = INL( ETH_RXUO ) ;
 
p->interrupts = p_eth_upd985xx->count_interrupts;
p->rx_count = INL( ETH_RBYT ) ;
p->rx_deliver = INL( ETH_RPKT ) ;
p->rx_resource = p_eth_upd985xx->count_rx_resource;
p->rx_restart = p_eth_upd985xx->count_rx_resource +
p_eth_upd985xx->count_rx_restart;
p->tx_count = INL( ETH_TBYT ) ;
p->tx_complete = INL( ETH_TPCT ) ;
p->tx_dropped = INL( ETH_TNCL ) ;
p->tx_queue_len = 1;
return 0; // OK
}
#endif
 
default:
break;
}
return -1;
}
 
// ------------------------------------------------------------------------
 
// EOF if_upd985xx.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.