Mercurial > flash_v2
changeset 1363:70b10f2956d8
Driver for Realtek 8139
| author | gthomas |
|---|---|
| date | Thu, 13 Nov 2003 13:39:07 +0000 |
| parents | 72507a6fc4c5 |
| children | 19f40f995cc2 |
| files | packages/ChangeLog packages/devs/eth/i386/pc/rltk8139/current/ChangeLog packages/devs/eth/i386/pc/rltk8139/current/cdl/i386_pc_rltk8139_eth_drivers.cdl packages/devs/eth/i386/pc/rltk8139/current/include/devs_eth_i386_pc_rltk8139.inl packages/devs/eth/rltk/8139/current/ChangeLog packages/devs/eth/rltk/8139/current/cdl/rltk_8139_eth_drivers.cdl packages/devs/eth/rltk/8139/current/doc/README packages/devs/eth/rltk/8139/current/src/if_8139.c packages/devs/eth/rltk/8139/current/src/if_8139.h packages/ecos.db |
| diffstat | 10 files changed, 2333 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/ChangeLog +++ b/packages/ChangeLog @@ -74,6 +74,10 @@ 2003-07-23 Chris Garry <cgarry@sweeney CYGPKG_DEVS_FLASH_ARM_E7T. Updated e7t target to include FLASH drivers. +2003-07-09 Eric Doenges <Eric.Doenges@DynaPel.com> + + * ecos.db: Add Realtek 8139 (PCI) ethernet driver. + 2003-06-12 John Dallaway <jld@ecoscentric.com> * ecosadmin.tcl: Add repository merge capability (undocumented and
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/i386/pc/rltk8139/current/ChangeLog @@ -0,0 +1,40 @@ +2003-07-09 Eric Doenges <Eric.Doenges@DynaPel.com> + + * include/devs_eth_i386_pc_rltk8139.inl: + * cdl/i386_pc_rltk8139_eth_drivers.cdl: + New package - RTL8139 PCI ethernet card driver + +//=========================================================================== +//####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#### +//===========================================================================
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/i386/pc/rltk8139/current/cdl/i386_pc_rltk8139_eth_drivers.cdl @@ -0,0 +1,92 @@ +# ==================================================================== +# +# i386_pc_rltk8139_eth_drivers.cdl +# +# Ethernet drivers - support for RealTek 8139 ethernet controller +# on i386 PC target +# +# ==================================================================== +#####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): Eric Doenges +# Contributors: +# Date: 2003-07-16 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_ETH_I386_PC_RLTK8139 { + display "PC RealTek 8139 ethernet driver" + description "Ethernet driver for standard PC's." + + parent CYGPKG_IO_ETH_DRIVERS + active_if CYGPKG_IO_ETH_DRIVERS + active_if CYGPKG_HAL_I386_PC + + include_dir cyg/io + + # FIXME: This really belongs in the RealTek_8139 package ? + cdl_interface CYGINT_DEVS_ETH_RLTK_8139_REQUIRED { + display "RealTek 8139 ethernet driver required" + } + + define_proc { + puts $::cdl_system_header "/***** ethernet driver proc output start *****/" + puts $::cdl_system_header "#define CYGDAT_DEVS_ETH_RLTK_8139_INL <cyg/io/devs_eth_i386_pc_rltk8139.inl>" + puts $::cdl_system_header "#define CYGDAT_DEVS_ETH_RLTK_8139_CFG <pkgconf/devs_eth_i386_pc_rltk8139.h>" + puts $::cdl_system_header "/***** ethernet driver proc output end *****/" + } + + cdl_component CYGPKG_DEVS_ETH_I386_PC_RLTK8139_ETH0 { + display "Ethernet port 0 driver" + flavor bool + default_value 1 + + implements CYGHWR_NET_DRIVERS + implements CYGHWR_NET_DRIVER_ETH0 + implements CYGINT_DEVS_ETH_RLTK_8139_REQUIRED + + cdl_option CYGDAT_DEVS_ETH_I386_PC_RLTK8139_ETH0_NAME { + display "Device name for the ETH0 ethernet port 0 driver" + flavor data + default_value {"\"eth0\""} + description " + This option sets the name of the ethernet device for the + RealTek 8139 ethernet port 0." + } + } +}
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/i386/pc/rltk8139/current/include/devs_eth_i386_pc_rltk8139.inl @@ -0,0 +1,90 @@ +//========================================================================== +// +// devs/eth/i386/pc/rltk8139/include/devs_eth_i386_pc_rltk8139.inl +// +// i386 PC RealTek 8139 ethernet I/O definitions. +// +//========================================================================== +//####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): Eric Doenges +// Contributors: +// Date: 2003-07-16 +// Purpose: i386 PC RealTek 8139 ethernet definitions +//####DESCRIPTIONEND#### +//========================================================================== + +// +// CAUTION! This driver has *not* been tested on PC hardware. It may work +// or not :-) If there are problems, they are probably cache related. +// If you find such, please let us know. +// +//#define CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY + +#define CACHE_ALIGNED __attribute__ ((aligned (HAL_DCACHE_LINE_SIZE))) + +#ifdef CYGPKG_DEVS_ETH_I386_PC_RLTK8139_ETH0 + +static cyg_uint8 rltk8139_eth0_rx_ring[RX_BUF_TOT_LEN] CACHE_ALIGNED; +static cyg_uint8 +rltk8139_eth0_tx_buffer[(TX_BUF_TOT_LEN + HAL_DCACHE_LINE_SIZE - 1) + & ~(HAL_DCACHE_LINE_SIZE - 1)] CACHE_ALIGNED; +static Rltk8139_t rltk8139_eth0_priv_data = { + 0, rltk8139_eth0_rx_ring, rltk8139_eth0_tx_buffer +}; + +ETH_DRV_SC(rltk8139_sc0, + &rltk8139_eth0_priv_data, + CYGDAT_DEVS_ETH_I386_PC_RLTK8139_ETH0_NAME, + rltk8139_start, + rltk8139_stop, + rltk8139_control, + rltk8139_can_send, + rltk8139_send, + rltk8139_recv, + rltk8139_deliver, + rltk8139_poll, + rltk8139_int_vector + ); + +NETDEVTAB_ENTRY(rltk8139_netdev0, + "rltk8139_" CYGDAT_DEVS_ETH_I386_PC_RLTK8139_ETH0_NAME, + rltk8139_init, + &rltk8139_sc0); + +#endif // CYGPKG_DEVS_ETH_I386_PC_RLTK8139_ETH0 + +// EOF devs_eth_i386_pc_rltk8139.inl
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/rltk/8139/current/ChangeLog @@ -0,0 +1,43 @@ +2003-07-09 Eric Doenges <Eric.Doenges@DynaPel.com> + + * src/if_8139.h: + * src/if_8139.c: + * doc/README: + * cdl/rltk_8139_eth_drivers.cdl: + New package - PCI ethernet driver for RTL8139 cards, + (using the Intel 82259 driver as inspiration). + +//=========================================================================== +//####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#### +//===========================================================================
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/rltk/8139/current/cdl/rltk_8139_eth_drivers.cdl @@ -0,0 +1,171 @@ +# ==================================================================== +# +# rltk_8139_eth_drivers.cdl +# +# RealTek 8139 ethernet driver +# +# ==================================================================== +#####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): Eric Doenges +# Original data: +# Contributors: +# Date: 2003-07-16 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_ETH_RLTK_8139 { + display "RealTek 8139 ethernet driver" + description "Ethernet driver for RealTek 8139 controller." + + parent CYGPKG_IO_ETH_DRIVERS + active_if CYGPKG_IO_ETH_DRIVERS + active_if CYGINT_DEVS_ETH_RLTK_8139_REQUIRED + + implements CYGINT_IO_ETH_MULTICAST + + include_dir cyg/devs/eth + + # SNMP demands to know stuff; this sadly makes us break the neat + # abstraction of the device having nothing exported. + # include_files include/8139_info.h + # and tell them that it is available + define_proc { + puts $::cdl_system_header \ + "#define CYGBLD_DEVS_ETH_DEVICE_H <pkgconf/devs_eth_rltk_8139.h>" + + puts $::cdl_header "#include CYGDAT_DEVS_ETH_RLTK_8139_CFG"; + } + + compile -library=libextras.a if_8139.c + + cdl_component CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS { + display "Share interrupt with other devices" + default_value 1 + description " + If this option is enabled, the driver does not assume that it is + in sole possession of the interrupt pin used by the 8139." + + cdl_option CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139 { + display "Mask 8139 interrupts on chip" + default_value 1 + description " + If this option is enabled, the driver masks interrupts in the 8139's + status register, and does not mask the interrupt vector. This is + only useful if the 8139 must share it's interrupt line with other + devices." + } + } + + cdl_option CYGDBG_DEVS_ETH_RLTK_8139_CHATTER { + display "Print debugging messages" + default_value 0 + description " + If this option is set, a lot of debugging messages are printed + to the console to help debug the driver." + } + +# cdl_component CYGDBG_DEVS_ETH_RLTK_8139_KEEP_STATISTICS { +# display "Keep Ethernet statistics" +# default_value 1 +# description " +# The ethernet device can maintain statistics about the network, +# specifically a great variety of error rates which are useful +# for network management. SNMP for example uses this +# information. There is some performance cost in maintaining +# this information; disable this option to recoup that." + +# cdl_option CYGDBG_DEVS_ETH_RLTK_8139_KEEP_8139_STATISTICS { +# display "Keep RealTek 8139 internal statistics" +# default_value 1 +# description " +# The i82559 keeps internal counters, and it is possible to +# acquire these. But the i82559 (reputedly) does not service +# the network whilst uploading the data to RAM from its +# internal registers. If throughput is a problem, disable +# this option to acquire only those statistics gathered by +# software, so that the i82559 never sleeps." +# } +# } + +# cdl_component CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM { +# display "SIOCSIFHWADDR records MAC address in EEPROM" +# default_value 0 +# description " +# The ioctl() socket call with operand SIOCSIFHWADDR sets the +# interface hardware address - the MAC address or ethernet +# address. This option causes the new MAC address to be written +# into the EEPROM associated with the interface, so that the new +# MAC address is permanently recorded. Doing this should be a +# carefully chosen decision, hence this option." +# } + + cdl_option CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX { + display "Size of the receive ring" + flavor data + legal_values 0 to 2 + default_value { CYGPKG_REDBOOT ? 0 : 2 } + define RX_BUF_LEN_IDX + description " + The 8139 stores all received packets in a single 'rx ring' + located somewhere in physical memory. The size of this ring + can be varied from ~8k to ~64k; however the driver currently + supports a maximum buffer size of only ~32k (so we can use + the 8139's WRAP mode). The actual buffer size is + 8192<<x + 16 + 1536 bytes, with x being the value of this + option." + } + + cdl_component CYGPKG_DEVS_ETH_RLTK_8139_OPTIONS { + display "RealTek 8139 ethernet driver build options" + flavor none + no_define + + cdl_option CYGPKG_DEVS_ETH_RLTK_8139_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 RealTek 8139 ethernet driver package. These + flags are used in addition to the set of global flags." + } + } +} +# EOF rltk_8139_eth_drivers.cdl
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/rltk/8139/current/doc/README @@ -0,0 +1,164 @@ +Some notes on the RealTek 8139 driver + + +1. Using the driver + +This driver follows the customization model used by many other drivers +to separate those parts of the code that are device specific from those +that are platform specific by requiring two packages to actually use the +driver -- the driver itself and a platform glue package that contains +only a .cdl and an .inl file (see the devs/i386/pc/rltk8139 package for +an example). + +Both the driver and the glue packages must be added to the package +database before you can use them. My entries look like this: + +package CYGPKG_DEVS_ETH_RLTK_8139 { + alias { "RealTek 8139 ethernet driver" + devs_eth_rltk_8139 8139_eth_driver } + hardware + directory devs/eth/rltk/8139 + script rltk_8139_eth_drivers.cdl + description "Ethernet driver for RealTek 8139 NIC." +} + +and + +package CYGPKG_DEVS_ETH_I386_RLTK8139 { + alias { "Standard PC with RealTek 8139 ethernet device" + devs_eth_i386_pc_rltk8139 } + hardware + directory devs/eth/i386/pc/rltk8139 + script i386_pc_rltk8139_eth_drivers.cdl + description "Ethernet driver for the RealTek 8139 family of chips." +} + +Finally, you will need to create a new target that includes the RealTek +driver. The easiest way to this is copy an existing target and add the +two packages defined above (and removing the Intel 82259 packages in case +of an i386 pc target). + + +2. Cache Coherency + +Since the 8139 reads data directly from memory via the PCI bus, you may +have to worry about data cache coherency. For eCos, there are basically +three cases (turning the data cache off is not considered a serious solution): + +a. Either the CPU has no data cache, or the CPU has cache snooping logic +that will detect memory accesses by PCI bus master devices and flush the cache +when necessary. In this case, nothing special needs to be done. + +b. The MMU is configured to access memory uncached in a certain address space. +In this case, the macro CYGARC_UNCACHED_ADDRESS() can be used to convert +normal (cached) into uncached accesses. The driver always uses this macro for +accessing the transmit and receive buffers, since if the HAL doesn't +support this mechanism, the macro does nothing and no harm is done. + +c. The data cache needs to be flushed/invalidated by the driver. In this case, +you must define CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY in the +platform specific .inl file. Furthermore, the HAL macros HAL_DCACHE_INVALIDATE +and HAL_DCACHE_FLUSH must be defined. Next, you must ensure that the buffers +are aligned to cache line boundaries; otherwise, the code could fail in +mysterious ways. + +One way to do this is to define the following in the .inl file: + +#define CACHE_ALIGNED __attribute__ ((aligned (HAL_DCACHE_LINE_SIZE))) + +Then, use this attribute on the transmit and receive buffer definitions: + +static cyg_uint8 rltk8139_eth0_rx_ring[RX_BUF_TOT_LEN] CACHE_ALIGNED; + +Note that this may fail for long cache lines, since the 'aligned' attribute +does not allow arbitrarily large alignment parameters. Unfortunately, the gcc +documentation does not say what the maximum alignment that can be specified +is. Additionally, the linker may also be limited in the maximum alignment that +can be used. In such cases, you'll have to bite the bullet and define more +space than would be strictly necessary, and ensure the necessary alignment +like this: + +static cyg_uint8 rltk8139_eth0_rx_ring[RX_BUF_TOT_LEN + HAL_DCACHE_LINE_SIZE]; + +Then, reference the buffers in the Rltk8139 definition like this: + +(cyg_uint8 *)((int)(&rltk8139_eth0_rx_ring[0] + HAL_DCACHE_LINE_SIZE) + & ~(HAL_DCACHE_LINE_SIZE - 1)) + +This assumes the cache line size is a power of 2; this is the case for all +CPUs I know of. It also assumes an int can hold a pointer; if this is +not true for your platform, use an integral type that can. + +Another thing to watch out for is that the buffers should also end on +a cache line boundary. If your linker places the buffers sequentially in +memory, you will only have to do this for the last buffer defined (since +all buffers will start on cache line boundaries): + +static cyg_uint8 +rltk8139_eth0_tx_buffer[(TX_BUF_TOT_LEN + HAL_DCACHE_LINE_SIZE - 1) + & ~(HAL_DCACHE_LINE_SIZE - 1)] CACHE_ALIGNED; + + +3. Interrupt sharing + +If the 8139 must share it's interrupt request line with other devices, the +HAL option 'chained interrupts' must be enabled. The 8139 driver does not +support IRQ muxing like the Intel 82559 driver does (see also *Limitations*). + +The driver's ISR does not clear the interrupt status bits since I believe this +should only be done after the conditions that caused those bits to be set +have been handled by the '_deliver' routine. Instead, the interrupt is masked. +There are two ways to do this (configurable with a CDL option): + +a. The interrupt vector is masked. Personally I think this is a bad idea + because this will also block interrupts from all other devices sharing + this interrupt until the network thread gets around to calling the + '_deliver' routine. + +b. Mask the interrupt request using the 8139's interrupt mask register. This + way, other devices' interrupt requests can still be serviced. Enable the + CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139 option to use this. + + +4. Limitations + +There are a number of limitations associated with this driver: + +a. The configuration of the NIC (MAC address, media selection, etc.) is + loaded from the serial EEPROM (which is assumed to exist) and cannot be + changed either at compile or run time. + +b. The 'twister' cannot be tuned. As far as I can make out, the 'twister' + can be tuned to improve signal quality over long lines. The RealTek + data sheet does not document the twister; and the code in the Linux + driver that does this is totally incomprehensible to me. + +c. If multiple 8139s share the same interrupt, chained interrupts have to + be used. No IRQ MUXing (like the Intel 82559 driver has) is supported. + +d. Programming the multicast acceptance filter is now implemented, but not + tested because eCos doesn't have such a test program (or at least I + couldn't find any). Since I have never used multicasting myself, I don't + feel competent to write one. Someone suggested setting up an IPv6 network + for testing, since it seems IPv6 makes use of multicasting in normal + operation, but I haven't got around to doing that. + +e. It's fairly slow. This is not really the driver's fault - the 8139 requires + a fast CPU to get anything approaching decent speed because all messages + have to be copied around in memory. + + +5. Credits + +The 8139's data sheet is not really all that helpful, since it contains +a lot of omissions and some data that is simply incorrect. As such, I am +indebted to Bill Paul for his well-documented OpenBSD driver, which was +invaluable for figuring out how the chip is supposed to work. The idea of +using 'enum' instead of '#define' came from the Linux 8139 driver, which I +initially wanted to port to eCos, but didn't because I found it extremely +hard to read and understand. (Note that I didn't copy any code from those +drivers to avoid tainting eCos' license). The basic structure of the driver +and .cdl files was taken from the eCos i82559 driver. + +I'd also like all the people who have downloaded and tested the driver, and +contributed bug reports and fixes.
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/rltk/8139/current/src/if_8139.c @@ -0,0 +1,1325 @@ +//========================================================================== +// +// if_8139.c +// +// RealTek 8139 ethernet driver +// +//========================================================================== +//####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): Eric Doenges +// Contributors: Chris Nimmers, Gary Thomas, Andy Dyer +// Date: 2003-07-09 +// Purpose: +// Description: hardware driver for RealTek 8139 ethernet +// Notes: This is a very basic driver that will send and receive +// packets and not much else. A lot of features of the 8139 +// are not supported (power management, MII interface, +// access to the serial eeprom, 'twister tuning', etc.). +// +// Many of the configuration options (like media type and +// speed) the 8139 has are taken directly from the serial +// eeprom and are not currently configurable from this driver. +// +// I've tentatively added some code to handle cache coherency +// issues for platforms that do not have a separate address +// space for uncached memory access and do not do cache +// snooping for PCI bus masters. This code can be activated by +// defining CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY +// in the platform specific .inl file. Note that if +// CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY is +// defined, the .inl file is also responsible for making sure +// the receive and transmit buffers are located in memory in +// such a way that flushing or invalidating cache lines for +// these buffers will not affect any other buffers. See the +// README in the doc directory for some suggestions on how +// to do this. +// +// Since the official data sheet for this chip is a bit +// vague, I had to look at the Linux and OpenBSD drivers to +// understand the basic workings of the chip; however, I have +// not copied any code from those drivers to avoid tainting +// eCos' license. +// +// FIXME: +// +//####DESCRIPTIONEND#### +// +//========================================================================== +#include <pkgconf/system.h> +#ifdef CYGPKG_IO_ETH_DRIVERS +#include <pkgconf/io_eth_drivers.h> +#endif +#include <pkgconf/devs_eth_rltk_8139.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/drv_api.h> +#include <cyg/hal/hal_cache.h> +#include <cyg/io/eth/netdev.h> +#include <cyg/io/eth/eth_drv.h> + +#include <string.h> /* for memset */ + +#ifdef CYGPKG_IO_PCI +#include <cyg/io/pci.h> +#else +#error "This driver requires the PCI package (CYGPKG_IO_PCI)" +#endif + +#include <cyg/io/pci.h> + +/* Necessary for memory mapping macros */ +#include CYGHWR_MEMORY_LAYOUT_H + +/* Check if we should be dumping debug information or not */ +#if defined CYGDBG_DEVS_ETH_RLTK_8139_CHATTER \ + && (CYGDBG_DEVS_ETH_RLTK_8139_CHATTER > 0) +#define DEBUG_RLTK8139_DRIVER +#endif + +#include "if_8139.h" + +/* Which interrupts we will handle */ +#define RLTK8139_IRQ (IR_SERR|IR_FOVW|IR_RXOVW|IR_TER|IR_TOK|IR_RER|IR_ROK) + +/* Allow platform-specific configuration of the driver */ +#ifndef CYGDAT_DEVS_ETH_RLTK_8139_INL +#error "CYGDAT_DEVS_ETH_RLTK_8139_INL not defined" +#else +#include CYGDAT_DEVS_ETH_RLTK_8139_INL +#endif + +/* + * If software cache coherency is required, the HAL_DCACHE_INVALIDATE + * hal macro must be defined as well. + */ +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY +#if !defined HAL_DCACHE_INVALIDATE || !defined HAL_DCACHE_FLUSH +#error "HAL_DCACHE_INVALIDATE/HAL_DCACHE_FLUSH not defined for this platform but CYGPKG_DEVS_ETH_RLTK_8139_CACHE_COHERENCY was defined." +#endif +#endif + +/* Local driver function declarations */ +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE +static cyg_uint32 rltk8139_isr(cyg_vector_t vector, cyg_addrword_t data); +#endif + +#ifdef ETH_DRV_SET_MC_LIST +static cyg_uint32 ether_crc(cyg_uint8 *data, int length); +static void rltk8139_set_multicast_list(Rltk8139_t *rltk8139_info, + struct eth_drv_mc_list *mc_list); +#endif + +static void rltk8139_reset(struct eth_drv_sc *sc); +static bool rltk8139_init(struct cyg_netdevtab_entry *tab); +static void rltk8139_start(struct eth_drv_sc *sc, unsigned char *enaddr, + int flags); +static void rltk8139_stop(struct eth_drv_sc *sc); +static int rltk8139_control(struct eth_drv_sc *sc, unsigned long key, + void *data, int data_length); +static int rltk8139_can_send(struct eth_drv_sc *sc); +static void rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, + int sg_len, int total_len, unsigned long key); +static void rltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, + int sg_len); +static void rltk8139_deliver(struct eth_drv_sc *sc); +static void rltk8139_poll(struct eth_drv_sc *sc); +static int rltk8139_int_vector(struct eth_drv_sc *sc); + +#ifdef DEBUG_RLTK8139_DRIVER +void rltk8139_print_state(struct eth_drv_sc *sc); +#endif + +/* + * Define inline functions to access the card. This will also handle + * endianess issues in one place. This code was lifted from the eCos + * i82559 driver. + */ +#if (CYG_BYTEORDER == CYG_MSBFIRST) +#define HAL_CTOLE32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24) & 0xff)) +#define HAL_LE32TOC(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24) & 0xff)) + +#define HAL_CTOLE16(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define HAL_LE16TOC(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) + +static inline void +OUTB(cyg_uint8 value, + cyg_uint32 io_address) +{ + HAL_WRITE_UINT8( io_address, value); +} + +static inline void +OUTW(cyg_uint16 value, cyg_uint32 io_address) +{ + HAL_WRITE_UINT16(io_address, + (((value & 0xff) << 8) | ((value & 0xff00) >> 8)) ); +} + +static inline void +OUTL(cyg_uint32 value, cyg_uint32 io_address) +{ + HAL_WRITE_UINT32(io_address, + ((((value) & 0xff) << 24) | (((value) & 0xff00) << 8) + | (((value) & 0xff0000) >> 8) + | (((value) >> 24) & 0xff)) ); +} + +static inline cyg_uint8 +INB(cyg_uint32 io_address) +{ + cyg_uint8 d; + HAL_READ_UINT8(io_address, d); + return d; +} + +static inline cyg_uint16 +INW(cyg_uint32 io_address) +{ + cyg_uint16 d; + HAL_READ_UINT16( io_address, d ); + return (((d & 0xff) << 8) | ((d & 0xff00) >> 8)); +} + +static inline cyg_uint32 +INL(cyg_uint32 io_address) +{ + cyg_uint32 d; + HAL_READ_UINT32(io_address, d); + return ((((d) & 0xff) << 24) | (((d) & 0xff00) << 8) + | (((d) & 0xff0000) >> 8) | (((d) >> 24) & 0xff)); +} +#else + +// Maintaining the same styleee as above... +#define HAL_CTOLE32(x) ((((x)))) +#define HAL_LE32TOC(x) ((((x)))) + +#define HAL_CTOLE16(x) ((((x)))) +#define HAL_LE16TOC(x) ((((x)))) + +static inline void OUTB(cyg_uint8 value, cyg_uint32 io_address) +{ HAL_WRITE_UINT8( io_address, value ); } + +static inline void OUTW(cyg_uint16 value, cyg_uint32 io_address) +{ HAL_WRITE_UINT16( io_address, value ); } + +static inline void OUTL(cyg_uint32 value, cyg_uint32 io_address) +{ HAL_WRITE_UINT32( io_address, value ); } + +static inline cyg_uint8 INB(cyg_uint32 io_address) +{ cyg_uint8 _t_; HAL_READ_UINT8( io_address, _t_ ); return _t_; } + +static inline cyg_uint16 INW(cyg_uint32 io_address) +{ cyg_uint16 _t_; HAL_READ_UINT16( io_address, _t_ ); return _t_; } + +static inline cyg_uint32 INL(cyg_uint32 io_address) +{ cyg_uint32 _t_; HAL_READ_UINT32( io_address, _t_ ); return _t_; } + +#endif // byteorder + + +/* + * Table of all known PCI device/vendor ID combinations for the RealTek 8139. + * Add them as you get to know them. + */ +#define CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES 1 +static pci_identifier_t +known_8139_aliases[CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES] = { + { 0x10ec, 0x8139, NULL } /* This is the offical RealTek vendor/device code */ +}; + + +/* + * Check if the device description matches a known 8139 alias. + */ +static cyg_bool +rltk8139_find_match_func(cyg_uint16 vendor_id, cyg_uint16 device_id, + cyg_uint32 class_id, void *p) +{ + int i; + + + for (i = 0; i < CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES; ++i) { + if (((known_8139_aliases[i].vendor_id == PCI_ANY_ID) || + (known_8139_aliases[i].vendor_id == vendor_id)) && + ((known_8139_aliases[i].device_id == PCI_ANY_ID) || + (known_8139_aliases[i].device_id == device_id))) + return true; + } + + return false; +} + + +/* + * Find the Nth 8139 device on all attached PCI busses and do some initial + * PCI-type initialization. Also setup the interrupt for use in eCos. + */ +static bool +rltk8139_find(int n_th, struct eth_drv_sc *sc) +{ + Rltk8139_t *rltk8139_info; + cyg_pci_device_id pci_device_id; + cyg_pci_device pci_device_info; + cyg_uint16 command; + int found = -1; + + + /* Go through all PCI devices until we find the Nth 8139 chip */ + do { + pci_device_id = CYG_PCI_NULL_DEVID; + if (!cyg_pci_find_matching(&rltk8139_find_match_func, NULL, + &pci_device_id)) + return false; + else + found += 1; + } while (found != n_th); + + /* Save device ID in driver private data in case we ever need it again */ + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + rltk8139_info->pci_device_id = pci_device_id; + + /* Now that we have found the device, we can extract some data about it */ + cyg_pci_get_device_info(pci_device_id, &pci_device_info); + + /* Get the assigned interrupt and set up ISR and DSR for it. */ + if (cyg_pci_translate_interrupt(&pci_device_info, &rltk8139_info->vector)) { +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf(" Wired to HAL interrupt vector %d\n", rltk8139_info->vector); +#endif + +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + /* + * Note that we use the generic eth_drv_dsr routine instead of + * our own. + */ + cyg_drv_interrupt_create(rltk8139_info->vector, 0, + (CYG_ADDRWORD)sc, + rltk8139_isr, + eth_drv_dsr, + &rltk8139_info->interrupt_handle, + &rltk8139_info->interrupt); + cyg_drv_interrupt_attach(rltk8139_info->interrupt_handle); +#endif + } + else { +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf(" Does not generate interrupts.\n"); +#endif + } + + /* + * Call 'cyg_pci_configure_device' for those platforms that do not + * configure the PCI bus during HAL initialization. According to Nick + * Garnett, there are good reasons to not configure PCI devices during HAL + * initialization. Also according to Nick, calling + * 'cyg_pci_configure_device' for devices already configured should have no + * effect and thus is safe to do. + */ + if (cyg_pci_configure_device(&pci_device_info)) { +#ifdef DEBUG_RLTK8139_DRIVER + int i; + diag_printf("Found device #%d on bus %d, devfn 0x%02x:\n", n_th, + CYG_PCI_DEV_GET_BUS(pci_device_id), + CYG_PCI_DEV_GET_DEVFN(pci_device_id)); + + if (pci_device_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) + diag_printf(" Note that board is active. Probed" + " sizes and CPU addresses are invalid!\n"); + + diag_printf(" Vendor 0x%04x", pci_device_info.vendor); + diag_printf("\n Device 0x%04x", pci_device_info.device); + diag_printf("\n Command 0x%04x, Status 0x%04x\n", + pci_device_info.command, pci_device_info.status) + ; + + diag_printf(" Class/Rev 0x%08x", pci_device_info.class_rev); + diag_printf("\n Header 0x%02x\n", pci_device_info.header_type); + + diag_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n", + pci_device_info.header.normal.sub_vendor, + pci_device_info.header.normal.sub_id); + + for(i = 0; i < CYG_PCI_MAX_BAR; i++) { + diag_printf(" BAR[%d] 0x%08x /", i, pci_device_info.base_address[i]); + diag_printf(" probed size 0x%08x / CPU addr 0x%08x\n", + pci_device_info.base_size[i], pci_device_info.base_map[i]); + } +#endif + } + else { +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("Failed to configure 8139 device #%d\n", n_th); +#endif + return false; + } + + /* + * Enable memory mapped and port based I/O and busmastering. We currently + * only support IO space accesses; memory mapping is enabled so that bit + * DVRLOAD in CONFIG1 is cleared automatically. + * + * NOTE: it seems that for some configurations/HALs, the device is already + * activated at this point, even though eCos' documentation suggests + * it shouldn't be. At least in my case, this is not a problem. + */ + cyg_pci_read_config_uint16(pci_device_info.devid, CYG_PCI_CFG_COMMAND, + &command); + command |= (CYG_PCI_CFG_COMMAND_IO | CYG_PCI_CFG_COMMAND_MEMORY + | CYG_PCI_CFG_COMMAND_MASTER); + cyg_pci_write_config_uint16(pci_device_info.devid, CYG_PCI_CFG_COMMAND, + command); + + /* + * This is the base address used to talk to the device. The 8139's IOAR + * and MEMAR registers are BAR0 and BAR1, respectively. + */ + rltk8139_info->base_address = pci_device_info.base_map[0]; + + /* + * Read the MAC address. The RealTek data sheet seems to claim this should + * only be read in 4 byte accesses, but the code below works just fine. + */ + for (found = 0; found < 6; ++found) + rltk8139_info->mac[found] = INB(rltk8139_info->base_address + IDR0 + found); + + /* + * This is the indicator for "uses an interrupt". The code was lifted + * from the eCos Intel 82559 driver. + */ + if (rltk8139_info->interrupt_handle != 0) { + cyg_drv_interrupt_acknowledge(rltk8139_info->vector); + +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_drv_interrupt_unmask(rltk8139_info->vector); +#endif + } + + return true; +} + +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE +/* + * Interrupt service routine. We do not clear the interrupt status bits + * (since this should really only be done after handling whatever caused + * the interrupt, and that is done in the '_deliver' routine), but instead + * clear the interrupt mask. + * + * If we are sharing interrupts with other devices, we have two options + * (configurable): + * + * 1. Mask the interrupt vector completly. Personally I think this is a bad + * idea because the other devices sharing this interrupt are also masked + * until the network thread gets around to calling the '_deliver' routine. + * + * 2. Use the interrupt mask register in the 8139 to mask just the interrupt + * request coming from the 8139. This way, the other devices' requests + * can still be serviced. + */ +static cyg_uint32 +rltk8139_isr(cyg_vector_t vector, cyg_addrword_t data) +{ + Rltk8139_t *rltk8139_info; +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS + cyg_uint16 isr; +#endif + + rltk8139_info = (Rltk8139_t *)(((struct eth_drv_sc *)data)->driver_private); + +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS + /* + * If interrupt sharing is enabled, check if the interrupt is really + * intended for us. Note that while the RealTek data sheet claims that + * reading the interrupt status register will clear all it's bits, + * this is not true, so we can read it without problems. + */ + if (!(isr = INW(rltk8139_info->base_address + ISR))) + return 0; +#endif + +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139 + /* Clear the interrupt mask to stop the current request. */ + OUTW(0, rltk8139_info->base_address + IMR); +#else + /* Mask the interrupt */ + cyg_interrupt_mask(vector); +#endif + + /* Acknowledge the interrupt for those platforms were this is necessary */ + cyg_interrupt_acknowledge(vector); + + return (CYG_ISR_HANDLED | CYG_ISR_CALL_DSR); +} +#endif /* ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE */ + +/* + * Reset the chip. This function is not exported to higher level software. + */ +static void +rltk8139_reset(struct eth_drv_sc *sc) +{ + rltk8139_stop(sc); + rltk8139_start(sc, NULL, 0); +} + +#ifdef ETH_DRV_SET_MC_LIST +/* + * I assume (hope !) that this is identical to Ethernet's CRC algorithm + * specified in IEEE 802.3. It does seem to calculate the same CRC that + * the 8139 itself does, so I think it is correct. + * Note that while Ethernet's polynomial is usually specified as 04C11DB7, + * we must use EDB88320 because we shift the bits to the left, not the right. + * (See ftp://ftp.rocksoft.com/papers/crc_v3.txt for a good description of + * CRC algorithms). + */ +static cyg_uint32 +ether_crc(cyg_uint8 *data, int length) +{ + int bit; + cyg_uint32 crc = 0xFFFFFFFFU; + + while (length-- > 0) { + crc ^= *data++; + for (bit = 0; bit < 8; ++bit) { + if (crc & 1) + crc = (crc >> 1) ^ 0xEDB88320U; + else + crc = (crc >> 1); + } + } + + return crc ^ 0xFFFFFFFFU; +} + + +/* + * Set up multicast filtering. The way I understand existing driver code + * (Linux and OpenBSD), the 8139 calculates the ethernet CRC of + * incoming addresses and uses the top 6 bits as an index into a hash + * table. If the corresponding bit is set in MAR0..7, the address is + * accepted. + */ +static void +rltk8139_set_multicast_list(Rltk8139_t *rltk8139_info, + struct eth_drv_mc_list *mc_list) +{ + cyg_uint32 mar[2], hash; + int i; + + /* If 'mc_list' is NULL, accept all multicast packets. */ + if (!mc_list) { + mar[0] = 0xFFFFFFFFU; + mar[1] = 0xFFFFFFFFU; + } + else { + mar[0] = 0; + mar[1] = 0; + + for (i = 0; i < mc_list->len; ++i) { + hash = ether_crc(&mc_list->addrs[i][0], ETHER_ADDR_LEN) >> 26; + mar[hash >> 5] |= (1 << (hash & 0x1F)); + } + } + + /* Program the new filter values */ + OUTL(mar[0], rltk8139_info->base_address + MAR0); + OUTL(mar[1], rltk8139_info->base_address + MAR4); +} +#endif /* ifdef ETH_DRV_SET_MC_LIST */ + + +/* + * Initialize the network interface. Since the chips is reset by calling + * _stop() and _start(), any code that will never need to be executed more + * than once after system startup should go here. + */ +static bool +rltk8139_init(struct cyg_netdevtab_entry *tab) +{ + struct eth_drv_sc *sc; + Rltk8139_t *rltk8139_info; + + + sc = (struct eth_drv_sc *)(tab->device_instance); + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + + /* + * Initialize the eCos PCI library. According to the documentation, it + * is safe to call this function multiple times, so we call it just to + * be sure it has been done. + */ + cyg_pci_init(); + + /* + * Scan the PCI bus for the specified chip. The '_find' function will also + * do some basic PCI initialization. + */ + if (!rltk8139_find(rltk8139_info->device_num, sc)) { +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_init: could not find RealTek 8139 chip #%d.\n", + rltk8139_info->device_num); +#endif + return false; + } + + /* + * The initial tx threshold is set here to prevent it from being reset + * with every _start(). + */ + rltk8139_info->tx_threshold = 3; + + /* Initialize upper level driver */ + (sc->funs->eth_drv->init)(sc, rltk8139_info->mac); + + return true; +} + + +/* + * (Re)Start the chip, initializing data structures and enabling the + * transmitter and receiver. Currently, 'flags' is unused by eCos. + */ +static void +rltk8139_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) +{ + Rltk8139_t *rltk8139_info; + int i; + + +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_start(%s)\n", sc->dev_name); +#endif + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + + /* + * Reset the chip. Existing driver code implies that this may take up + * to 10ms; since I don't know under what exact circumstances this code may + * be called I busy wait here regardless. + */ + OUTB(RST, rltk8139_info->base_address + CR); + while (INB(rltk8139_info->base_address + CR) & RST); + +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_start(%s): 8139 was successfully reset.\n", + sc->dev_name); +#endif + + /* + * Clear the key storage area. These keys are used by the eCos networking + * support code to keep track of individual packets. + */ + for (i = 0; i < NUM_TX_DESC; ++i) + rltk8139_info->tx_desc_key[i] = 0; + + /* Initialize transmission buffer control */ + rltk8139_info->tx_free_desc = 0; + rltk8139_info->tx_num_free_desc = NUM_TX_DESC; + + /* + * Set the requested MAC address if enaddr != NULL. This is a special + * feature of my '_start' function since it's used to reset the chip after + * errors as well. + */ + if (enaddr != NULL) { + for (i = 0; i < 6; ++i) { + rltk8139_info->mac[i] = enaddr[i]; + OUTB(enaddr[i], rltk8139_info->base_address + IDR0 + i); + } + } + + /* + * Now setup the transmission and reception buffers. These could be done + * in _init() and kept around, but putting them here fits better logically. + */ + OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer + + 0 * TX_BUF_SIZE)), + rltk8139_info->base_address + TSAD0); + OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer + + 1 * TX_BUF_SIZE)), + rltk8139_info->base_address + TSAD1); + OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer + + 2 * TX_BUF_SIZE)), + rltk8139_info->base_address + TSAD2); + OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer + + 3 * TX_BUF_SIZE)), + rltk8139_info->base_address + TSAD3); + OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)rltk8139_info->rx_ring), + rltk8139_info->base_address + RBSTART); + + /* + * Enable the transmitter and receiver, then clear the missed packet + * counter. + */ + OUTB(INB(rltk8139_info->base_address + CR) | (TE|RE), + rltk8139_info->base_address + CR); + OUTL(0, rltk8139_info->base_address + MPC); + + /* + * It seems the receiver and transmitter configuration can only + * be set after the transmitter/receiver have been enabled. + */ + OUTL(TXCFG, rltk8139_info->base_address + TCR); + OUTL(RXCFG | AM, rltk8139_info->base_address + RCR); + + /* + * Enable the transmitter and receiver again. I'm not sure why this is + * necessary; the Linux driver does it so we do it here just to be on + * the safe side. + */ + OUTB(INB(rltk8139_info->base_address + CR) | (TE|RE), + rltk8139_info->base_address + CR); + +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + /* + * If this driver was not compiled in stand alone (without interrupts) + * mode, enable interrupts. + */ + OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR); +#endif + +#ifdef DEBUG_RLTK8139_DRIVER + rltk8139_print_state(sc); +#endif +} + + +/* + * Stop the chip, disabling the transmitter and receiver. + */ +static void +rltk8139_stop(struct eth_drv_sc *sc) +{ + Rltk8139_t *rltk8139_info; + + +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_stop(%s)\n", sc->dev_name); +#endif + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + + /* Disable receiver and transmitter */ + OUTB(INB(rltk8139_info->base_address + CR) & ~(TE|RE), + rltk8139_info->base_address + CR); + + /* Mask all interrupts */ + OUTW(0, rltk8139_info->base_address + IMR); +} + + +/* + * 8139 control function. Unlike a 'real' ioctl function, this function is + * not required to tell the caller why a request failed, only that it did + * (see the eCos documentation). + */ +static int +rltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data, + int data_length) +{ + int i; + Rltk8139_t *rltk8139_info; + + +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_control(%08x, %lx)\n", sc, key); +#endif + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + + switch (key) { +#ifdef ETH_DRV_SET_MAC_ADDRESS + case ETH_DRV_SET_MAC_ADDRESS: + if ( 6 != data_length ) + return 1; + + /* Set the mac address */ + for (i = 0; i < 6; ++i) { + rltk8139_info->mac[i] = *(((cyg_uint8 *)data) + i); + OUTB(rltk8139_info->mac[i], rltk8139_info->base_address + IDR0 + i); + } + return 0; +#endif + +#ifdef ETH_DRV_GET_MAC_ADDRESS + case ETH_DRV_GET_MAC_ADDRESS: + if (6 != data_length) + return 1; + + memcpy(data, rltk8139_info->mac, 6); + return 0; +#endif + +#ifdef ETH_DRV_GET_IF_STATS_UD + case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE + //ETH_STATS_INIT( sc ); // so UPDATE the statistics structure +#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) + break; +#endif + +#ifdef ETH_DRV_SET_MC_LIST + case ETH_DRV_SET_MC_LIST: + /* + * Program the 8139's multicast filter register. If the eth_drv_mc_list + * contains at least one element, set the accept multicast bit in the + * receive config register. + */ + rltk8139_set_multicast_list(rltk8139_info, (struct eth_drv_mc_list *)data); + if (((struct eth_drv_mc_list *)data)->len > 0) + OUTL(INL(rltk8139_info->base_address + RCR) | AM, + rltk8139_info->base_address + RCR); + else + OUTL(INL(rltk8139_info->base_address + RCR) & ~AM, + rltk8139_info->base_address + RCR); + + return 0; +#endif // ETH_DRV_SET_MC_LIST + +#ifdef ETH_DRV_SET_MC_ALL + case ETH_DRV_SET_MC_ALL: + /* + * Set the accept multicast bit in the receive config register and + * program the multicast filter to accept all addresses. + */ + rltk8139_set_multicast_list(rltk8139_info, NULL); + OUTL(INL(rltk8139_info->base_address + RCR) | AM, + rltk8139_info->base_address + RCR); + return 0; +#endif // ETH_DRV_SET_MC_ALL + + default: + return 1; + } + + return 1; +} + + +/* + * Check if a new packet can be sent. + */ +static int +rltk8139_can_send(struct eth_drv_sc *sc) +{ + return ((Rltk8139_t *)(sc->driver_private))->tx_num_free_desc; +} + + +/* + * Send a packet over the wire. + */ +static void +rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, + int total_len, unsigned long key) +{ + Rltk8139_t *rltk8139_info; + cyg_uint8 *tx_buffer; + struct eth_drv_sg *last_sg; + int desc; + + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_send(%s, %08x, %d, %d, %08lx)\n", + sc->dev_name, sg_list, sg_len, total_len, key); +#endif + + CYG_ASSERT(total_len <= TX_BUF_SIZE, "packet too long"); + + /* + * Get the next free descriptor to send. We lock out all interrupts + * and scheduling because we really, really do not want to be interrupted + * at this point. + * + * IMPORTANT NOTE: the RealTek data sheet does not really make this clear, + * but when they talk about a 'ring' of transmit descriptors, they + * _really_ mean it, i.e. you _must_ use descriptor #1 after descriptor + * #0 even if transmission of descriptor #0 has already completed. + */ +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_interrupt_disable(); +#endif + + /* + * Sanity check to see if '_send' was called even though there is no free + * descriptor. This is probably unnecessary. + */ + if (rltk8139_info->tx_num_free_desc == 0) { +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_interrupt_enable(); +#endif +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_send(%s): no free descriptor available\n", + sc->dev_name); +#endif + return; + } + + /* + * Get the free descriptor and advance the descriptor counter modulo + * TX_NUM_DESC. We assume that TX_NUM_DESC will always be a power of 2. + */ + desc = rltk8139_info->tx_free_desc; + rltk8139_info->tx_free_desc = (rltk8139_info->tx_free_desc + 1) + & (NUM_TX_DESC - 1); + + /* Decrement the number of free descriptors */ + rltk8139_info->tx_num_free_desc -= 1; + +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + /* Reenable interrupts at this point */ + cyg_interrupt_enable(); +#endif + + /* + * Determine the buffer memory to use and tell the hardware about it. + * Since we use fixed buffer addresses, we do not need to set up TSADx. + * Memorize the key so we can call the tx_done callback correctly. + * + * While it would be possible to set TSADx to the packet directly if + * it is stored in a linear memory area with 32 bit alignment, it seems + * this happens so seldomly that it's simply not worth the extra + * runtime check. + */ + tx_buffer = CYGARC_UNCACHED_ADDRESS(rltk8139_info->tx_buffer + + TX_BUF_SIZE * desc); + rltk8139_info->tx_desc_key[desc] = key; + + /* + * Copy the data to the designated position. Note that unlike the eCos + * Intel 82559 driver, we simply assume that all the scatter/gather list + * elements' lengths will add up to total_len exactly, and don't check + * to make sure. + */ + for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) { + memcpy(tx_buffer, (void *)(sg_list->buf), sg_list->len); + tx_buffer += sg_list->len; + } + + /* + * Make sure the packet has the minimum ethernet packet size, padding + * with zeros if necessary. + */ + if (total_len < MIN_ETH_FRAME_SIZE) { + memset(tx_buffer, 0, MIN_ETH_FRAME_SIZE - total_len); + total_len = MIN_ETH_FRAME_SIZE; + } + + /* + * Flush the data cache here if necessary. This ensures the 8139 can + * read the correct data from the transmit buffer. + */ +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY + HAL_DCACHE_FLUSH(rltk8139_info->tx_buffer + TX_BUF_SIZE * desc, total_len); +#endif + + /* + * Now setup the correct transmit descriptor to actually send the data. + * The early TX threshold is incremented by the driver until we reach a + * size that prevents transmit underruns. (An earlier attempt to calculate + * this parameter from the packet size didn't work). + */ + OUTL((rltk8139_info->tx_threshold << ERTXTH_SHIFT) | (total_len & SIZE), + rltk8139_info->base_address + TSD0 + (desc<<2)); +} + + +/* + * This routine actually retrieves data from the receive ring by + * copying it into the specified scatter/gather buffers. Again, + * we assume the scatter/gather list is OK and don't check against + * total length. + */ +static void +rltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, + int sg_len) +{ + Rltk8139_t *rltk8139_info; + struct eth_drv_sg *last_sg; + cyg_uint8 *rx_buffer; + + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + rx_buffer = rltk8139_info->rx_current; + + /* + * Invalidate the cache line(s) mapped to the receive buffer + * if necessary. + */ +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY + HAL_DCACHE_INVALIDATE(rx_buffer, rltk8139_info->rx_size); +#endif + + for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) { + memcpy((void *)(sg_list->buf), rx_buffer, sg_list->len); + rx_buffer += sg_list->len; + } +} + + +/* + * This function does all the heavy lifting associated with interrupts. + */ +static void +rltk8139_deliver(struct eth_drv_sc *sc) +{ + Rltk8139_t *rltk8139_info; + cyg_uint16 status, pci_status; + cyg_uint32 tsd; + int desc; + + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + + /* + * The RealTek data sheet claims that reading the ISR will clear + * it. This is incorrect; to clear a bit in the ISR, a '1' must be + * written to the ISR instead. We immediately clear the interrupt + * bits at this point. + */ + status = INW(rltk8139_info->base_address + ISR); + OUTW(status, rltk8139_info->base_address + ISR); + +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_deliver(%s): %04x\n", sc->dev_name, status); +#endif + + /* + * Check for a PCI error. This seems like a very serious error to + * me, so we will reset the chip and hope for the best. + */ + if (status & IR_SERR) { + cyg_pci_read_config_uint16(rltk8139_info->pci_device_id, + CYG_PCI_CFG_STATUS, &pci_status); + cyg_pci_write_config_uint16(rltk8139_info->pci_device_id, + CYG_PCI_CFG_STATUS, pci_status); +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_deliver(%s): PCI error %04x\n", + sc->dev_name, pci_status); +#endif + + rltk8139_reset(sc); + return; + } + + /* Check for transmission complete (with errors or not) */ + if ((status & IR_TER) || (status & IR_TOK)) { + /* + * Figure out which descriptors' status must be checked. We lock out + * interrupts while manipulating the descriptor list because we do not + * want to be interrupted at this point. + */ + while (1) { +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_interrupt_disable(); +#endif + + /* Check if all descriptors are ready, in which case we are done. */ + if (rltk8139_info->tx_num_free_desc >= NUM_TX_DESC) { +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_interrupt_enable(); +#endif + break; + } + + desc = (rltk8139_info->tx_free_desc + - (NUM_TX_DESC - rltk8139_info->tx_num_free_desc)) + & (NUM_TX_DESC - 1); +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_interrupt_enable(); +#endif + /* Get the current status of the descriptor */ + tsd = INL(rltk8139_info->base_address + TSD0 + (desc<<2)); + + /* + * If a transmit FIFO underrun occurred, increment the threshold + * value. + */ + if ((tsd & TUN) && (rltk8139_info->tx_threshold < 64)) + rltk8139_info->tx_threshold += 1; + + /* + * Check if a transmission completed OK. RealTek's data sheet implies + * that a successful transmission that experiences underrun will only + * set TUN. This is not true; TOK is set for all successful + * transmissions. + */ + if (tsd & TOK) { + (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], 0); + } + else if (tsd & TABT) { + /* + * Set the CLRABT bit in TCR. Since I haven't encountered any + * transmission aborts so far, I don't really know if this code + * will work or not. + */ + OUTL(INL(rltk8139_info->base_address + TCR) & CLRABT, + rltk8139_info->base_address + TCR); + (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], -1); + } + else { + /* + * This descriptor is not ready. Since the descriptors are used + * in a ring, this means that no more descriptors are ready. + */ + break; + } + + /* + * Clear the saved key value. This is not really necessary, since + * the key value is never used to determine if a descriptor is + * valid or not. However, clearing it is a tidier IMO. + */ + rltk8139_info->tx_desc_key[desc] = 0; + + /* + * Increment the free descriptor count and go through the loop again + * to see if more descriptors are ready. + */ +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_interrupt_disable(); +#endif + rltk8139_info->tx_num_free_desc += 1; +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + cyg_interrupt_enable(); +#endif + } + } + + if (status & IR_ROK) { + /* + * Received a frame. Note that '_deliver' does not actually copy any + * data; it just determines how many bytes are available and tells + * the generic ethernet driver about it, which then calls into + * the '_recv' function to copy the data. + */ + cyg_uint16 rx_pos; + cyg_uint32 header, length; + + /* + * CAPR contains the index into the receive buffer. It is controlled + * completely in software. For some reason, CAPR points 16 bytes + * before the actual start of the packet. + */ + rx_pos = (INW(rltk8139_info->base_address + CAPR) + 16) % RX_BUF_LEN; + + /* + * Loop until the rx buffer is empty. I have no idea how the 8139 + * determines if the buffer still contains a packet; it may check + * that CAPR points 16 bytes before CBR. + */ + while (!(INB(rltk8139_info->base_address + CR) & BUFE)) { + /* + * Invalidate the data cache for the cache line containing the header + * if necessary. + */ +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY + HAL_DCACHE_INVALIDATE(&rltk8139_info->rx_ring[rx_pos], + sizeof(cyg_uint32)); +#endif + + /* + * The 8139 prepends each packet with a 32 bit packet header that + * contains a 16 bit length and 16 bit status field, in little-endian + * byte order. + */ + header = HAL_LE32TOC(*((volatile cyg_uint32 *)CYGARC_UNCACHED_ADDRESS(&rltk8139_info->rx_ring[rx_pos]))); + + /* + * If the 8139 is still copying data for this packet into the + * receive ring, it will set packet length to 0xfff0. This shouldn't + * ever happen because we do not use early receive. + */ + if ((header >> 16) == 0xFFF0) + break; + + /* + * Since the 8139 appends the ethernet CRC to every packet, we + * must subtract 4 from the length to get the true packet length. + */ + length = (header >> 16) - 4; + + /* + * Check if the packet was received correctly. The OpenBSD driver + * resets the chip if this is not the case; we attempt to salvage + * following packets by doing nothing. + */ + if (!(header & HDR_ROK)) { + } + else { + /* + * Packet was received OK. Determine from where to start copying + * bytes. This is saved in the driver private area so rlt8139_recv + * doesn't have to redetermine this information. Then, inform + * the generic ethernet driver about the packet. + */ + rltk8139_info->rx_current = CYGARC_UNCACHED_ADDRESS(rltk8139_info->rx_ring + rx_pos + 4); + rltk8139_info->rx_size = length; + + /* Tell eCos about the packet */ + (sc->funs->eth_drv->recv)(sc, length); + } + + /* + * Update CAPR. CAPR must be aligned to a 32 bit boundary, and should + * point 16 bytes before it's actual position. + */ + rx_pos = ((rx_pos + length + 8 + 3) & ~3) % RX_BUF_LEN; + OUTW((rx_pos - 16) % RX_BUF_LEN, rltk8139_info->base_address + CAPR); + } + } + + if (status & IR_RXOVW) { + /* + * In case of a receive buffer overflow, the RealTek data sheet claims we + * should update CAPR and then write a '1' to ROK in ISR. However, none of + * the other 8139 drivers I have looked at do this, so we will just reset + * the chip instead. + */ +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_deliver(%s): receive buffer overflow\n", + sc->dev_name); +#endif + rltk8139_reset(sc); + return; + } + + if (status & IR_FOVW) { + /* + * Rx FIFO overflow. According to RealTek's data sheet, this is cleared + * by writing a '1' to RXOVW. Again, none of the 8139 drivers I have + * seen actually do this, so we reset the chip instead. + */ +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_deliver(%s): receive FIFO overflow\n", + sc->dev_name); +#endif + rltk8139_reset(sc); + return; + } + +#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE + /* Finally, reenable interrupts */ +#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139 + OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR); +#else + cyg_interrupt_unmask(rltk8139_info->vector); +#endif +#endif +} + + +/* + * '_poll' does the same thing as '_deliver'. It is called periodically when + * the ethernet driver is operated in non-interrupt mode, for instance by + * RedBoot. + */ +static void +rltk8139_poll(struct eth_drv_sc *sc) +{ + Rltk8139_t *rltk8139_info; + cyg_uint16 isr; + + +#ifdef DEBUG_RLTK8139_DRIVER + diag_printf("rltk8139_poll(%s)\n", sc->dev_name); +#endif + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + + /* + * Get the current interrupt status. If anything changed, call + * _deliver. + */ + if ((isr = INW(rltk8139_info->base_address + ISR))) + rltk8139_deliver(sc); +} + + +/* + * Return the interrupt vector used by this device. + */ +static int +rltk8139_int_vector(struct eth_drv_sc *sc) +{ + return ((Rltk8139_t *)(sc->driver_private))->vector; +} + + +/* + * Quick and dirty register dump. This is somewhat dangerous, since + * we read the register space 32 bits at a time, regardless of actual + * register sizes. + */ +#ifdef DEBUG_RLTK8139_DRIVER +void +rltk8139_print_state(struct eth_drv_sc *sc) { + int i; + Rltk8139_t *rltk8139_info; + + + rltk8139_info = (Rltk8139_t *)(sc->driver_private); + + for (i = IDR0; i < FFER; i += 16) { + diag_printf("8139 reg address 0x%02x = 0x%08x", i, + INL(rltk8139_info->base_address + i)); + diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 4)); + diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 8)); + diag_printf(" 0x%08x\n", INL(rltk8139_info->base_address + i + 12)); + } +} +#endif
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/rltk/8139/current/src/if_8139.h @@ -0,0 +1,366 @@ +#ifndef CYGONCE_DEVS_ETH_REALTEK_8139_INFO_H +#define CYGONCE_DEVS_ETH_REALTEK_8139_INFO_H +/*========================================================================== +// +// 8139_info.h +// +// +//========================================================================== +//####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): Eric Doenges +// Contributors: Chris Nimmers, Gary Thomas, Andy Dyer +// Date: 2003-07-09 +// Description: +// +//####DESCRIPTIONEND#### +*/ +#include <pkgconf/devs_eth_rltk_8139.h> + + +/* + * Used to define all vendor/device ID combinations we know about to find + * the chip. + */ +typedef struct { + cyg_uint16 vendor_id; + cyg_uint16 device_id; + void *data; +} pci_identifier_t; + +#define PCI_ANY_ID (0xFFFF) + +/* + * Valid receive buffer sizes are 8k+16, 16k+16, 32k+16, or 64k+16. + * For the last case, WRAP mode should not be enabled. Since we do not + * currently want to support unwrapped mode, do not use 64k+16 at this + * point. The buffer length is set via the configuration mechanism. + */ +#if (CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX < 0) |\ + (CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX > 2) +#error "The receive ring size index must be in the range of 0 to 2" +#endif +#define RX_BUF_LEN (8192 << (CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX)) +#define RX_BUF_PAD 16 +#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ +#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) + +/* Number of Tx descriptor registers. */ +#define NUM_TX_DESC 4 + +/* + * Max supported ethernet frame size. The 8139 cannot transmit packets more + * than 1792 bytes long. Also, since transmit buffers must be 32-bit + * aligned, MAX_ETH_FRAME_SIZE should always be a multiple of 4. + */ +#define MIN_ETH_FRAME_SIZE 60 /* without FCS */ +#define MAX_ETH_FRAME_SIZE 1536 /* is this with/without FCS ? */ + +/* Size of the Tx buffers. */ +#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE +#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) + +/* Rx buffer level before first PCI transfer ('5' is 512 bytes) */ +#define RX_FIFO_THRESH 5 + +/* + * Maximum PCI rx and tx bursts. This value ranges from '0' (16 bytes) + * to '7' (unlimited), with MXDMA = 2^(4 + 'value'). + */ +#define RX_DMA_BURST 6 +#define TX_DMA_BURST 6 + +/* + * Device driver private data + */ +typedef struct { + /* Device number. Used for actually finding the device */ + cyg_uint32 device_num; + + /* Receive buffer ring area */ + cyg_uint8 *rx_ring; + + /* Transmit buffer area */ + cyg_uint8 *tx_buffer; + + /* PCI device ID */ + cyg_pci_device_id pci_device_id; + + /* Address for memory mapped I/O */ + cyg_uint32 base_address; + + /* Our current MAC address */ + unsigned char mac[6]; + + /* tx FIFO threshold. */ + cyg_uint8 tx_threshold; + + /* This is the first free descriptor. */ + int tx_free_desc; + + /* This is the number of currently free descriptors */ + int tx_num_free_desc; + + /* Keys to match _send calls with the tx_done callback */ + unsigned long tx_desc_key[NUM_TX_DESC]; + + /* + * This is used to (temporarily) store the address of the current + * received packet. We save it here to avoid having to calculate it + * several times. + */ + cyg_uint8 *rx_current; + cyg_uint32 rx_size; + + /* Interrupt handling stuff */ + cyg_vector_t vector; + cyg_handle_t interrupt_handle; + cyg_interrupt interrupt; +} Rltk8139_t; + + +/* + * Register offsets and bit definitions. These use the names in the 8139 + * data sheet, not those found e.g. in the Linux driver for the 8139. + */ +enum { + IDR0 = 0x0, /* mac address, seemingly in big-endian order */ + IDR1 = 0x1, + IDR2 = 0x2, + IDR3 = 0x3, + IDR4 = 0x4, + IDR5 = 0x5, + MAR0 = 0x8, /* multicast registers (0-7) */ + MAR1 = 0x9, + MAR2 = 0xA, + MAR3 = 0xB, + MAR4 = 0xC, + MAR5 = 0xD, + MAR6 = 0xE, + MAR7 = 0xF, + TSD0 = 0x10, /* L, transmit status of descriptor 0 */ + TSD1 = 0x14, + TSD2 = 0x18, + TSD3 = 0x1C, + TSAD0 = 0x20, /* L, transmit start address of descriptor 0 */ + TSAD1 = 0x24, + TSAD2 = 0x28, + TSAD3 = 0x2C, + RBSTART = 0x30, /* L, receive buffer start address */ + ERBCR = 0x34, /* W, early receive byte count register */ + ERSR = 0x36, /* B, early receive status register */ + CR = 0x37, /* B, command register */ + CAPR = 0x38, /* W, current address of packet read */ + CBR = 0x3A, /* W, current buffer address */ + IMR = 0x3C, /* W, interrupt mask register */ + ISR = 0x3E, /* W, interrupt status register */ + TCR = 0x40, /* L, transmit configuration register */ + RCR = 0x44, /* L, receive configuration register */ + TCTR = 0x48, /* L, timer count register */ + MPC = 0x4C, /* L, missed packet counter */ + CR9346 = 0x50, /* B, 93C46 (serial eeprom) command register */ + CONFIG0 = 0x51, /* B, configuration register 0 */ + CONFIG1 = 0x52, /* B, configuration register 1 */ + TIMERINT= 0x54, /* L, timer interrupt register */ + MSR = 0x58, /* B, media status register */ + CONFIG3 = 0x59, /* B, configuration register 0 */ + CONFIG4 = 0x5A, /* B, configuration register 1 */ + MULINT = 0x5C, /* W, multiple interrupt select */ + RERID = 0x5E, /* B, PCI revision ID; should be 0x10 */ + TSAD = 0x60, /* W, transmit status of all descriptors */ + BMCR = 0x62, /* W, basic mode control register */ + BMSR = 0x64, /* W, basic mode status register */ + ANAR = 0x66, /* W, auto-negotiation advertisement register */ + ANLPAR = 0x68, /* W, auto-negotiation link partner register */ + ANER = 0x6A, /* W, auto-negotiation expansion register */ + DIS = 0x6C, /* W, disconnect counter */ + FCSC = 0x6E, /* W, false carrier sense counter */ + NWAYTR = 0x70, /* W, N-way test register */ + REC = 0x72, /* W, RX_ER counter */ + CSCR = 0x74, /* W, CS configuration register */ + PHY1_PARM = 0x78, /* L, PHY parameter 1 */ + TW_PARM = 0x7C, /* L, twister parameter */ + PHY2_PARM = 0x80, /* B, PHY parameter 2 */ + CRC0 = 0x84, /* B, power management CRC register for wakeup frame 0 */ + CRC1 = 0x85, /* B, power management CRC register for wakeup frame 1 */ + CRC2 = 0x86, /* B, power management CRC register for wakeup frame 2 */ + CRC3 = 0x87, /* B, power management CRC register for wakeup frame 3 */ + CRC4 = 0x88, /* B, power management CRC register for wakeup frame 4 */ + CRC5 = 0x89, /* B, power management CRC register for wakeup frame 5 */ + CRC6 = 0x8A, /* B, power management CRC register for wakeup frame 6 */ + CRC7 = 0x8B, /* B, power management CRC register for wakeup frame 7 */ + WAKEUP0 = 0x8C, /* Q, power management wakeup frame 0 (64 bits) */ + WAKEUP1 = 0x94, /* Q, power management wakeup frame 1 (64 bits) */ + WAKEUP2 = 0x9C, /* Q, power management wakeup frame 2 (64 bits) */ + WAKEUP3 = 0xA4, /* Q, power management wakeup frame 3 (64 bits) */ + WAKEUP4 = 0xAC, /* Q, power management wakeup frame 4 (64 bits) */ + WAKEUP5 = 0xB4, /* Q, power management wakeup frame 5 (64 bits) */ + WAKEUP6 = 0xBC, /* Q, power management wakeup frame 6 (64 bits) */ + WAKEUP7 = 0xC4, /* Q, power management wakeup frame 7 (64 bits) */ + LSBCRC0 = 0xCC, /* B, LSB of mask byte of wakeup frame 0 offset 12 to 75 */ + LSBCRC1 = 0xCD, /* B, LSB of mask byte of wakeup frame 1 offset 12 to 75 */ + LSBCRC2 = 0xCE, /* B, LSB of mask byte of wakeup frame 2 offset 12 to 75 */ + LSBCRC3 = 0xCF, /* B, LSB of mask byte of wakeup frame 3 offset 12 to 75 */ + LSBCRC4 = 0xD0, /* B, LSB of mask byte of wakeup frame 4 offset 12 to 75 */ + LSBCRC5 = 0xD1, /* B, LSB of mask byte of wakeup frame 5 offset 12 to 75 */ + LSBCRC6 = 0xD2, /* B, LSB of mask byte of wakeup frame 6 offset 12 to 75 */ + LSBCRC7 = 0xD3, /* B, LSB of mask byte of wakeup frame 7 offset 12 to 75 */ + FLASH = 0xD4, /* L, flash memory read/write register */ + CONFIG5 = 0xD8, /* B, configuration register #5 */ + FER = 0xF0, /* L, function event register (CardBus only) */ + FEMR = 0xF4, /* L, function event mask register (CardBus only) */ + FPSR = 0xF8, /* L, function present state register (CardBus only) */ + FFER = 0xFC /* L, function force event register (CardBus only) */ +}; + +/* Receive status register in Rx packet header */ +enum { + MAR = (1<<15), /* multicast address received */ + PAM = (1<<14), /* physical address matched */ + BAR = (1<<13), /* broadcast address received */ + ISE = (1<<5), /* invalid symbol error */ + RUNT = (1<<4), /* runt packet (<64 bytes) received */ + LONG = (1<<3), /* long packet (>4K bytes) received */ + CRC = (1<<2), /* CRC error */ + FAE = (1<<1), /* frame alignment error */ + ROK = (1<<0) /* receive OK */ +}; + +/* Transmit status register */ +enum { + CRS = (1<<31), /* carrier sense lost */ + TABT = (1<<30), /* transmit abort */ + OWC = (1<<29), /* out of window collision */ + CDH = (1<<28), /* CD heart beat */ + NCC_SHIFT = 24, + NCC = (0xF<<24), /* number of collision count */ + ERTXTH_SHIFT = 16, + ERTXTH = (0x1F<<16), /* early tx threshold, in multiples of 32 bytes */ + TOK = (1<<15), /* transmission OK */ + TUN = (1<<14), /* transmit FIFO underrun */ + OWN = (1<<13), /* own */ + SIZE = 0xFFF /* descriptor size */ +}; + +/* Command register */ +enum { + RST = (1<<4), /* reset */ + RE = (1<<3), /* receiver enable */ + TE = (1<<2), /* transmitter enable */ + BUFE = (1<<0) /* buffer empty */ +}; + +/* Transmit configuration register */ +enum { + CLRABT = (1<<0) /* clear abort */ +}; + +/* Receive configuration register */ +enum { + ERTH_SHIFT = 24, /* Early Rx threshold bits (4) */ + MULERINT = (1<<17), /* multiple early interrupt */ + RER8 = (1<<16), /* ? */ + RXFTH_SHIFT= 13, /* Rx FIFO threshold */ + RBLEN_SHIFT= 11, /* Rx buffer length */ + MXDMA_SHIFT= 8, /* max DMA burst size per Rx DMA burst */ + WRAP = (1<<7), /* WRAP mode */ + SEL9356 = (1<<6), /* EEPROM select */ + AER = (1<<5), /* accept error packets */ + AR = (1<<4), /* accept runt packets */ + AB = (1<<3), /* accept broadcast packets */ + AM = (1<<2), /* accept multicast packets */ + APM = (1<<1), /* accept physical match packets (our MAC) */ + AAP = (1<<0), /* accept physical address packets (any MAC) */ +}; + +/* TSAD (transmit status of all descriptors */ +enum { + TOK3 = (1<<15), + TOK2 = (1<<14), + TOK1 = (1<<13), + TOK0 = (1<<12), + TUN3 = (1<<11), + TUN2 = (1<<10), + TUN1 = (1<<9), + TUN0 = (1<<8), + TABT3 = (1<<7), + TABT2 = (1<<6), + TABT1 = (1<<5), + TABT0 = (1<<4), + OWN3 = (1<<3), + OWN2 = (1<<2), + OWN1 = (1<<1), + OWN0 = (1<<0) +}; + +/* Interrupt mask/status register */ +enum { + IR_SERR = (1<<15), /* system error interrupt */ + IR_TIMEOUT = (1<<14), /* time out interrupt */ + IR_LENCHG = (1<<13), /* cable length change interrupt */ + IR_FOVW = (1<<6), /* Rx FIFO overflow */ + IR_FUN = (1<<5), /* Packet underrun or link change interrupt */ + IR_RXOVW = (1<<4), /* Rx buffer overflow */ + IR_TER = (1<<3), /* transmit error interrupt */ + IR_TOK = (1<<2), /* transmit OK interrupt */ + IR_RER = (1<<1), /* receive error interrupt */ + IR_ROK = (1<<0) /* receive OK interrupt */ +}; + +/* Packet header bits */ +enum { + HDR_MAR = (1<<15), /* multicast address received */ + HDR_PAM = (1<<14), /* physical address matched */ + HDR_BAR = (1<<13), /* broadcast address matched */ + HDR_ISE = (1<<5), /* invalid symbol error */ + HDR_RUNT = (1<<4), /* runt packet received (packet < 64 bytes) */ + HDR_LONG = (1<<3), /* long packet (>4k) */ + HDR_CRC = (1<<2), /* CRC error */ + HDR_FAE = (1<<1), /* frame alignment error */ + HDR_ROK = (1<<0) /* receive OK */ +}; + + +/* + * Define some options to use + */ +#define TXCFG ((0x3 << 24) | (TX_DMA_BURST << MXDMA_SHIFT)) +#define RXCFG ((RX_FIFO_THRESH << RXFTH_SHIFT) |\ + (RX_BUF_LEN_IDX << RBLEN_SHIFT) |\ + (RX_DMA_BURST << MXDMA_SHIFT) |\ + WRAP | AB | APM) + +#endif /* ifndef CYGONCE_DEVS_ETH_REALTEK_8139_INFO_H */
--- a/packages/ecos.db +++ b/packages/ecos.db @@ -5260,6 +5260,44 @@ target moab { # -------------------------------------------------------------------------- +# Realtek 8139 (PCI) Ethernet driver +package CYGPKG_DEVS_ETH_RLTK_8139 { + alias { "Realtek 8139 ethernet driver" rltk8139_eth_driver } + hardware + directory devs/eth/rltk/8139 + script rltk_8139_eth_drivers.cdl + description "Ethernet driver for Realtek 8139 (PCI) card." +} + +package CYGPKG_DEVS_ETH_I386_PC_RLTK8139 { + alias { "Intel PC with Realtek 8139 ethernet driver" pc_rltk8139_eth_driver } + hardware + directory devs/eth/i386/pc/rltk8139 + script i386_pc_rltk8139_eth_drivers.cdl + description "Intel PC using Realtek 8139 (PCI) card." +} + +target pc_rltk8139 { + alias { "i386 PC target using Realtek 8139 networking" } + packages { CYGPKG_HAL_I386 + CYGPKG_HAL_I386_GENERIC + CYGPKG_HAL_I386_PC + CYGPKG_HAL_I386_PCMB + CYGPKG_IO_PCI + CYGPKG_IO_SERIAL_GENERIC_16X5X + CYGPKG_IO_SERIAL_I386_PC + CYGPKG_DEVS_ETH_RLTK_8139 + CYGPKG_DEVS_ETH_I386_PC_RLTK8139 + CYGPKG_DEVICES_WALLCLOCK_DALLAS_DS12887 + CYGPKG_DEVICES_WALLCLOCK_I386_PC + } + description " + The pc target provides the packages needed to run eCos binaries + on a standard i386 PC motherboard, using a Realtek 8139 network card." +} + +# -------------------------------------------------------------------------- + package CYGPKG_VNC_SERVER { alias { "VNC server" vnc_server } directory net/vnc_server
