From b0471864737545dcce55c30a784277ef9c5f9c44 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 14 Sep 2007 15:43:37 +0000 Subject: 2007-09-14 Kate Feng * Makefile.am, README, README.booting, README.irq, preinstall.am, GT64260/MVME5500I2C.c, include/bsp.h, irq/irq.c, irq/irq.h, irq/irq_init.c, pci/pci.c, pci/pci_interface.c, pci/pcifinddevice.c, start/preload.S, startup/bspclean.c, startup/bspstart.c, startup/pgtbl_activate.c, startup/reboot.c: Merge my improvements in this BSP including a new network driver for the 1GHz NIC. * network/if_100MHz/GT64260eth.c, network/if_100MHz/GT64260eth.h, network/if_100MHz/GT64260ethreg.h, network/if_100MHz/Makefile.am, network/if_1GHz/Makefile.am, network/if_1GHz/POSSIBLEBUG, network/if_1GHz/if_wm.c, network/if_1GHz/if_wmreg.h, network/if_1GHz/pci_map.c, network/if_1GHz/pcireg.h: New files. --- c/src/lib/libbsp/powerpc/mvme5500/ChangeLog | 15 + .../libbsp/powerpc/mvme5500/GT64260/MVME5500I2C.c | 9 +- c/src/lib/libbsp/powerpc/mvme5500/Makefile.am | 33 +- c/src/lib/libbsp/powerpc/mvme5500/README | 38 +- c/src/lib/libbsp/powerpc/mvme5500/README.booting | 26 +- c/src/lib/libbsp/powerpc/mvme5500/README.irq | 60 +- c/src/lib/libbsp/powerpc/mvme5500/include/bsp.h | 30 +- c/src/lib/libbsp/powerpc/mvme5500/irq/irq.c | 683 +++++---- c/src/lib/libbsp/powerpc/mvme5500/irq/irq.h | 32 +- c/src/lib/libbsp/powerpc/mvme5500/irq/irq_init.c | 144 +- .../mvme5500/network/if_100MHz/GT64260eth.c | 1575 ++++++++++++++++++++ .../mvme5500/network/if_100MHz/GT64260eth.h | 140 ++ .../mvme5500/network/if_100MHz/GT64260ethreg.h | 880 +++++++++++ .../powerpc/mvme5500/network/if_100MHz/Makefile.am | 46 + .../powerpc/mvme5500/network/if_1GHz/Makefile.am | 45 + .../powerpc/mvme5500/network/if_1GHz/POSSIBLEBUG | 4 + .../powerpc/mvme5500/network/if_1GHz/if_wm.c | 1556 +++++++++++++++++++ .../powerpc/mvme5500/network/if_1GHz/if_wmreg.h | 737 +++++++++ .../powerpc/mvme5500/network/if_1GHz/pci_map.c | 131 ++ .../powerpc/mvme5500/network/if_1GHz/pcireg.h | 384 +++++ c/src/lib/libbsp/powerpc/mvme5500/pci/pci.c | 9 +- .../libbsp/powerpc/mvme5500/pci/pci_interface.c | 69 +- .../libbsp/powerpc/mvme5500/pci/pcifinddevice.c | 47 +- c/src/lib/libbsp/powerpc/mvme5500/preinstall.am | 28 +- c/src/lib/libbsp/powerpc/mvme5500/start/preload.S | 70 +- .../lib/libbsp/powerpc/mvme5500/startup/bspclean.c | 2 + .../lib/libbsp/powerpc/mvme5500/startup/bspstart.c | 254 +--- .../powerpc/mvme5500/startup/pgtbl_activate.c | 48 +- c/src/lib/libbsp/powerpc/mvme5500/startup/reboot.c | 4 +- 29 files changed, 6197 insertions(+), 902 deletions(-) create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.c create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.h create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260ethreg.h create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/Makefile.am create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/Makefile.am create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/POSSIBLEBUG create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wm.c create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wmreg.h create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pci_map.c create mode 100644 c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pcireg.h diff --git a/c/src/lib/libbsp/powerpc/mvme5500/ChangeLog b/c/src/lib/libbsp/powerpc/mvme5500/ChangeLog index b95243e776..bf9d1c1454 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/ChangeLog +++ b/c/src/lib/libbsp/powerpc/mvme5500/ChangeLog @@ -1,3 +1,18 @@ +2007-09-14 Kate Feng + + * Makefile.am, README, README.booting, README.irq, + preinstall.am, GT64260/MVME5500I2C.c, include/bsp.h, irq/irq.c, + irq/irq.h, irq/irq_init.c, pci/pci.c, pci/pci_interface.c, + pci/pcifinddevice.c, start/preload.S, startup/bspclean.c, + startup/bspstart.c, startup/pgtbl_activate.c, startup/reboot.c: + Merge my improvements in this BSP including a new network + driver for the 1GHz NIC. + * network/if_100MHz/GT64260eth.c, network/if_100MHz/GT64260eth.h, + network/if_100MHz/GT64260ethreg.h, network/if_100MHz/Makefile.am, + network/if_1GHz/Makefile.am, network/if_1GHz/POSSIBLEBUG, + network/if_1GHz/if_wm.c, network/if_1GHz/if_wmreg.h, + network/if_1GHz/pci_map.c, network/if_1GHz/pcireg.h: New files. + 2007-04-06 Ralf Corsépius * bsp_specs: Remove lib (Now expected to exist in GCC). diff --git a/c/src/lib/libbsp/powerpc/mvme5500/GT64260/MVME5500I2C.c b/c/src/lib/libbsp/powerpc/mvme5500/GT64260/MVME5500I2C.c index ddfae32783..ff64924485 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/GT64260/MVME5500I2C.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/GT64260/MVME5500I2C.c @@ -12,23 +12,24 @@ */ #include /* printk */ -#include #include "bsp/GT64260TWSI.h" /* #define I2C_DEBUG*/ +typedef unsigned int u32; +typedef unsigned char unchar; -unsigned char I2cAddrPack(unsigned char busAddr,uint32_t offset) +unchar I2cAddrPack(unchar busAddr,u32 offset) { return(busAddr | ((offset & 0x700) >> 7)); } -unsigned char I2cDevByteAddr(uint32_t devA2A1A0, unsigned char byteNum) +unchar I2cDevByteAddr(u32 devA2A1A0, unchar byteNum) { return(( devA2A1A0 >>(byteNum*8)) & 0xff); } /**************************************************************************** * I2Cread_eeprom - read EEPROM VPD from the I2C */ -int I2Cread_eeprom(unsigned char I2cBusAddr,uint32_t devA2A1A0,uint32_t AddrBytes,unsigned char *pBuff,uint32_t numBytes) +int I2Cread_eeprom(unchar I2cBusAddr,u32 devA2A1A0,u32 AddrBytes,unchar *pBuff,u32 numBytes) { int status=0, lastByte=0; diff --git a/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am b/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am index 5476dcd93f..77f19d1c7b 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am +++ b/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am @@ -7,6 +7,9 @@ ACLOCAL_AMFLAGS = -I ../../../../aclocal include $(top_srcdir)/../../../../automake/compile.am include $(top_srcdir)/../../bsp.am +#prevent the compiler from generating FP instructions +AM_CFLAGS += -msoft-float + dist_project_lib_DATA = bsp_specs include_HEADERS = include/bsp.h @@ -29,6 +32,7 @@ EXTRA_DIST = startup/bootpstuff.c noinst_PROGRAMS += startup.rel startup_rel_SOURCES = startup/bspstart.c \ ../../powerpc/shared/startup/pgtbl_setup.c startup/pgtbl_activate.c \ + ../../powerpc/shared/startup/pretaskinghook.c \ ../../powerpc/shared/startup/sbrk.c ../../shared/bootcard.c \ startup/bspclean.c ../../shared/bsplibc.c ../../shared/bsppost.c \ ../../shared/main.c ../../shared/gnatinstallhandler.c startup/reboot.c @@ -42,8 +46,8 @@ pclock_rel_CPPFLAGS = $(AM_CPPFLAGS) pclock_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) ### -include_bsp_HEADERS = ../../powerpc/shared/console/uart.h \ - ../../shared/vmeUniverse/vme_am_defs.h +include_bsp_HEADERS = ../../powerpc/shared/console/uart.h +include_bsp_HEADERS += ../../powerpc/shared/console/consoleIo.h noinst_PROGRAMS += console.rel console_rel_SOURCES = ../../powerpc/shared/console/uart.c \ @@ -64,7 +68,7 @@ pci_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) include_bsp_HEADERS += irq/irq.h noinst_PROGRAMS += irq.rel -irq_rel_SOURCES = irq/irq_init.c irq/GT64260Int.c irq/irq.c \ +irq_rel_SOURCES = irq/irq_init.c irq/irq.c \ ../../powerpc/shared/irq/irq_asm.S irq_rel_CPPFLAGS = $(AM_CPPFLAGS) irq_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) @@ -97,27 +101,28 @@ GT64260_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) ## if HAS_NETWORKING -include_bsp_HEADERS += network/GT64260eth.h network/GT64260ethreg.h +include_bsp_HEADERS += network/if_100MHz/GT64260eth.h network/if_100MHz/GT64260ethreg.h \ + network/if_1GHz/if_wmreg.h network/if_1GHz/pcireg.h network_CPPFLAGS = -D_KERNEL noinst_PROGRAMS += network.rel -network_rel_SOURCES = network/GT64260eth.c +network_rel_SOURCES = network/if_100MHz/GT64260eth.c \ + network/if_1GHz/if_wm.c network/if_1GHz/pci_map.c network_rel_CPPFLAGS = $(AM_CPPFLAGS) $(network_CPPFLAGS) network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) endif -## -include_bsp_HEADERS += ../../shared/vmeUniverse/VME.h vme/VMEConfig.h -include_bsp_HEADERS += ../../shared/vmeUniverse/vmeUniverse.h \ +##vme +include_bsp_HEADERS += ../../shared/vmeUniverse/VME.h vme/VMEConfig.h \ + ../../shared/vmeUniverse/vmeUniverse.h \ ../../shared/vmeUniverse/vmeUniverseDMA.h\ ../../shared/vmeUniverse/bspVmeDmaList.h\ - ../../shared/vmeUniverse/VMEDMA.h + ../../shared/vmeUniverse/VMEDMA.h \ + ../../shared/vmeUniverse/vme_am_defs.h noinst_PROGRAMS += vme.rel -vme_rel_SOURCES = ../../shared/vmeUniverse/vmeUniverse.c -vme_rel_SOURCES+= ../../shared/vmeUniverse/bspVmeDmaList.c -vme_rel_SOURCES+= ../shared/vme/vmeconfig.c -vme_rel_SOURCES+= ../shared/vme/vme_universe.c -vme_rel_SOURCES+= ../shared/vme/vme_universe_dma.c +vme_rel_SOURCES = ../../shared/vmeUniverse/vmeUniverse.c\ + ../shared/vme/vmeconfig.c ../../shared/vmeUniverse/bspVmeDmaList.c\ + ../shared/vme/vme_universe.c ../shared/vme/vme_universe_dma.c vme_rel_CPPFLAGS = $(AM_CPPFLAGS) vme_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) diff --git a/c/src/lib/libbsp/powerpc/mvme5500/README b/c/src/lib/libbsp/powerpc/mvme5500/README index 7d8b915fa4..75da1b6aa9 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/README +++ b/c/src/lib/libbsp/powerpc/mvme5500/README @@ -1,7 +1,40 @@ # -# $Id$ +# $Id: README,v 1.3.1 Shuchen Kate Feng, NSLS, BNL (08/27/07) # +Please reference README.booting for the boot/load process. + +For the priority setting of the Interrupt Requests (IRQs), please +reference README.irq + +The BSP is built and tested on the 4.7.1 and 4.7.99.2 CVS RTEMS release. + +I believe in valuable real-time programming, where technical neatness, +performance and truth are. Any suggestion, bug reports, or even bug +fixes (great!) are welcome so that I still believe what I believe. + + +ACKNOWLEDGEMENTS +---------------- +Acknowledgements: + +Valuable information was obtained from the following: +1) Marvell NDA document for the discovery system controller. +Other related documents are listed at : +http://www.aps.anl.gov/epics/meetings/2006-06/RTEMS_Primer_SIG/RTEMS_BSP_MVME5500.pdf +2) netBSD: For the two NICS and some headers : + Allegro Networks, Inc., Wasabi Systems, Inc. +3) RTEMS: For the SVGM5 BSP + Stanford Linear Accelerator Center, Till Straumann + + This BSP also builds on top of the work of others who have contributed + to similar RTEMS powerpc shared and motorola_powerpc BSPs, most notably + Eric Valette, Till Straumann, Eric Norum and others. + +LICENSE +------- +See ./LICENSE file. + BSP NAME: mvme5500 BOARD: MVME5500 by Motorola BUS: PCI @@ -12,9 +45,6 @@ MODE: 32/64 bit mode (support 32 bit for now) DEBUG MONITOR: MOTLoad SYSTEM CONTROLLER: GT64260B -OTHER README FILES: README.booting,README.rtems-4.6.0-patch,README.VME, - README.irq - PERIPHERALS =========== TIMERS: Eight, 32 bit programmable diff --git a/c/src/lib/libbsp/powerpc/mvme5500/README.booting b/c/src/lib/libbsp/powerpc/mvme5500/README.booting index 4a33d7fcc7..19e9567908 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/README.booting +++ b/c/src/lib/libbsp/powerpc/mvme5500/README.booting @@ -1,18 +1,15 @@ -README.booting: written by S. Kate Feng , 2004/10/11 +README.booting: written by S. Kate Feng , Aug. 28, 2007 The bootloader is adapted from Till Straumann's Generic Mini-loader, -which he wrote originally for the SVGM powerpc board. Part of the -BSP was derived from the "RTEMS-PowerPC BSPs" and the NetBSD projects. -As of today, the BSP is built and tested on the RTEMS-4.6.0 -release with small patches I added (see README.rtems-4.6.0-patch -and rtems-4.6.0-patch/ directory). - +which he wrote originally for the SVGM powerpc board. +The BSP is built and tested on the 4.7 CVS RTEMS release. Booting requirement : ------------------------- -1) One needs to setup BOOTP/DHCP and TFTP servers and /etc/bootptab - properly to boot the system. (Note : EPICS needs a NTP server). +1) One needs to setup BOOTP/DHCP and TFTP servers and /etc/bootptab(BOOTP) + or /etc/dhcpd.conf (DHCP) properly to boot the system. + (Note : EPICS needs a NTP server). 2) Please copy the prebuilt RTEMS binary (e.g. misc/rtems5500-cexp.bin) and perhaps others (e.g. misc/st.sys) to the /tftpboot/epics/hostname/bin/ @@ -35,8 +32,10 @@ MVME5500> Note : (cxx.xx.xx.xx is the client IP address and sxx.xx.xx.xx is the server IP address) -4) Other reference web sites: +4) Other reference web sites for mvme5500 BSP: http://lansce.lanl.gov/EPICS/presentations/KateFeng%20RTEMS-mvme55001.ppt +http://www.nsls.bnl.gov/facility/expsys/software/EPICS/ +http://www.nsls.bnl.gov/facility/expsys/software/EPICS/FAQ.txt 5) When generating code (especially C++) for this system, one should use at least gcc-3.2 (preferrably a copy downloaded from the RTEMS @@ -53,10 +52,3 @@ other useful utilities such as telnet, nfs, and so on. tools and BSP, I would recommend one to reference http://www.aps.anl.gov/epics/base/RTEMS/tutorial/ in additional to the RTEMS document. - - -TODO lists: -1) 1 GHZ ethernet ( work in progress, to be released soon) -2) To measure the interrupt latency and context switching. -3) To implement the watchdog timer. - diff --git a/c/src/lib/libbsp/powerpc/mvme5500/README.irq b/c/src/lib/libbsp/powerpc/mvme5500/README.irq index 3ebf672b3f..fb31c4a5c3 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/README.irq +++ b/c/src/lib/libbsp/powerpc/mvme5500/README.irq @@ -1,52 +1,20 @@ -README.irq : Shuchen Kate Feng , 10/10/04 +README.irq : Shuchen Kate Feng , Sept. 2, 2007 - -The BSPirqPrioTable[] listed in irq_init.c is where the +As per implementation in shared PPC code, +the BSPirqPrioTable[96] listed in irq_init.c is where the software developers can change the levels of priority -for main interrupts based on the need of their -applications. - - -Presently, a dynamic IRQ table (e.g. mainIrqTbl[64]), which is -arranged dynamically based on the priority levels of enabled -main interrupts, is used in C_dispatch_irq_handler() to -incorporate the handling of the software priority levels. - - -The valid entries listed in mainIrqTbl[64] by the BSP are: - -1. Main interrupt 59 (GPP31_24 : no enabled IRQ yet, - to enable 'watchdog timer' if needed) -2. Main interrupt 57 (GPP15_8 : VME interrupt enabled, - to enable 'PMC1' if needed) -3. Main interrupt 58 (GPP23_16 : no enabled IRQ yet, - to enable '1 GHZ ethernet' or 'PMC2' - if needed) -4. Main interrupt 32 (10/100 MHZ ethernet) -5. Main interrupt 56 (GPP7_0 : presently only COM1/COM2 enabled) - - -The main IRQs can be added to the mainIrqTbl[] dynamically -via the BSP_enable_main_irq(), or removed from the mainIrqTbl[] -dynamically via the BSP_disable_main_irq(). - - -Regarding other GPP interrupts not listed in the GPP7_0IrqTbl[8], -GPP15_8IrqTbl[8], GPP23_16IrqTbl[8], or GPP31_24IrqTbl[8], they -could be enabled by being added to the correspondent of -the four aforementioned tables listed in the irq_init.c. - +for all the interrupts based on the need of their +applications. The IRQs can be eanbled dynamically via the +BSP_enable_pic_irq(), or disbaled dynamically via the +BSP_disable_pic_irq(). -Caveat: Presently, the eight GPP IRQs for each BSP_MAIN_GPPx_y_IRQ group -are set at the same main priority in the BSPirqPrioTable[], while the -sub-priority levels for the eight GPP in each group are sorted -statically by developers in the GPPx_yIrqTbl[8] from the highest -priority to the lowest one. +Support for run-time priority setup could be +added easily, but there is no action taken yet due to concerns +over computer security at VME CPU level. -Note : -1. GPP7-0 (Main interrupt high cause, bit 24) -2. GPP15-8 (Main interrupt high cause, bit 25) -3. GPP23-16 (Main interrupt high cause, bit 26) -4. GPP31-24 (Main interrupt high cause, bit 27) +The software developers are forbidden to setup picIsrTable[], +as it is a powerful engine for the BSP to find the pending +highest priority IRQ at run time. It ensures the fastest/faster +interrupt service to the highest/higher priority IRQ, if pending. diff --git a/c/src/lib/libbsp/powerpc/mvme5500/include/bsp.h b/c/src/lib/libbsp/powerpc/mvme5500/include/bsp.h index e119615e56..847b4a59e4 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/include/bsp.h +++ b/c/src/lib/libbsp/powerpc/mvme5500/include/bsp.h @@ -7,7 +7,7 @@ * found in found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * - * S. Kate Feng 12/03 : Modified it to support the MVME5500 board. + * S. Kate Feng 2003-2007 : Modified it to support the mvme5500 BSP. * */ @@ -53,14 +53,13 @@ #define BSP_MAX_PCI_BUS (BSP_MAX_PCI_BUS_ON_PCI0+BSP_MAX_PCI_BUS_ON_PCI1) -#if 0 -/* T.S, 2007/1: in order to let the universe acknowledge the interrupt - * (this allows for VME software priorities) corresponding support - * **MUST** be present in the interrupt controller driver - * Unless that's implemented DO NOT define BSP_PIC_DO_EOI. +/* The glues to Till's vmeUniverse, although the name does not + * actually reflect the relevant architect of the MVME5500. + * Till TODO ? : BSP_PCI_DO_EOI instead ? + * BSP_EXT_IRQ0 instead of BSP_PCI_IRQ0 ? + * */ #define BSP_PIC_DO_EOI inl(0xc34) /* PCI IACK */ -#endif #define BSP_PCI_IRQ0 BSP_GPP_IRQ_LOWEST_OFFSET /* @@ -111,11 +110,28 @@ extern int BSP_connect_clock_handler (void); extern unsigned long _BSP_clear_hostbridge_errors(); +extern unsigned int BSP_heap_start; + +#if 1 #define RTEMS_BSP_NETWORK_DRIVER_NAME "gt1" #define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_GT64260eth_driver_attach +#else +#define RTEMS_BSP_NETWORK_DRIVER_NAME "wmG1" +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_i82544EI_driver_attach +#endif extern int RTEMS_BSP_NETWORK_DRIVER_ATTACH(/* struct rtems_bsdnet_ifconfig * */); +#define gccMemBar() RTEMS_COMPILER_MEMORY_BARRIER() + +static inline void memBar() +{ + asm volatile("sync":::"memory"); +} +static inline void ioBar() +{ + asm volatile("eieio":::"memory"); +} #endif diff --git a/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.c b/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.c index 9c22dcb167..a4a82448f4 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.c @@ -6,14 +6,20 @@ * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. + * http://www.OARcorp.com/rtems/license.html. * - * Special acknowledgement to Till Straumann - * for providing inputs to the IRQ handling and optimization. + * Acknowledgement May 2004 : to Till Straumann + * for some inputs. * - * Modified and added support for the MVME5500 board - * Copyright 2003, 2004, Shuchen Kate Feng , + * Copyright 2003, 2004, 2005, 2007 Shuchen Kate Feng , * NSLS,Brookhaven National Laboratory + * 1) Modified and added support for the MVME5500 board. + * 2) The implementation of picIsrTable[] is an original work by the + * author to optimize the software IRQ priority scheduling because + * Discovery controller does not provide H/W IRQ priority schedule. + * It ensures the fastest/faster interrupt service to the + * highest/higher priority IRQ, if pendig. + * 3) _CPU_MSR_SET() needs RTEMS_COMPILER_MEMORY_BARRIER() * */ @@ -23,7 +29,9 @@ #include #include #include +#include #include +#include #include #include /* for printk */ @@ -31,20 +39,35 @@ #define HI_INT_CAUSE 0x40000000 -/*#define DEBUG*/ +#define MAX_IRQ_LOOP 30 -int gpp_int_error =0; +#define EDGE_TRIGGER + +#define _MSR_GET( _mask) \ + do { \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + _CPU_MSR_GET( _mask); \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + } while (0); + +#define _MSR_SET( _mask) \ + do { \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + _CPU_MSR_SET( _mask); \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + } while (0); + +/* #define DEBUG_IRQ*/ /* * pointer to the mask representing the additionnal irq vectors * that must be disabled when a particular entry is activated. - * They will be dynamically computed from teh prioruty table given + * They will be dynamically computed from the table given * in BSP_rtems_irq_mngt_set(); * CAUTION : this table is accessed directly by interrupt routine * prologue. */ -static unsigned int irq_prio_maskLO_tbl[BSP_MAIN_IRQ_NUMBER]; -static unsigned int irq_prio_maskHI_tbl[BSP_MAIN_IRQ_NUMBER]; +static unsigned int BSP_irq_prio_mask_tbl[3][BSP_PIC_IRQ_NUMBER]; /* * default handler connected on each irq after bsp initialization @@ -58,26 +81,55 @@ static rtems_irq_connect_data default_rtems_entry; static rtems_irq_global_settings* internal_config; static rtems_irq_connect_data* rtems_hdl_tbl; -static unsigned int irqCAUSE[20], irqLOW[20], irqHIGH[20]; -static int irqIndex=0; +static volatile unsigned *BSP_irqMask_reg[3]; +static volatile unsigned *BSP_irqCause_reg[3]; +static volatile unsigned BSP_irqMask_cache[3]={0,0,0}; -/* - * Check if IRQ is a MAIN CPU internal IRQ + +static int picIsrTblPtr=0; +static unsigned int GPPIrqInTbl=0; +static unsigned long long MainIrqInTbl=0; + +/* + * The software developers are forbidden to setup picIsrTable[], + * as it is a powerful engine for the BSP to find the pending + * highest priority IRQ at run time. It ensures the fastest/faster + * interrupt service to the highest/higher priority IRQ, if pendig. + * + * The picIsrTable[96] is updated dynamically at run time + * based on the priority levels set at BSPirqPrioTable[96], + * while the BSP_enable_pic_irq(), and BSP_disable_pic_irq() + * commands are invoked. + * + * The picIsrTable[96] lists the enabled CPU main and GPP external interrupt + * numbers [0 (lowest)- 95 (highest)] starting from the highest priority + * one to the lowest priority one. The highest priority interrupt is + * located at picIsrTable[0], and the lowest priority interrupt is located + * at picIsrTable[picIsrTblPtr-1]. + * + * */ -static inline int is_main_irq(const rtems_irq_number irqLine) -{ - return (((int) irqLine <= BSP_MICH_IRQ_MAX_OFFSET) & - ((int) irqLine >= BSP_MICL_IRQ_LOWEST_OFFSET) - ); -} +/* BitNums for Main Interrupt Lo/High Cause and GPP, -1 means invalid bit */ +static unsigned int picIsrTable[BSP_PIC_IRQ_NUMBER]={ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1 }; + /* - * Check if IRQ is a GPP IRQ + * Check if IRQ is a MAIN CPU internal IRQ or GPP external IRQ */ -static inline int is_gpp_irq(const rtems_irq_number irqLine) +static inline int is_pic_irq(const rtems_irq_number irqLine) { return (((int) irqLine <= BSP_GPP_IRQ_MAX_OFFSET) & - ((int) irqLine >= BSP_GPP_IRQ_LOWEST_OFFSET) + ((int) irqLine >= BSP_MICL_IRQ_LOWEST_OFFSET) ); } @@ -91,104 +143,14 @@ static inline int is_processor_irq(const rtems_irq_number irqLine) ); } -#define GT_GPP_Int1_Cause GT_GPP_Interrupt_Cause+1 -#define GT_GPP_Int2_Cause GT_GPP_Interrupt_Cause+2 -#define GT_GPP_Int3_Cause GT_GPP_Interrupt_Cause+3 - -void GT_GPP_IntHandler0() -{ - - unsigned gppCause, irqNum, bitNum; - int i, found=0; - - gppCause = inb(GT_GPP_Interrupt_Cause) & GT_GPPirq_cache; - - for (i=0; GPP7_0IrqTbl[i]!=-1;i++){ - bitNum =GPP7_0IrqTbl[i]; - if (gppCause & (1<>8); - - for (i=0; GPP15_8IrqTbl[i]!=-1;i++){ - bitNum =GPP15_8IrqTbl[i]; - if (gppCause & (1<>16); - - for (i=0; GPP23_16IrqTbl[i]!=-1;i++){ - bitNum =GPP23_16IrqTbl[i]; - if (gppCause & (1<>24); - - for (i=0; GPP31_24IrqTbl[i]!=-1;i++){ - bitNum=GPP31_24IrqTbl[i]; - if (gppCause & (1< a equal priority. - */ - if (internal_config->irqPrioTbl [i] >= internal_config->irqPrioTbl [j]) { - irq_prio_mask |= (unsigned long long)(1LLU << j); - } + /* + * Mask interrupts at PIC level that have a lower priority + * or a equal priority. + */ + if (internal_config->irqPrioTbl [i] >= internal_config->irqPrioTbl [j]) + irq_prio_mask |= (unsigned long long)(1LLU << j); } + - irq_prio_maskLO_tbl[i] = irq_prio_mask & 0xffffffff; - irq_prio_maskHI_tbl[i] = (irq_prio_mask>>32) & 0xffffffff; + BSP_irq_prio_mask_tbl[0][i] = irq_prio_mask & 0xffffffff; + BSP_irq_prio_mask_tbl[1][i] = (irq_prio_mask>>32) & 0xffffffff; #ifdef DEBUG - printk("irq_mask_prio_tbl[%d]:0x%8x%8x\n",i,irq_prio_maskHI_tbl[i], - irq_prio_maskLO_tbl[i]); -#endif + printk("irq_mask_prio_tbl[%d]:0x%8x%8x\n",i,BSP_irq_prio_mask_tbl[1][i], + BSP_irq_prio_mask_tbl[0][i]); +#endif + + BSP_irq_prio_mask_tbl[2][i] = 1<irqPrioTbl [i] >= internal_config->irqPrioTbl [j]) + BSP_irq_prio_mask_tbl[2][i] |= 1 << (j-BSP_GPP_IRQ_LOWEST_OFFSET); + } + } } } + +static void UpdateMainIrqTbl(int irqNum) +{ + int i=0, j, shifted=0; + + switch (irqNum) { + case BSP_MAIN_GPP7_0_IRQ: + case BSP_MAIN_GPP15_8_IRQ: + case BSP_MAIN_GPP23_16_IRQ: + case BSP_MAIN_GPP31_24_IRQ: + return; /* Do nothing, let GPP take care of it */ + break; + } +#ifdef SHOW_MORE_INIT_SETTINGS + unsigned long val2, val1; +#endif + + /* If entry not in table*/ + if ( ((irqNumBSP_MICH_IRQ_MAX_OFFSET) && + (!(( 1 << (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)) & GPPIrqInTbl)))) + { + while ( picIsrTable[i]!=-1) { + if (internal_config->irqPrioTbl[irqNum]>internal_config->irqPrioTbl[picIsrTable[i]]) { + /* all other lower priority entries shifted right */ + for (j=picIsrTblPtr;j>i; j--) + picIsrTable[j]=picIsrTable[j-1]; + picIsrTable[i]=irqNum; + shifted=1; + break; + } + i++; + } + if (!shifted) picIsrTable[picIsrTblPtr]=irqNum; + if (irqNum >BSP_MICH_IRQ_MAX_OFFSET) + GPPIrqInTbl |= (1<< (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)); + else + MainIrqInTbl |= (unsigned long long)(1LLU << irqNum); + picIsrTblPtr++; + } +#ifdef SHOW_MORE_INIT_SETTINGS + val2 = (MainIrqInTbl>>32) & 0xffffffff; + val1 = MainIrqInTbl&0xffffffff; + printk("irqNum %d, MainIrqInTbl 0x%x%x\n", irqNum, val2, val1); + BSP_printPicIsrTbl(); +#endif + +} + + +static void CleanMainIrqTbl(int irqNum) +{ + int i, j; + + switch (irqNum) { + case BSP_MAIN_GPP7_0_IRQ: + case BSP_MAIN_GPP15_8_IRQ: + case BSP_MAIN_GPP23_16_IRQ: + case BSP_MAIN_GPP31_24_IRQ: + return; /* Do nothing, let GPP take care of it */ + break; + } + if ( ((irqNumBSP_MICH_IRQ_MAX_OFFSET) && + (( 1 << (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)) & GPPIrqInTbl))) + { /* If entry in table*/ + for (i=0; i<64; i++) { + if (picIsrTable[i]==irqNum) {/*remove it from the entry */ + /* all other lower priority entries shifted left */ + for (j=i;jBSP_MICH_IRQ_MAX_OFFSET) + GPPIrqInTbl &= ~(1<< (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)); + else + MainIrqInTbl &= ~(1LLU << irqNum); + picIsrTblPtr--; + break; + } + } + } +} + +void BSP_enable_pic_irq(const rtems_irq_number irqNum) +{ + unsigned bitNum, regNum; + unsigned int level; + + bitNum = modIrq32(((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET); + regNum = divIrq32(((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET); + + rtems_interrupt_disable(level); + + UpdateMainIrqTbl((int) irqNum); + BSP_irqMask_cache[regNum] |= (1 << bitNum); + + out_le32(BSP_irqMask_reg[regNum], BSP_irqMask_cache[regNum]); + while (in_le32(BSP_irqMask_reg[regNum]) != BSP_irqMask_cache[regNum]); + + rtems_interrupt_enable(level); +} + +void BSP_disable_pic_irq(const rtems_irq_number irqNum) +{ + unsigned bitNum, regNum; + unsigned int level; + + bitNum = modIrq32(((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET); + regNum = divIrq32(((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET); + + rtems_interrupt_disable(level); + + CleanMainIrqTbl((int) irqNum); + BSP_irqMask_cache[regNum] &= ~(1 << bitNum); + + out_le32(BSP_irqMask_reg[regNum], BSP_irqMask_cache[regNum]); + while (in_le32(BSP_irqMask_reg[regNum]) != BSP_irqMask_cache[regNum]); + + rtems_interrupt_enable(level); +} + +int BSP_setup_the_pic() /* adapt the same name as shared/irq */ +{ + int i; + + /* Get ready for discovery BSP */ + BSP_irqMask_reg[0]= (volatile unsigned int *) (GT64260_REG_BASE + GT_CPU_INT_MASK_LO); + BSP_irqMask_reg[1]= (volatile unsigned int *) (GT64260_REG_BASE + GT_CPU_INT_MASK_HI); + BSP_irqMask_reg[2]= (volatile unsigned int *) (GT64260_REG_BASE + GT_GPP_Interrupt_Mask); + + BSP_irqCause_reg[0]= (volatile unsigned int *) (GT64260_REG_BASE + GT_MAIN_INT_CAUSE_LO); + BSP_irqCause_reg[1]= (volatile unsigned int *) (GT64260_REG_BASE + GT_MAIN_INT_CAUSE_HI); + BSP_irqCause_reg[2]= (volatile unsigned int *) (GT64260_REG_BASE + GT_GPP_Interrupt_Cause); + +#ifdef EDGE_TRIGGER + + /* Page 401, Table 598: + * Comm Unit Arbiter Control register : + * bit 10:GPP interrupts as level sensitive(1) or edge sensitive(0). + * We set the GPP interrupts to be edge sensitive. + * MOTload default is set as level sensitive(1). + */ + outl((inl(GT_CommUnitArb_Ctrl)& (~(1<<10))), GT_CommUnitArb_Ctrl); +#else + outl((inl(GT_CommUnitArb_Ctrl)| (1<<10)), GT_CommUnitArb_Ctrl); +#endif + +#if 0 + printk("BSP_irqMask_reg[0] = 0x%x, BSP_irqCause_reg[0] 0x%x\n", + in_le32(BSP_irqMask_reg[0]), + in_le32(BSP_irqCause_reg[0])); + printk("BSP_irqMask_reg[1] = 0x%x, BSP_irqCause_reg[1] 0x%x\n", + in_le32(BSP_irqMask_reg[1]), + in_le32(BSP_irqCause_reg[1])); + printk("BSP_irqMask_reg[2] = 0x%x, BSP_irqCause_reg[2] 0x%x\n", + in_le32(BSP_irqMask_reg[2]), + in_le32(BSP_irqCause_reg[2])); +#endif + + /* Initialize the interrupt related GT64260 registers */ + for (i=0; i<3; i++) { + out_le32(BSP_irqCause_reg[i], 0); + out_le32(BSP_irqMask_reg[i], 0); + } + in_le32(BSP_irqMask_reg[2]); + compute_pic_masks_from_prio(); + +#if 0 + printk("BSP_irqMask_reg[0] = 0x%x, BSP_irqCause_reg[0] 0x%x\n", + in_le32(BSP_irqMask_reg[0]), + in_le32(BSP_irqCause_reg[0])); + printk("BSP_irqMask_reg[1] = 0x%x, BSP_irqCause_reg[1] 0x%x\n", + in_le32(BSP_irqMask_reg[1]), + in_le32(BSP_irqCause_reg[1])); + printk("BSP_irqMask_reg[2] = 0x%x, BSP_irqCause_reg[2] 0x%x\n", + in_le32(BSP_irqMask_reg[2]), + in_le32(BSP_irqCause_reg[2])); +#endif + + /* + * + */ + for (i=BSP_MICL_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET ; i++) { + if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { + BSP_enable_pic_irq(i); + rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); + } + else { + rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); + BSP_disable_pic_irq(i); + } + } + + return(1); +} + /* * This function check that the value given for the irq line * is valid. @@ -260,9 +442,9 @@ int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) * RATIONALE : to always have the same transition by forcing the user * to get the previous handler before accepting to disconnect. */ - _CPU_ISR_Disable(level); + rtems_interrupt_disable(level); if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { - _CPU_ISR_Enable(level); + rtems_interrupt_enable(level); printk("IRQ vector %d already connected\n",irq->name); return 0; } @@ -271,35 +453,33 @@ int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) * store the data provided by user */ rtems_hdl_tbl[irq->name] = *irq; +#ifdef BSP_SHARED_HANDLER_SUPPORT + rtems_hdl_tbl[irq->name].next_handler = (void *)-1; +#endif - if (is_main_irq(irq->name)) { + if (is_pic_irq(irq->name)) { /* - * Enable (internal ) Main Interrupt Cause Low and High + * Enable PIC irq : Main Interrupt Cause Low and High & GPP external */ #ifdef DEBUG_IRQ - printk("main irq %d\n",irq->name); + printk("PIC irq %d\n",irq->name); #endif - BSP_enable_main_irq(irq->name); - } - - if (is_gpp_irq(irq->name)) { - /* - * Enable (external) GPP[x] interrupt - */ - BSP_enable_gpp_irq((int) irq->name); + BSP_enable_pic_irq(irq->name); } + else { + if (is_processor_irq(irq->name)) { + /* + * Enable exception at processor level + */ - if (is_processor_irq(irq->name)) { - /* - * Enable exception at processor level - */ + } } /* * Enable interrupt on device - - irq->on(irq);*/ + */ + irq->on(irq); - _CPU_ISR_Enable(level); + rtems_interrupt_enable(level); return 1; } @@ -331,24 +511,19 @@ int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { return 0; } - _CPU_ISR_Disable(level); + rtems_interrupt_disable(level); - if (is_main_irq(irq->name)) { - /* - * disable CPU main interrupt - */ - BSP_disable_main_irq(irq->name); - } - if (is_gpp_irq(irq->name)) { - /* - * disable external interrupt - */ - BSP_disable_gpp_irq(irq->name); - } - if (is_processor_irq(irq->name)) { - /* - * disable exception at processor level - */ + /* + * disable PIC interrupt + */ + if (is_pic_irq(irq->name)) + BSP_disable_pic_irq(irq->name); + else { + if (is_processor_irq(irq->name)) { + /* + * disable exception at processor level + */ + } } /* @@ -361,7 +536,8 @@ int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) */ rtems_hdl_tbl[irq->name] = default_rtems_entry; - _CPU_ISR_Enable(level); + + rtems_interrupt_enable(level); return 1; } @@ -372,8 +548,9 @@ int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) { - int i; unsigned int level; + int i; + /* * Store various code accelerators */ @@ -381,51 +558,17 @@ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) default_rtems_entry = config->defaultEntry; rtems_hdl_tbl = config->irqHdlTbl; - _CPU_ISR_Disable(level); - compute_GT64260int_masks_from_prio(); + rtems_interrupt_disable(level); - /* - * set up internal tables used by rtems interrupt prologue - */ - /* - * start with MAIN CPU IRQ - */ - for (i=BSP_MICL_IRQ_LOWEST_OFFSET; i < BSP_GPP_IRQ_LOWEST_OFFSET ; i++) { - if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { - BSP_enable_main_irq(i); - rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); - } - else { - rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); - BSP_disable_main_irq(i); - } - } - /* - * continue with external IRQ - */ - for (i=BSP_GPP_IRQ_LOWEST_OFFSET; i BSP_MICH_IRQ_MAX_OFFSET) + out_le32(BSP_irqCause_reg[2], ~bitmask);/* Till Straumann: Ack the edge triggered GPP IRQ */ #endif - oldMask[0]= GT_MAINirqLO_cache; - oldMask[1]= GT_MAINirqHI_cache; - - for (i=0;mainIrqTbl[i]!=-1;i++) { - irq=mainIrqTbl[i]; - if ( irq < startIrqNum ) continue; - regNum = irq/32; - bitNum = irq % 32; - if ( mainCause[regNum] & (1< It seems that reading back is necessary to ensure the - * interrupt mask updated. Otherwise, spurious interrupt will - * happen. However, I do not want to use "while loop" to risk - * the CPU stuck. I wound rather keep track of the interrupt - * mask if not updated. - */ - if (((irqLOW[irqIndex]= inl(GT_CPU_INT_MASK_LO))!=GT_MAINirqLO_cache)|| - ((irqHIGH[irqIndex]= inl(GT_CPU_INT_MASK_HI))!=GT_MAINirqHI_cache)){ - irqIndex++; - irqIndex %=20; - irqCAUSE[irqIndex] = irq; - } - _CPU_MSR_GET(msr); + + _MSR_GET(msr); new_msr = msr | MSR_EE; - _CPU_MSR_SET(new_msr); + _MSR_SET(new_msr); rtems_hdl_tbl[irq].hdl(rtems_hdl_tbl[irq].handle); - _CPU_MSR_SET(msr); + _MSR_SET(msr); + + for (j=0; j<3; j++ ) BSP_irqMask_cache[j] = oldMask[j]; break; } } - GT_MAINirqLO_cache=oldMask[0]; - outl(GT_MAINirqLO_cache, GT_CPU_INT_MASK_LO); - GT_MAINirqHI_cache=oldMask[1]; - outl(GT_MAINirqHI_cache, GT_CPU_INT_MASK_HI); + + out_le32((volatile unsigned *)0xf1000c1c, oldMask[0]); + out_le32((volatile unsigned *)0xf1000c6c, oldMask[1]); + out_le32((volatile unsigned *)0xf100f10c, oldMask[2]); + in_le32((volatile unsigned *)0xf100f10c); } void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx) @@ -535,10 +667,15 @@ void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx) */ } -void BSP_printIRQMask() +/* Only print part of the entries for now */ +void BSP_printPicIsrTbl() { int i; - for (i=0; i< 20; i++) - printk("IRQ%d : 0x%x %x \n", irqCAUSE[i], irqHIGH[i],irqLOW[i]); + printk("picIsrTable[12]={"); + for (i=0; i<12; i++) + printk("%d,", picIsrTable[i]); + printk("}\n"); + + printk("GPPIrqInTbl: 0x%x :\n", GPPIrqInTbl); } diff --git a/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.h b/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.h index e89ddf3220..9b7c21367e 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.h +++ b/c/src/lib/libbsp/powerpc/mvme5500/irq/irq.h @@ -15,12 +15,13 @@ * found in found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * - * Copyright 2004, Brookhaven National Laboratory and + * Copyright 2004, 2005 Brookhaven National Laboratory and * Shuchen Kate Feng * * - modified shared/irq/irq.h for Mvme5500 (no ISA devices/PIC) * - Discovery GT64260 interrupt controller instead of 8259. * - Added support for software IRQ priority levels. + * - modified to optimize the IRQ latency and handling * * $Id$ */ @@ -28,13 +29,14 @@ #ifndef LIBBSP_POWERPC_MVME5500_IRQ_IRQ_H #define LIBBSP_POWERPC_MVME5500_IRQ_IRQ_H +/*#define BSP_SHARED_HANDLER_SUPPORT 1*/ #include #define BSP_ASM_IRQ_VECTOR_BASE 0x0 #ifndef ASM -#define DynamicIrqTbl 1 +#define OneTierIrqPrioTbl 1 /* * Symbolic IRQ names and related definitions. @@ -83,7 +85,8 @@ * Summary */ #define BSP_IRQ_NUMBER (BSP_MISC_IRQ_MAX_OFFSET + 1) -#define BSP_MAIN_IRQ_NUMBER (64) +#define BSP_MAIN_IRQ_NUMBER (64) +#define BSP_PIC_IRQ_NUMBER (96) #define BSP_LOWEST_OFFSET (BSP_MICL_IRQ_LOWEST_OFFSET) #define BSP_MAX_OFFSET (BSP_MISC_IRQ_MAX_OFFSET) @@ -109,6 +112,7 @@ #define BSP_MAIN_GPP31_24_IRQ (BSP_MICH_IRQ_LOWEST_OFFSET+27) /* on the MVME5500, these are the GT64260B external GPP0 interrupt */ +#define BSP_PCI_IRQ_LOWEST_OFFSET (BSP_GPP_IRQ_LOWEST_OFFSET) #define BSP_UART_COM2_IRQ (BSP_GPP_IRQ_LOWEST_OFFSET) #define BSP_UART_COM1_IRQ (BSP_GPP_IRQ_LOWEST_OFFSET) #define BSP_GPP8_IRQ_OFFSET (BSP_GPP_IRQ_LOWEST_OFFSET+8) @@ -129,29 +133,7 @@ */ #define BSP_DECREMENTER (BSP_PROCESSOR_IRQ_LOWEST_OFFSET) -typedef unsigned int rtems_GTirq_masks; - -extern rtems_GTirq_masks GT_GPPirq_cache; -extern rtems_GTirq_masks GT_MAINirqLO_cache, GT_MAINirqHI_cache; - -void BSP_enable_main_irq(unsigned irqNum); -void BSP_disable_main_irq(unsigned irqNum); -void BSP_enable_gpp_irq(unsigned irqNum); -void BSP_disable_gpp_irq(unsigned irqNum); - extern void BSP_rtems_irq_mng_init(unsigned cpuId); -extern int gpp_int_error; -#if DynamicIrqTbl -extern int MainIrqTblPtr; -extern unsigned long long MainIrqInTbl; -extern unsigned char GPPinMainIrqTbl[4]; -#endif -extern unsigned int mainIrqTbl[64]; -extern unsigned int GPP7_0IrqTbl[8]; -extern unsigned int GPP15_8IrqTbl[8]; -extern unsigned int GPP23_16IrqTbl[8]; -extern unsigned int GPP31_24IrqTbl[8]; #endif - #endif diff --git a/c/src/lib/libbsp/powerpc/mvme5500/irq/irq_init.c b/c/src/lib/libbsp/powerpc/mvme5500/irq/irq_init.c index 6ebee01fa1..0902383d41 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/irq/irq_init.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/irq/irq_init.c @@ -5,16 +5,13 @@ * * CopyRight (C) 1999 valette@crf.canon.fr * - * Special acknowledgement to Till Straumann - * for providing inputs to the IRQ optimization. - * * Modified and added support for the MVME5500. - * Copyright 2003, 2004, Brookhaven National Laboratory and + * Copyright 2003, 2004, 2005, Brookhaven National Laboratory and * Shuchen Kate Feng * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. + * http://www.rtems.com/license/LICENSE * */ #include @@ -22,14 +19,12 @@ #include #include #include /* ASM_EXT_VECTOR, ASM_DEC_VECTOR ... */ +/*#define TRACE_IRQ_INIT*/ extern unsigned int external_exception_vector_prolog_code_size[]; extern void external_exception_vector_prolog_code(); extern unsigned int decrementer_exception_vector_prolog_code_size[]; extern void decrementer_exception_vector_prolog_code(); -extern void GT_GPP_IntHandler0(), GT_GPP_IntHandler1(); -extern void GT_GPP_IntHandler2(), GT_GPP_IntHandler3(); -extern void BSP_GT64260INT_init(); /* * default on/off function @@ -47,116 +42,49 @@ static int connected() {return 1;} static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; static rtems_irq_global_settings initial_config; static rtems_irq_connect_data defaultIrq = { - /* vectorIdex, hdl , handle , on , off , isOn */ - 0, nop_func , NULL , nop_func , nop_func , not_connected + /* vectorIdex, hdl , handle , on , off , isOn */ + 0, nop_func , NULL , nop_func , nop_func , not_connected }; -rtems_irq_prio BSPirqPrioTable[BSP_MAIN_IRQ_NUMBER]={ +rtems_irq_prio BSPirqPrioTable[BSP_PIC_IRQ_NUMBER]={ /* * This table is where the developers can change the levels of priority * based on the need of their applications. * - * actual priorities for CPU MAIN interrupts 0-63: + * actual priorities for CPU MAIN and GPP interrupts (0-95) + * * 0 means that only current interrupt is masked (lowest priority) - * 255 means all other interrupts are masked + * 255 is only used by bits 24, 25, 26 and 27 of the CPU high + * interrupt Mask: (e.g. GPP7_0, GPP15_8, GPP23_16, GPP31_24). + * The IRQs of those four bits are always enabled. When it's used, + * the IRQ number is never listed in the dynamic picIsrTable[96]. + * + * The priorities of GPP interrupts were decided by their own + * value set at BSPirqPrioTable. + * */ /* CPU Main cause low interrupt */ /* 0-15 */ - 0, 0, 0, 0, 0, 0, 0, 0, 4/*Timer*/, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 64/*Timer*/, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* CPU Main cause high interrupt */ /* 32-47 */ - 1/*10/100MHZ*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2/*10/100MHz*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 48-63 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0/*serial*/, 3/*VME*/, 2/*1GHZ*/, 5/*WD*/, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 255 /*GPP0-7*/, 255/*GPP8-15*/, 255/*GPP16-23*/, 255/*GPP24-31*/, 0, 0, 0, 0, + /* GPP interrupts */ + /* GPP0-7 */ + 1/*serial*/,0, 0, 0, 0, 0, 0, 0, + /* GPP8-15 */ + 47/*PMC1A*/,46/*PMC1B*/,45/*PMC1C*/,44/*PMC1D*/,30/*VME0*/, 29/*VME1*/,3,1, + /* GPP16-23 */ + 37/*PMC2A*/,36/*PMC2B*/,35/*PMC2C*/,34/*PMC2D*/,23/*1GHz*/, 0,0,0, + /* GPP24-31 */ + 7/*watchdog*/, 0,0,0,0,0,0,0 }; -/* The mainIrqTbl[64] lists the enabled CPU main interrupt - * numbers [0-63] starting from the highest priority one - * to the lowest priority one. - * - * The highest priority interrupt is located at mainIrqTbl[0], and - * the lowest priority interrupt is located at - * mainIrqTbl[MainIrqTblPtr-1]. - */ - -#if DynamicIrqTbl -/* The mainIrqTbl[64] is updated dynamically based on the priority - * levels set at BSPirqPrioTable[64], as the BSP_enable_main_irq() and - * BSP_disable_main_irq() commands are invoked. - * - * Caveat: The eight GPP IRQs for each BSP_MAIN_GPPx_y_IRQ group are set - * at the same main priority in the BSPirqPrioTable, while the - * sub-priority levels for the eight GPP in each group are sorted - * statically by developers in the GPPx_yIrqTbl[8] from the highest - * priority to the lowest one. - */ -int MainIrqTblPtr=0; -unsigned long long MainIrqInTbl=0; -unsigned char GPPinMainIrqTbl[4]={0,0,0,0}; -/* BitNums for Main Interrupt Lo/High Cause, -1 means invalid bit */ -unsigned int mainIrqTbl[BSP_MAIN_IRQ_NUMBER]={ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1}; -#else -/* Pre-sorted for IRQ optimization, and prioritization - * The interrupts sorted are : - - 1. Watchdog timer (GPP #25) - 2. Timers 0-1 (Main interrupt low cause, bit 8) - 3. VME interrupt (GPP #12) - 4. 1 GHZ ethernet (GPP #20) - 5. 10/100 MHZ ethernet (Main interrupt high cause, bit 0) - 6. COM1/COM2 (GPP #0) - -*/ -/* BitNums for Main Interrupt Lo/High Cause, -1 means invalid bit */ -unsigned int mainIrqTbl[64]={ BSP_MAIN_GPP31_24_IRQ, /* 59:watchdog timer */ - BSP_MAIN_TIMER0_1_IRQ, /* 8:Timers 0-1 */ - BSP_MAIN_GPP15_8_IRQ, /* 57:VME interrupt */ - BSP_MAIN_GPP23_16_IRQ, /* 58: 1 GHZ ethernet */ - BSP_MAIN_ETH0_IRQ, /* 32:10/100 MHZ ethernet */ - BSP_MAIN_GPP7_0_IRQ, /* 56:COM1/COM2 */ - -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1}; -#endif - -unsigned int GPP7_0IrqTbl[8]={0, /* COM1/COM2 */ - -1, -1, -1, -1, -1, -1, -1}; -unsigned int GPP15_8IrqTbl[8]={ 4, 5, 6, 7, /* VME interrupt 0-3 */ - 0, 1, 2, 3 /* PMC1 INT A, B, C, D */}; -unsigned int GPP23_16IrqTbl[8]={4, /* 82544 1GHZ ethernet (20-16=4)*/ - 0, 1, 2, 3, /* PMC2 INT A, B, C, D */ - -1, -1, -1}; -unsigned int GPP31_24IrqTbl[8]={1, /* watchdog timer (25-24=1) */ - -1, -1, -1, -1, -1, -1, -1}; - -static int -doit(unsigned intNum, rtems_irq_hdl handler, int (*p)(const rtems_irq_connect_data*)) -{ - rtems_irq_connect_data d={0}; - d.name = intNum; - d.isOn = connected; - d.hdl = handler; - return p(&d); -} - -int BSP_GT64260_install_isr(unsigned intNum,rtems_irq_hdl handler) -{ - return doit(intNum, handler, BSP_install_rtems_irq_handler); -} - /* * This code assumes the exceptions management setup has already * been done. We just need to replace the exceptions that will @@ -174,7 +102,6 @@ void BSP_rtems_irq_mng_init(unsigned cpuId) #ifdef TRACE_IRQ_INIT printk("Initializing the interrupt controller of the GT64260\n"); #endif - BSP_GT64260INT_init(); #ifdef TRACE_IRQ_INIT printk("Going to re-initialize the rtemsIrq table %d\n",BSP_IRQ_NUMBER); @@ -186,8 +113,8 @@ void BSP_rtems_irq_mng_init(unsigned cpuId) * re-init the rtemsIrq table */ for (i = 0; i < BSP_IRQ_NUMBER; i++) { - rtemsIrq[i] = defaultIrq; - rtemsIrq[i].name = i; + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; } /* @@ -209,13 +136,10 @@ void BSP_rtems_irq_mng_init(unsigned cpuId) */ BSP_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); } +#ifdef TRACE_IRQ_INIT + printk("Done setup irq mngt configuration\n"); +#endif - /* Connect the GPP int handler to each of the associated main cause bits */ - BSP_GT64260_install_isr(BSP_MAIN_GPP7_0_IRQ, GT_GPP_IntHandler0); /* COM1 & COM2, .... */ - BSP_GT64260_install_isr(BSP_MAIN_GPP15_8_IRQ, GT_GPP_IntHandler1); - BSP_GT64260_install_isr(BSP_MAIN_GPP23_16_IRQ, GT_GPP_IntHandler2); - BSP_GT64260_install_isr(BSP_MAIN_GPP31_24_IRQ, GT_GPP_IntHandler3); - /* * We must connect the raw irq handler for the two * expected interrupt sources : decrementer and external interrupts. diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.c b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.c new file mode 100644 index 0000000000..8ef16ce120 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.c @@ -0,0 +1,1575 @@ +/* GT64260eth.c : GT64260 10/100 Mb ethernet MAC driver + * + * Copyright (c) 2003,2004 Brookhaven National Laboratory + * S. Kate Feng + * All rights reserved + * + * Acknowledgements: + * netBSD : Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc. + * Marvell : NDA document for the discovery system controller + * The author referenced two RTEMS network drivers of other NICs. + * rtems : 1) dec21140.c, a network driver for for TULIP based Ethernet Controller + * (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr + * + * 2) yellowfin.c, a network driver for the SVGM5 BSP. + * Stanford Linear Accelerator Center, Till Straumann + * + * Some notes from the author, S. Kate Feng : + * + * 1) Mvme5500 uses Eth0 (controller 0) of the GT64260 to implement + * the 10/100 BaseT Ethernet with PCI Master Data Byte Swap\ + * control. + * 2) Implemented hardware snoop instead of software snoop + * to ensure SDRAM cache coherency. (Copyright : NDA item) + * 3) Added S/W support for multi mbuf. (TODO : Let the H/W do it) + * + */ +#define BYTE_ORDER BIG_ENDIAN + +#define INET + +#include +#include /* printk */ +#include /* printf for statistics */ +#include + +#include /* inp & friends */ +#include /* registers.h is included here */ +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include /* SIOCADDMULTI, SIOC... */ +#include +#include +#include +#include + +#ifdef INET +#include +#endif + +#include +#include +#include +#include + +#define GT_ETH_TASK_NAME "Geth" +#define PKT_BUF_SZ 1536 +#define SOFTC_ALIGN 31 +#define HASH_ALIGN 15 + +#define TXQ_HiLmt_OFF 2 + +/* + * 1. printk debug is for diagnosis only, which may cause + * unexpected result, especially if txq is under heavy load + * because CPU is fast with a decent cache. + */ +#define GTeth_debug 0 +#define GTeth_rx_debug 0 + +#if 0 +#define GE_FORGOT +#define GE_NORX +#define GT_DEBUG +#endif + +/* RTEMS event to kill the daemon */ +#define KILL_EVENT RTEMS_EVENT_1 +/* RTEMS event to (re)start the transmitter */ +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 +/* RTEMS events used by the ISR */ +#define RX_EVENT RTEMS_EVENT_3 +#define TX_EVENT RTEMS_EVENT_4 +#define ERR_EVENT RTEMS_EVENT_5 + +#define ALL_EVENTS (KILL_EVENT|START_TRANSMIT_EVENT|RX_EVENT|TX_EVENT|ERR_EVENT) + +enum GTeth_whack_op { + GE_WHACK_START, GE_WHACK_RESTART, + GE_WHACK_CHANGE, GE_WHACK_STOP +}; + +enum GTeth_hash_op { + GE_HASH_ADD, GE_HASH_REMOVE, +}; + +#define ET_MINLEN 64 /* minimum message length */ + +static int GTeth_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data); +static void GTeth_ifstart (struct ifnet *); +static void GTeth_ifchange(struct GTeth_softc *sc); +static void GTeth_init_rx_ring(struct GTeth_softc *sc); +static void GT64260eth_daemon(void *arg); +static int GT64260eth_sendpacket(struct GTeth_softc *sc,struct mbuf *m); +static unsigned GTeth_txq_done(struct GTeth_softc *sc); +static void GTeth_tx_cleanup(struct GTeth_softc *sc); +static void GTeth_tx_start(struct GTeth_softc *sc); +static void GTeth_tx_stop(struct GTeth_softc *sc); +static void GTeth_rx_cleanup(struct GTeth_softc *sc); +static int GT64260eth_rx(struct GTeth_softc *sc); +static void GTeth_rx_setup(struct GTeth_softc *sc); +static void GTeth_rxprio_setup(struct GTeth_softc *sc); +static void GTeth_rx_stop(struct GTeth_softc *dc); +static void GT64260eth_isr(); +static int GTeth_hash_compute(struct GTeth_softc *sc,unsigned char eaddr[ETHER_ADDR_LEN]); +static int GTeth_hash_entry_op(struct GTeth_softc *sc, enum GTeth_hash_op op, + enum GTeth_rxprio prio,unsigned char eaddr[ETHER_ADDR_LEN]); + +static int GTeth_hash_fill(struct GTeth_softc *sc); +static void GTeth_hash_init(struct GTeth_softc *sc); + +static struct GTeth_softc *root_GT64260eth_dev = NULL; + +static void GT64260eth_irq_on(const rtems_irq_connect_data *irq) +{ + struct GTeth_softc *sc; + + for (sc= root_GT64260eth_dev; sc; sc= sc-> next_module) { + outl(0x30883444,ETH0_EIMR); /* MOTLoad default interrupt mask */ + return; + } +} + +static void GT64260eth_irq_off(const rtems_irq_connect_data *irq) +{ + struct GTeth_softc *sc; + + for (sc= root_GT64260eth_dev; sc; sc= sc-> next_module) + outl(0, ETH0_EIMR); +} + +static int GT64260eth_irq_is_on(const rtems_irq_connect_data *irq) +{ + return(inl(ETH0_EICR) & ETH_IR_EtherIntSum); +} + +static void GT64260eth_isr() +{ + struct GTeth_softc *sc = root_GT64260eth_dev; + rtems_event_set events=0; + uint32_t cause; + + + cause = inl(ETH0_EICR); + outl( ~cause,ETH0_EICR); /* clear the ICR */ + + if ( (!cause) || (cause & 0x803d00)) { + sc->intr_errsts[sc->intr_err_ptr2++]=cause; + sc->intr_err_ptr2 %=INTR_ERR_SIZE; /* Till Straumann */ + events |= ERR_EVENT; + } + + /* ETH_IR_RxBuffer_3|ETH_IR_RxError_3 */ + if (cause & 0x880000) { + sc->stats.rxInterrupts++; + events |= RX_EVENT; + } + /* If there is an error, we want to continue to next descriptor */ + /* ETH_IR_TxBufferHigh|ETH_IR_TxEndHigh|ETH_IR_TxErrorHigh */ + if (cause & 0x444) { + sc->stats.txInterrupts++; + events |= TX_EVENT; + /* It seems to be unnecessary. However, it's there + * to be on the safe side due to the datasheet. + * So far, it does not seem to affect the network performance + * based on the EPICS catime. + */ + /* ETH_ESDCMR_TXDH | ETH_ESDCMR_ERD = 0x800080 */ + if ((sc->txq_nactive > 1)&& ((inl(ETH0_ESDCMR)Ð_ESDCMR_TXDH)==0)) + outl(0x800080,ETH0_ESDCMR); + + + } + rtems_event_send(sc->daemonTid, events); +} + +static rtems_irq_connect_data GT64260ethIrqData={ + BSP_MAIN_ETH0_IRQ, + (rtems_irq_hdl) GT64260eth_isr, + NULL, + (rtems_irq_enable) GT64260eth_irq_on, + (rtems_irq_disable) GT64260eth_irq_off, + (rtems_irq_is_enabled) GT64260eth_irq_is_on, +}; + +static void GT64260eth_init_hw(struct GTeth_softc *sc) +{ + +#ifdef GT_DEBUG + printk("GT64260eth_init_hw("); +#endif + /* Kate Feng : Turn the hardware snoop on as MOTLoad did not have + * it on by default. + */ + outl(RxBSnoopEn|TxBSnoopEn|RxDSnoopEn|TxDSnoopEn, GT_CUU_Eth0_AddrCtrlLow); + outl(HashSnoopEn, GT_CUU_Eth0_AddrCtrlHigh); + + sc->rxq_intrbits=0; + sc->sc_flags=0; + +#ifndef GE_NORX + GTeth_rx_setup(sc); +#endif + +#ifndef GE_NOTX + GTeth_tx_start(sc); +#endif + + sc->sc_pcr |= ETH_EPCR_HS_512; + outl(sc->sc_pcr, ETH0_EPCR); + outl(sc->sc_pcxr, ETH0_EPCXR); /* port config. extended reg. */ + outl(0, ETH0_EICR); /* interrupt cause register */ + outl(sc->sc_intrmask, ETH0_EIMR); +#ifndef GE_NOHASH + /* Port Hash Table Pointer Reg*/ + outl(((unsigned) sc->sc_hashtable),ETH0_EHTPR); +#endif +#ifndef GE_NORX + outl(ETH_ESDCMR_ERD,ETH0_ESDCMR); /* enable Rx DMA in SDMA Command Register */ + sc->sc_flags |= GE_RXACTIVE; +#endif +#ifdef GT_DEBUG + printk("SDCMR 0x%x ", inl(ETH0_ESDCMR)); +#endif + + /* connect the interrupt handler which should + * take care of enabling interrupts + */ + if (!BSP_install_rtems_irq_handler(>64260ethIrqData)) + printk("GT64260eth: unable to install ISR"); + + /* The ethernet port is ready to transmit/receive */ + outl(sc->sc_pcr | ETH_EPCR_EN, ETH0_EPCR); + +#ifdef GT_DEBUG + printk(")\n"); +#endif +} + +static void GT64260eth_stop_hw(struct GTeth_softc *sc) +{ + + printk("GT64260eth_stop_hw("); + + /* remove our interrupt handler which will also + * disable interrupts at the MPIC and the device + * itself + */ + if (!BSP_remove_rtems_irq_handler(>64260ethIrqData)) + printk("GT64260eth: unable to remove IRQ handler!"); + + outl(sc->sc_pcr, ETH0_EPCR); + outl(0, ETH0_EIMR); + + sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; +#ifndef GE_NOTX + GTeth_tx_stop(sc); +#endif +#ifndef GE_NORX + GTeth_rx_stop(sc); +#endif + sc->sc_hashtable = NULL; + if (GTeth_debug>0) printk(")"); +} + +static void GT64260eth_stop(struct GTeth_softc *sc) +{ + if (GTeth_debug>0) printk("GT64260eth_stop("); + + /* The hardware is shutdown in the daemon */ + /* kill the daemon. We also must release the networking + * semaphore or there'll be a deadlock... + */ + rtems_event_send(sc->daemonTid, KILL_EVENT); + rtems_bsdnet_semaphore_release(); + + sc->daemonTid=0; + /* now wait for it to die */ + rtems_semaphore_obtain(sc->daemonSync,RTEMS_WAIT,RTEMS_NO_TIMEOUT); + + /* reacquire the bsdnet semaphore */ + rtems_bsdnet_semaphore_obtain(); + if (GTeth_debug>0) printk(")"); +} + +static void GT64260eth_ifinit(void *arg) +{ + struct GTeth_softc *sc = (struct GTeth_softc*)arg; + int i; + +#ifdef GT_DEBUG + printk("GT64260eth_ifinit(): daemon ID: 0x%08x)\n", sc->daemonTid); +#endif + if (sc->daemonTid) { +#ifdef GT_DEBUG + printk("GT64260eth: daemon already up, doing nothing\n"); +#endif + return; + } + +#ifndef GE_NOHASH + /* Mvme5500, the user must initialize the hash table before enabling the + * Ethernet controller + */ + GTeth_hash_init(sc); + GTeth_hash_fill(sc); +#endif + + sc->intr_err_ptr1=0; + sc->intr_err_ptr2=0; + for (i=0; i< INTR_ERR_SIZE; i++) sc->intr_errsts[i]=0; + + /* initialize the hardware (we are holding the network semaphore at this point) */ + (void)GT64260eth_init_hw(sc); + + /* launch network daemon */ + + /* NOTE: + * in ss-20011025 (and later) any task created by 'bsdnet_newproc' is + * wrapped by code which acquires the network semaphore... + */ + sc->daemonTid = rtems_bsdnet_newproc(GT_ETH_TASK_NAME,4096,GT64260eth_daemon,arg); + + /* Tell the world that we're running */ + sc->arpcom.ac_if.if_flags |= IFF_RUNNING; + +} + +/* attach parameter tells us whether to attach or to detach the driver */ +/* Attach this instance, and then all the sub-devices */ +int rtems_GT64260eth_driver_attach(struct rtems_bsdnet_ifconfig *config, int attach) +{ + struct GTeth_softc *sc; + struct ifnet *ifp; + unsigned sdcr, data; + unsigned char hwaddr[6]; + int i, unit, phyaddr; + void *softc_mem; + char *name; + + unit = rtems_bsdnet_parse_driver_name(config, &name); + if (unit < 0) return 0; + + printk("\nEthernet driver name %s unit %d \n",name, unit); + printk("(c) 2004, Brookhaven National Lab. (RTEMS/mvme5500 port)\n"); + + /* Make certain elements e.g. descriptor lists are aligned. */ + softc_mem = rtems_bsdnet_malloc(sizeof(*sc) + SOFTC_ALIGN, M_FREE, M_NOWAIT); + + /* Check for the very unlikely case of no memory. */ + if (softc_mem == NULL) + printk("GT64260eth: OUT OF MEMORY"); + + sc = (void *)(((long)softc_mem + SOFTC_ALIGN) & ~SOFTC_ALIGN); + memset(sc, 0, sizeof(*sc)); + + if (GTeth_debug>0) printk("txq_desc[0] addr:%x, rxq_desc[0] addr:%x, sizeof sc %d\n",&sc->txq_desc[0], &sc->rxq_desc[0], sizeof(*sc)); + + sc->sc_macno = unit-1; + + data = inl(ETH_EPAR); + phyaddr = ETH_EPAR_PhyAD_GET(data, sc->sc_macno); + + /* try to read HW address from the device if not overridden + * by config + */ + if (config->hardware_address) { + memcpy(hwaddr, config->hardware_address, ETHER_ADDR_LEN); + } else { + printk("Read EEPROM "); + for (i = 0; i < 6; i++) + hwaddr[i] = ConfVPD_buff[VPD_ENET0_OFFSET+i]; + } + +#ifdef GT_DEBUG + printk("using MAC addr from device:"); + for (i = 0; i < ETHER_ADDR_LEN; i++) printk("%x:", hwaddr[i]); + printk("\n"); +#endif + + memcpy(sc->arpcom.ac_enaddr, hwaddr, ETHER_ADDR_LEN); + + ifp = &sc->arpcom.ac_if; + + sc->sc_pcr = inl(ETH0_EPCR); + sc->sc_pcxr = inl(ETH0_EPCXR); + sc->sc_intrmask = inl(ETH0_EIMR) | ETH_IR_MIIPhySTC; + + printk("address %s\n", ether_sprintf(hwaddr)); + +#ifdef GT_DEBUG + printk(", pcr %x, pcxr %x ", sc->sc_pcr, sc->sc_pcxr); +#endif + + + sc->sc_pcxr |= ETH_EPCXR_PRIOrx_Override; + sc->sc_pcxr |= (3<<6); /* highest priority only */ + sc->sc_pcxr &= ~ETH_EPCXR_RMIIEn; /* MII mode */ + + /* Max. Frame Length (packet) allowed for reception is 1536 bytes, + * instead of 2048 (MOTLoad default) or 64K. + */ + sc->sc_pcxr &= ~(3 << 14); + sc->sc_pcxr |= (ETH_EPCXR_MFL_1536 << 14); + sc->sc_max_frame_length = PKT_BUF_SZ; + + + if (sc->sc_pcr & ETH_EPCR_EN) { + int tries = 1000; + /* Abort transmitter and receiver and wait for them to quiese*/ + outl(ETH_ESDCMR_AR|ETH_ESDCMR_AT,ETH0_ESDCMR); + do { + rtems_bsp_delay(100); + } while (tries-- > 0 && (inl(ETH0_ESDCMR) & (ETH_ESDCMR_AR|ETH_ESDCMR_AT))); + } +#ifdef GT_DEBUG + printk(", phy %d (mii)\n", phyaddr); + printk("ETH0_ESDCMR %x ", inl(ETH0_ESDCMR)); +#endif + + sc->sc_pcr &= ~(ETH_EPCR_EN | ETH_EPCR_RBM | ETH_EPCR_PM | ETH_EPCR_PBF); + +#ifdef GT_DEBUG + printk("Now sc_pcr %x,sc_pcxr %x", sc->sc_pcr, sc->sc_pcxr); +#endif + + /* + * Now turn off the GT. If it didn't quiese, too ***ing bad. + */ + outl(sc->sc_pcr, ETH0_EPCR); + outl(sc->sc_intrmask, ETH0_EIMR); + sdcr = inl(ETH0_ESDCR); + /* Burst size is limited to 4 64bit words */ + ETH_ESDCR_BSZ_SET(sdcr, ETH_ESDCR_BSZ_4); + sdcr |= ETH_ESDCR_RIFB;/*limit interrupt on frame boundaries, instead of buffer*/ +#if 0 + sdcr &= ~(ETH_ESDCR_BLMT|ETH_ESDCR_BLMR); /* MOTLoad defualt Big-endian */ +#endif + outl(sdcr, ETH0_ESDCR); + +#ifdef GT_DEBUG + printk("sdcr %x \n", sdcr); +#endif + + if (phyaddr== -1) printk("MII auto negotiation ?"); + + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + + ifp->if_softc = sc; + + /* set this interface's name and unit */ + ifp->if_unit = unit; + ifp->if_name = name; + + ifp->if_mtu = config->mtu ? config->mtu : ETHERMTU; + + ifp->if_init = GT64260eth_ifinit; + ifp->if_ioctl = GTeth_ifioctl; + ifp->if_start = GTeth_ifstart; + ifp->if_output = ether_output; + + /* ifp->if_watchdog = GTeth_ifwatchdog;*/ + + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + /* create the synchronization semaphore */ + if (RTEMS_SUCCESSFUL != rtems_semaphore_create( + rtems_build_name('G','e','t','h'),0,0,0,&sc->daemonSync)) + printk("GT64260eth: semaphore creation failed"); + + sc->next_module = root_GT64260eth_dev; + root_GT64260eth_dev = sc; + + /* Actually attach the interface */ + if_attach(ifp); + ether_ifattach(ifp); + +#ifdef GT_DEBUG + printk("GT64260eth: Ethernet driver has been attached (handle 0x%08x,ifp 0x%08x)\n",sc, ifp); +#endif + + return(1); +} + +static void GT64260eth_stats(struct GTeth_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + +#if 0 + printf(" Rx Interrupts:%-8lu\n", sc->stats.rxInterrupts); + printf(" Receive Packets:%-8lu\n", ifp->if_ipackets); + printf(" Receive errors:%-8lu\n", ifp->if_ierrors); + printf(" Framing Errors:%-8lu\n", sc->stats.frame_errors); + printf(" Crc Errors:%-8lu\n", sc->stats.crc_errors); + printf(" Oversized Frames:%-8lu\n", sc->stats.length_errors); + printf(" Active Rxqs:%-8u\n", sc->rxq_active); + printf(" Tx Interrupts:%-8lu\n", sc->stats.txInterrupts); +#endif + printf("Multi-BuffTx Packets:%-8lu\n", sc->stats.txMultiBuffPacket); + printf("Multi-BuffTx max len:%-8lu\n", sc->stats.txMultiMaxLen); + printf("SingleBuffTx max len:%-8lu\n", sc->stats.txSinglMaxLen); + printf("Multi-BuffTx maxloop:%-8lu\n", sc->stats.txMultiMaxLoop); + printf("Tx buffer max len :%-8lu\n", sc->stats.txBuffMaxLen); +#if 0 + printf(" Transmitt Packets:%-8lu\n", ifp->if_opackets); + printf(" Transmitt errors:%-8lu\n", ifp->if_oerrors); + printf(" Tx/Rx collisions:%-8lu\n", ifp->if_collisions); + printf(" Active Txqs:%-8u\n", sc->txq_nactive); +#endif +} + +void GT64260eth_printStats() +{ + GT64260eth_stats(root_GT64260eth_dev); +} + +static int GTeth_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct GTeth_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + + int error = 0; + +#ifdef GT_DEBUG + printk("GTeth_ifioctl("); +#endif + + switch (cmd) { + default: + if (GTeth_debug >0) { + printk("etherioctl("); + if (cmd== SIOCSIFADDR) printk("SIOCSIFADDR "); + } + return ether_ioctl(ifp, cmd, data); + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { + case IFF_RUNNING: /* not up, so we stop */ + GT64260eth_stop(sc); + break; + case IFF_UP: /* not running, so we start */ + GT64260eth_ifinit(sc); + break; + case IFF_UP|IFF_RUNNING:/* active->active, update */ + GT64260eth_stop(sc); + GT64260eth_ifinit(sc); + break; + default: /* idle->idle: do nothing */ + break; + } + break; + case SIO_RTEMS_SHOW_STATS: + GT64260eth_stats (sc); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + error = (cmd == SIOCADDMULTI) + ? ether_addmulti(ifr, &sc->arpcom) + : ether_delmulti(ifr, &sc->arpcom); + if (error == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) + GTeth_ifchange(sc); + error = 0; + } + break; + case SIOCSIFMTU: + if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) { + error = EINVAL; + break; + } + ifp->if_mtu = ifr->ifr_mtu; + break; + } + +#ifdef GT_DEBUG + printk("exit ioctl\n"); +#endif + return error; +} + +static void GTeth_ifstart(struct ifnet *ifp) +{ + struct GTeth_softc *sc = ifp->if_softc; + +#ifdef GT_DEBUG + printk("GTeth_ifstart("); +#endif + + if ((ifp->if_flags & IFF_RUNNING) == 0) { +#ifdef GT_DEBUG + printk("IFF_RUNNING==0\n"); +#endif + return; + } + + ifp->if_flags |= IFF_OACTIVE; + rtems_event_send (sc->daemonTid, START_TRANSMIT_EVENT); +#ifdef GT_DEBUG + printk(")\n"); +#endif +} + +/* Initialize the Rx rings */ +static void GTeth_init_rx_ring(struct GTeth_softc *sc) +{ + int i; + volatile struct GTeth_desc *rxd; + unsigned nxtaddr; + + sc->rxq_fi=0; + sc->rxq_head_desc = &sc->rxq_desc[0]; + rxd = sc->rxq_head_desc; + + sc->rxq_desc_busaddr = (unsigned long) sc->rxq_head_desc; +#ifdef GT_DEBUG + printk("rxq_desc_busaddr %x ,&sc->rxq_desc[0] %x\n", + sc->rxq_desc_busaddr, sc->rxq_head_desc); +#endif + + nxtaddr = sc->rxq_desc_busaddr + sizeof(*rxd); + sc->rx_buf_sz = (sc->arpcom.ac_if.if_mtu <= 1500 ? PKT_BUF_SZ : sc->arpcom.ac_if.if_mtu + 32); + sc->rxq_active = RX_RING_SIZE; + + for (i = 0; i < RX_RING_SIZE; i++, rxd++, nxtaddr += sizeof(*rxd)) { + struct mbuf *m; + + rxd->ed_lencnt= sc->rx_buf_sz <<16; + rxd->ed_cmdsts = RX_CMD_F|RX_CMD_L|RX_CMD_O|RX_CMD_EI; + + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + m->m_pkthdr.rcvif = &sc->arpcom.ac_if; + sc->rxq_mbuf[i] = m; + + /* convert mbuf pointer to data pointer of correct type */ + rxd->ed_bufptr = (unsigned) mtod(m, void *); + + /* + * update the nxtptr to point to the next txd. + */ + if (i == RX_RING_SIZE - 1) + nxtaddr = sc->rxq_desc_busaddr; + rxd->ed_nxtptr = nxtaddr; + +#ifdef GT_DEBUG + printk("ed_lencnt %x, rx_buf_sz %x ",rxd->ed_lencnt, sc->rx_buf_sz); + printk("ed_cmdsts %x \n",rxd->ed_cmdsts); + printk("mbuf @ 0x%x, next desc. @ 0x%x\n",rxd->ed_bufptr,rxd->ed_nxtptr); +#endif + } +} + +void GTeth_rxprio_setup(struct GTeth_softc *sc) +{ + + GTeth_init_rx_ring(sc); + + sc->rxq_intrbits = ETH_IR_RxBuffer|ETH_IR_RxError|ETH_IR_RxBuffer_3|ETH_IR_RxError_3; +} + +static int GT64260eth_rx(struct GTeth_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + int nloops=0; + +#ifdef GT_DEBUG + if (GTeth_rx_debug>0) printk("GT64260eth_rx("); +#endif + + while (sc->rxq_active > 0) { + volatile struct GTeth_desc *rxd = &sc->rxq_desc[sc->rxq_fi]; + struct ether_header *eh; + unsigned int cmdsts; + unsigned int byteCount; + + cmdsts = rxd->ed_cmdsts; + + /* + * Sometimes the GE "forgets" to reset the ownership bit. + * But if the length has been rewritten, the packet is ours + * so pretend the O bit is set. + * + */ + byteCount = rxd->ed_lencnt & 0xffff; + + if (cmdsts & RX_CMD_O) { + if (byteCount == 0) + return(0); + + /* Setting command/status to be zero seems to eliminate + * the spurious interrupt associated with the GE_FORGOT issue. + */ + rxd->ed_cmdsts=0; + +#ifdef GE_FORGOT + /* + * For dignosis purpose only. Not a good practice to turn it on + */ + printk("Rxq %d %d %d\n", sc->rxq_fi, byteCount,nloops); +#endif + } + + /* GT gave the ownership back to the CPU or the length has + * been rewritten , which means there + * is new packet in the descriptor/buffer + */ + + nloops++; + /* + * If this is not a single buffer packet with no errors + * or for some reason it's bigger than our frame size, + * ignore it and go to the next packet. + */ + if ((cmdsts & (RX_CMD_F|RX_CMD_L|RX_STS_ES)) != + (RX_CMD_F|RX_CMD_L) || + byteCount > sc->sc_max_frame_length) { + --sc->rxq_active; + ifp->if_ipackets++; + ifp->if_ierrors++; + if (cmdsts & RX_STS_OR) sc->stats.or_errors++; + if (cmdsts & RX_STS_CE) sc->stats.crc_errors++; + if (cmdsts & RX_STS_MFL) sc->stats.length_errors++; + if (cmdsts & RX_STS_SF) sc->stats.frame_errors++; + if ((cmdsts & RX_STS_LC) || (cmdsts & RX_STS_COL)) + ifp->if_collisions++; + goto give_it_back; + } + m = sc->rxq_mbuf[sc->rxq_fi]; + m->m_len = m->m_pkthdr.len = byteCount - sizeof(struct ether_header); + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + + ifp->if_ipackets++; + ifp->if_ibytes+=byteCount; + --sc->rxq_active; + + give_it_back: + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + sc->rxq_mbuf[sc->rxq_fi]= m; + /* convert mbuf pointer to data pointer of correct type */ + rxd->ed_bufptr = (unsigned) mtod(m, void*); + rxd->ed_lencnt = (unsigned long) sc->rx_buf_sz <<16; + rxd->ed_cmdsts = RX_CMD_F|RX_CMD_L|RX_CMD_O|RX_CMD_EI; + + if (++sc->rxq_fi == RX_RING_SIZE) sc->rxq_fi = 0; + + sc->rxq_active++; + } /* while (sc->rxq_active > 0) */ +#ifdef GT_DEBUG + if (GTeth_rx_debug>0) printk(")"); +#endif + return nloops; +} + +static void GTeth_rx_setup(struct GTeth_softc *sc) +{ + + if (GTeth_rx_debug>0) printk("GTeth_rx_setup("); + + GTeth_rxprio_setup(sc); + + if ((sc->sc_flags & GE_RXACTIVE) == 0) { + /* First Rx Descriptor Pointer 3 */ + outl( sc->rxq_desc_busaddr, ETH0_EFRDP3); + /* Current Rx Descriptor Pointer 3 */ + outl( sc->rxq_desc_busaddr,ETH0_ECRDP3); +#ifdef GT_DEBUG + printk("ETH0_EFRDP3 0x%x, ETH0_ECRDP3 0x%x \n", inl(ETH0_EFRDP3), + inl(ETH0_ECRDP3)); +#endif + } + sc->sc_intrmask |= sc->rxq_intrbits; + + if (GTeth_rx_debug>0) printk(")\n"); +} + +static void GTeth_rx_cleanup(struct GTeth_softc *sc) +{ + int i; + + if (GTeth_rx_debug>0) printk( "GTeth_rx_cleanup("); + + for (i=0; i< RX_RING_SIZE; i++) { + if (sc->rxq_mbuf[i]) { + m_freem(sc->rxq_mbuf[i]); + sc->rxq_mbuf[i]=0; + } + } + if (GTeth_rx_debug>0) printk(")"); +} + +static void GTeth_rx_stop(struct GTeth_softc *sc) +{ + if (GTeth_rx_debug>0) printk( "GTeth_rx_stop("); + sc->sc_flags &= ~GE_RXACTIVE; + sc->sc_idlemask &= ~(ETH_IR_RxBits|ETH_IR_RxBuffer_3|ETH_IR_RxError_3); + sc->sc_intrmask &= ~(ETH_IR_RxBits|ETH_IR_RxBuffer_3|ETH_IR_RxError_3); + outl(sc->sc_intrmask, ETH0_EIMR); + outl(ETH_ESDCMR_AR, ETH0_ESDCMR); /* abort receive */ + do { + rtems_bsp_delay(10); + } while (inl(ETH0_ESDCMR) & ETH_ESDCMR_AR); + GTeth_rx_cleanup(sc); + if (GTeth_rx_debug>0) printk(")"); +} + +static void GTeth_txq_free(struct GTeth_softc *sc, unsigned cmdsts) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + volatile struct GTeth_desc *txd = &sc->txq_desc[sc->txq_fi]; + + /* ownership is sent back to CPU */ + if (GTeth_debug>0) printk("txq%d,active %d\n", sc->txq_fi, sc->txq_nactive); + + txd->ed_cmdsts &= ~TX_CMD_O; /* in case GT forgot */ + + /* statistics */ + ifp->if_opackets++; + ifp->if_obytes += sc->txq_mbuf[sc->txq_fi]->m_len; + if (cmdsts & TX_STS_ES) { + ifp->if_oerrors++; + if ((cmdsts & TX_STS_LC) || (cmdsts & TX_STS_COL)) + ifp->if_collisions++; + } + /* Free the original mbuf chain */ + m_freem(sc->txq_mbuf[sc->txq_fi]); + sc->txq_mbuf[sc->txq_fi] = 0; + ifp->if_timer = 5; + + sc->txq_free++; + if (++sc->txq_fi == TX_RING_SIZE) sc->txq_fi = 0; + --sc->txq_nactive; +} + +static int txq_high_limit(struct GTeth_softc *sc) +{ + /* + * Have we [over]consumed our limit of descriptors? + * Do we have enough free descriptors? + */ + if ( TX_RING_SIZE == sc->txq_nactive + TXQ_HiLmt_OFF) { + volatile struct GTeth_desc *txd2 = &sc->txq_desc[sc->txq_fi]; + unsigned cmdsts; + + cmdsts = txd2->ed_cmdsts; + if (cmdsts & TX_CMD_O) { /* Ownership (1=GT 0=CPU) */ + int nextin; + + /* + * Sometime the Discovery forgets to update the + * last descriptor. See if CPU owned the descriptor + * after it (since we know we've turned that to + * the discovery and if CPU owned it, the Discovery + * gave it back). If CPU does, we know the Discovery + * gave back this one but forgot to mark it back to CPU. + */ + nextin = (sc->txq_fi + 1) % TX_RING_SIZE; + if (sc->txq_desc[nextin].ed_cmdsts & TX_CMD_O) { +#if 0 + printk("Overconsuming Tx descriptors!\n"); +#endif + return 1; + } + printk("Txq %d forgot\n", sc->txq_fi); + } + /* Txq ring is almost full, let's free the current buffer here */ +#if 0 + printk("Txq ring near full, free desc%d\n",sc->txq_fi); +#endif + GTeth_txq_free(sc, cmdsts); + } /* end if ( TX_RING_SIZE == sc->txq_nactive + TXQ_HiLmt_OFF) */ + return 0; +} + +static int GT64260eth_sendpacket(struct GTeth_softc *sc,struct mbuf *m) +{ + volatile struct GTeth_desc *txd = &sc->txq_desc[sc->txq_lo]; + unsigned intrmask = sc->sc_intrmask; + unsigned loop=0, index= sc->txq_lo; + + /* + * The end-of-list descriptor we put on last time is the starting point + * for this packet. The GT is supposed to terminate list processing on + * a NULL nxtptr but that currently is broken so a CPU-owned descriptor + * must terminate the list. + */ + intrmask = sc->sc_intrmask; + + if ( !(m->m_next)) {/* single buffer packet */ + sc->txq_mbuf[index]= m; + sc->stats.txSinglMaxLen= MAX(m->m_len, sc->stats.txSinglMaxLen); + } + else /* multiple mbufs in this packet */ + { + struct mbuf *mtp, *mdest; + volatile unsigned char *pt; + int len, y; + +#ifdef GT_DEBUG + printk("multi mbufs "); +#endif + MGETHDR(mdest, M_WAIT, MT_DATA); + MCLGET(mdest, M_WAIT); + pt = (volatile unsigned char *)mdest->m_data; + for (mtp=m,len=0;mtp;mtp=mtp->m_next) { + loop++; + if ( (y=(len+mtp->m_len)) > sizeof(union mcluster)) { + /* GT64260 allows us to chain the remaining to the next + * free descriptors. + */ + printk("packet size %x > mcluster %x\n", y,sizeof(union mcluster)); + printk("GT64260eth : packet too large "); + } + memcpy((void *)pt,(char *)mtp->m_data, mtp->m_len); + pt += mtp->m_len; +#if 0 + printk("%d ",mtp->m_len); +#endif + len += mtp->m_len; + sc->stats.txBuffMaxLen=MAX(mtp->m_len,sc->stats.txBuffMaxLen); + } + sc->stats.txMultiMaxLoop=MAX(loop, sc->stats.txMultiMaxLoop); +#if 0 + printk("\n"); +#endif + mdest->m_len=len; + /* free old mbuf chain */ + m_freem(m); + sc->txq_mbuf[index] = m = mdest; + sc->stats.txMultiBuffPacket++; + sc->stats.txMultiMaxLen= MAX(m->m_len, sc->stats.txMultiMaxLen); + } + if (m->m_len < ET_MINLEN) m->m_len = ET_MINLEN; + + txd->ed_bufptr = (unsigned) mtod(m, void*); + txd->ed_lencnt = m->m_len << 16; + /*txd->ed_cmdsts = TX_CMD_L|TX_CMD_GC|TX_CMD_P|TX_CMD_O|TX_CMD_F|TX_CMD_EI;*/ + txd->ed_cmdsts = 0x80c70000; + while (txd->ed_cmdsts != 0x80c70000); + memBar(); + +#ifdef GT_DEBUG + printk("len = %d, cmdsts 0x%x ", m->m_len,txd->ed_cmdsts); +#endif + + /* + * Tell the SDMA engine to "Fetch!" + * Start Tx high. + */ + sc->txq_nactive++; + outl(0x800080, ETH0_ESDCMR); /* ETH_ESDCMR_TXDH| ETH_ESDCMR_ERD */ + if ( ++sc->txq_lo == TX_RING_SIZE) sc->txq_lo = 0; + sc->txq_free--; + +#if 0 + /* + * Since we have put an item into the packet queue, we now want + * an interrupt when the transmit queue finishes processing the + * list. But only update the mask if needs changing. + */ + intrmask |= sc->txq_intrbits & ( ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh); + if (sc->sc_intrmask != intrmask) { + sc->sc_intrmask = intrmask; + outl(sc->sc_intrmask, ETH0_EIMR); + } +#endif + +#if 0 + printk("EICR= %x, EIMR= %x ", inl(ETH0_EICR), inl(ETH0_EIMR)); + printk("%s:transmit frame #%d queued in slot %d.\n", + sc->arpcom.ac_if.if_name, sc->txq_lo, index); + printk("pcr %x, pcxr %x DMA dcr %x cmr %x\n", inl(ETH0_EPCR), inl(ETH0_EPCXR), inl(ETH0_ESDCR), inl(ETH0_ESDCMR)); +#endif + + return 1; +} + +static unsigned GTeth_txq_done(struct GTeth_softc *sc) +{ + if (GTeth_debug>0) printk("Txdone(" ); + + while (sc->txq_nactive > 0) { + /* next to be returned to the CPU */ + volatile struct GTeth_desc *txd = &sc->txq_desc[sc->txq_fi]; + unsigned cmdsts; + + /* if GT64260 still owns it ....... */ + if ((cmdsts = txd->ed_cmdsts) & TX_CMD_O) { + int nextin; + + /* Someone quoted : + * "Sometimes the Discovery forgets to update the + * ownership bit in the descriptor." + * More correctly, the last descriptor of each + * transmitted frame is returned to CPU ownership and + * status is updated only after the actual transmission + * of the packet is completed. Also, if there is an error + * during transmission, we want to continue the + * transmission of the next descriptor, in additions to + * reporting the error. + */ + /* The last descriptor */ + if (sc->txq_nactive == 1) return(0); + + /* + * Sometimes the Discovery forgets to update the + * ownership bit in the descriptor. See if CPU owned + * the descriptor after it (since we know we've turned + * that to the Discovery and if CPU owned it now then the + * Discovery gave it back). If we do, we know the + * Discovery gave back this one but forgot to mark it + * back to CPU. + */ + nextin = (sc->txq_fi + 1) % TX_RING_SIZE; + + if (sc->txq_desc[nextin].ed_cmdsts & TX_CMD_O) return(0); + printk("Txq%d forgot\n",sc->txq_fi); + } /* end checking GT64260eth owner */ + GTeth_txq_free(sc, cmdsts); + } /* end while */ + if (GTeth_debug>0) printk(")\n"); + return(1); +} + +static void GTeth_tx_start(struct GTeth_softc *sc) +{ + int i; + volatile struct GTeth_desc *txd; + unsigned nxtaddr; + +#ifdef GT_DEBUG + printk("GTeth_tx_start("); +#endif + sc->sc_intrmask &= ~(ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh| + ETH_IR_TxEndLow |ETH_IR_TxBufferLow); + + txd = &sc->txq_desc[0]; + sc->txq_desc_busaddr = (unsigned long) &sc->txq_desc[0]; +#ifdef GT_DEBUG + printk("txq_desc_busaddr %x, &sc->txq_desc[0] %x \n", + sc->txq_desc_busaddr,&sc->txq_desc[0]); +#endif + + nxtaddr = sc->txq_desc_busaddr + sizeof(*txd); + + sc->txq_pendq.ifq_maxlen = 10; + sc->txq_pendq.ifq_head= NULL; + sc->txq_pendq.ifq_tail= NULL; + sc->txq_nactive = 0; + sc->txq_fi = 0; + sc->txq_lo = 0; + sc->txq_inptr = PKT_BUF_SZ; + sc->txq_outptr = 0; + sc->txq_free = TX_RING_SIZE; + + for (i = 0; i < TX_RING_SIZE; + i++, txd++, nxtaddr += sizeof(*txd)) { + sc->txq_mbuf[i]=0; + txd->ed_bufptr = 0; + + /* + * update the nxtptr to point to the next txd. + */ + txd->ed_cmdsts = 0; + if ( i== TX_RING_SIZE-1) nxtaddr = sc->txq_desc_busaddr; + txd->ed_nxtptr = nxtaddr; +#ifdef GT_DEBUG + printk("next desc. @ 0x%x\n",txd->ed_nxtptr); +#endif + } + + sc->txq_intrbits = ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh; + sc->txq_esdcmrbits = ETH_ESDCMR_TXDH; /* Start Tx high */ + sc->txq_epsrbits = ETH_EPSR_TxHigh; + /* offset to current tx desc ptr reg */ + sc->txq_ectdp = (caddr_t)ETH0_ECTDP1; + /* Current Tx Desc Pointer 1 */ + outl(sc->txq_desc_busaddr,ETH0_ECTDP1); + +#ifdef GT_DEBUG + printk(")\n"); +#endif +} + +static void GTeth_tx_cleanup(struct GTeth_softc *sc) +{ + int i; + + for (i=0; i< TX_RING_SIZE; i++) { + if (sc->txq_mbuf[i]) { + m_freem(sc->txq_mbuf[i]); + sc->txq_mbuf[i]=0; + } + } +} + +static void GTeth_tx_stop(struct GTeth_softc *sc) +{ + /* SDMA command register : stop Tx high and low */ + outl(ETH_ESDCMR_STDH|ETH_ESDCMR_STDL, ETH0_ESDCMR); + + GTeth_txq_done(sc); + sc->sc_intrmask &= ~(ETH_IR_TxEndHigh|ETH_IR_TxBufferHigh| + ETH_IR_TxEndLow |ETH_IR_TxBufferLow); + GTeth_tx_cleanup(sc); + + sc->arpcom.ac_if.if_timer = 0; +} + +/* TOCHECK : Should it be about rx or tx ? */ +static void GTeth_ifchange(struct GTeth_softc *sc) +{ + if (GTeth_debug>0) printk("GTeth_ifchange("); + if (GTeth_debug>5) printk("(pcr=%#x,imr=%#x)",inl(ETH0_EPCR),inl(ETH0_EIMR)); + /* printk("SIOCADDMULTI (SIOCDELMULTI): is it about rx or tx ?\n");*/ + outl(sc->sc_pcr | ETH_EPCR_EN, ETH0_EPCR); + outl(sc->sc_intrmask, ETH0_EIMR); + GTeth_ifstart(&sc->arpcom.ac_if); + /* Current Tx Desc Pointer 0 and 1 */ + if (GTeth_debug>5) printk("(ectdp0=%#x, ectdp1=%#x)", + inl(ETH0_ECTDP0), inl(ETH0_ECTDP1)); + if (GTeth_debug>0) printk(")"); +} + +static int GTeth_hash_compute(struct GTeth_softc *sc,unsigned char eaddr[ETHER_ADDR_LEN]) +{ + unsigned w0, add0, add1; + unsigned result; + + if (GTeth_debug>0) printk("GTeth_hash_compute("); + add0 = ((unsigned) eaddr[5] << 0) | + ((unsigned) eaddr[4] << 8) | + ((unsigned) eaddr[3] << 16); + + add0 = ((add0 & 0x00f0f0f0) >> 4) | ((add0 & 0x000f0f0f) << 4); + add0 = ((add0 & 0x00cccccc) >> 2) | ((add0 & 0x00333333) << 2); + add0 = ((add0 & 0x00aaaaaa) >> 1) | ((add0 & 0x00555555) << 1); + + add1 = ((unsigned) eaddr[2] << 0) | + ((unsigned) eaddr[1] << 8) | + ((unsigned) eaddr[0] << 16); + + add1 = ((add1 & 0x00f0f0f0) >> 4) | ((add1 & 0x000f0f0f) << 4); + add1 = ((add1 & 0x00cccccc) >> 2) | ((add1 & 0x00333333) << 2); + add1 = ((add1 & 0x00aaaaaa) >> 1) | ((add1 & 0x00555555) << 1); + +#ifdef GT_DEBUG + printk("eaddr= %s add1:%x add0:%x\n", ether_sprintf1(eaddr), add1, add0); +#endif + + /* + * hashResult is the 15 bits Hash entry address. + * ethernetADD is a 48 bit number, which is derived from the Ethernet + * MAC address, by nibble swapping in every byte (i.e MAC address + * of 0x123456789abc translates to ethernetADD of 0x21436587a9cb). + */ + if ((sc->sc_pcr & ETH_EPCR_HM) == 0) { + /* + * hashResult[14:0] = hashFunc0(ethernetADD[47:0]) + * + * hashFunc0 calculates the hashResult in the following manner: + * hashResult[ 8:0] = ethernetADD[14:8,1,0] + * XOR ethernetADD[23:15] XOR ethernetADD[32:24] + */ + result = (add0 & 3) | ((add0 >> 6) & ~3); + result ^= (add0 >> 15) ^ (add1 >> 0); + result &= 0x1ff; + /* + * hashResult[14:9] = ethernetADD[7:2] + */ + result |= (add0 & ~3) << 7; /* excess bits will be masked */ +#ifdef GT_DEBUG + printk("hash result %x ", result & 0x7fff); +#endif + } else { +#define TRIBITFLIP 073516240 /* yes its in octal */ + /* + * hashResult[14:0] = hashFunc1(ethernetADD[47:0]) + * + * hashFunc1 calculates the hashResult in the following manner: + * hashResult[08:00] = ethernetADD[06:14] + * XOR ethernetADD[15:23] XOR ethernetADD[24:32] + */ + w0 = ((add0 >> 6) ^ (add0 >> 15) ^ (add1)) & 0x1ff; + /* + * Now bitswap those 9 bits + */ + result = 0; + result |= ((TRIBITFLIP >> (((w0 >> 0) & 7) * 3)) & 7) << 6; + result |= ((TRIBITFLIP >> (((w0 >> 3) & 7) * 3)) & 7) << 3; + result |= ((TRIBITFLIP >> (((w0 >> 6) & 7) * 3)) & 7) << 0; + + /* + * hashResult[14:09] = ethernetADD[00:05] + */ + result |= ((TRIBITFLIP >> (((add0 >> 0) & 7) * 3)) & 7) << 12; + result |= ((TRIBITFLIP >> (((add0 >> 3) & 7) * 3)) & 7) << 9; +#ifdef GT_DEBUG + printk("1(%#x)", result); +#endif + } +#ifdef GT_DEBUG + printk(")"); +#endif + + /* 1/2K address filtering (MOTLoad default )? ->16KB memory required + * or 8k address filtering ? -> 256KB memory required + */ + return result & ((sc->sc_pcr & ETH_EPCR_HS_512) ? 0x7ff : 0x7fff); +} + +static int GTeth_hash_entry_op(struct GTeth_softc *sc, enum GTeth_hash_op op, + enum GTeth_rxprio prio,unsigned char eaddr[ETHER_ADDR_LEN]) +{ + unsigned long long he; + unsigned long long *maybe_he_p = NULL; + int limit; + int hash; + int maybe_hash = 0; + +#ifdef GT_DEBUG + printk("GTeth_hash_entry_op(prio %d ", prio); +#endif + + hash = GTeth_hash_compute(sc, eaddr); + + if (sc->sc_hashtable == NULL) { + printk("hashtable == NULL!"); + } +#ifdef GT_DEBUG + printk("Hash computed %x eaddr %s\n", hash,ether_sprintf1(eaddr)); +#endif + + /* + * Assume we are going to insert so create the hash entry we + * are going to insert. We also use it to match entries we + * will be removing. The datasheet is wrong for this. + */ + he = (((unsigned long long) eaddr[5]) << 43) | + (((unsigned long long) eaddr[4]) << 35) | + (((unsigned long long) eaddr[3]) << 27) | + (((unsigned long long) eaddr[2]) << 19) | + (((unsigned long long) eaddr[1]) << 11) | + (((unsigned long long) eaddr[0]) << 3) | + ((unsigned long long) HSH_PRIO_INS(prio) | HSH_V | HSH_R); + /* he = 0x1b1acd87d08005;*/ + /* + * The GT will search upto 12 entries for a hit, so we must mimic that. + */ + hash &= (sc->sc_hashmask / sizeof(he)); + +#ifdef GT_DEBUG + if (GTeth_debug>0) { + unsigned val1, val2; + + val1= he & 0xffffffff; + val2= (he >>32) & 0xffffffff; + printk("Hash addr value %x%x, entry %x\n",val2,val1, hash); + } +#endif + + for (limit = HSH_LIMIT; limit > 0 ; --limit) { + /* + * Does the GT wrap at the end, stop at the, or overrun the + * end? Assume it wraps for now. Stash a copy of the + * current hash entry. + */ + unsigned long long *he_p = &sc->sc_hashtable[hash]; + unsigned long long thishe = *he_p; + + /* + * If the hash entry isn't valid, that break the chain. And + * this entry a good candidate for reuse. + */ + if ((thishe & HSH_V) == 0) { + maybe_he_p = he_p; + break; + } + + /* + * If the hash entry has the same address we are looking for + * then ... if we are removing and the skip bit is set, its + * already been removed. if are adding and the skip bit is + * clear, then its already added. In either return EBUSY + * indicating the op has already been done. Otherwise flip + * the skip bit and return 0. + */ + if (((he ^ thishe) & HSH_ADDR_MASK) == 0) { + if (((op == GE_HASH_REMOVE) && (thishe & HSH_S)) || + ((op == GE_HASH_ADD) && (thishe & HSH_S) == 0)) + return EBUSY; + *he_p = thishe ^ HSH_S; + + if (GTeth_debug>0) { + unsigned val1, val2; + + val1= *he_p & 0xffffffff; + val2= (*he_p >>32) & 0xffffffff; + printk("flip skip bit result %x%x entry %x ",val2,val1, hash); + } + return 0; + } + + /* + * If we haven't found a slot for the entry and this entry + * is currently being skipped, return this entry. + */ + if (maybe_he_p == NULL && (thishe & HSH_S)) { + maybe_he_p = he_p; + maybe_hash = hash; + } + hash = (hash + 1) & (sc->sc_hashmask / sizeof(he)); + } + + /* + * If we got here, then there was no entry to remove. + */ + if (op == GE_HASH_REMOVE) { + printk("GT64260eth : No entry to remove\n"); + return ENOENT; + } + + /* + * If we couldn't find a slot, return an error. + */ + if (maybe_he_p == NULL) { + printk("GT64260eth : No slot found"); + return ENOSPC; + } + + /* Update the entry.*/ + *maybe_he_p = he; + if (GTeth_debug>0) { + unsigned val1, val2; +#if 0 + unsigned long *pt= sc->sc_hashtable; + int i, loop; + + for (loop= 0; loop< 256; loop++) { + printk("%d)", loop); + for (i=0; i< 16; i++, pt++) printk("%x ",*pt); + printk("\n"); + } +#endif + val1= he & 0xffffffff; + val2= (he >>32) & 0xffffffff; + printk("Update Hash result %x%x, table addr %x entry %x )\n",val2, val1, maybe_he_p, hash); + } + return 0; +} + +static int GTeth_hash_fill(struct GTeth_softc *sc) +{ + struct ether_multistep step; + struct ether_multi *enm; + int error; + +#ifdef GT_DEBUG + printk( "GTeth_hash_fill("); +#endif + error = GTeth_hash_entry_op(sc,GE_HASH_ADD,GE_RXPRIO_HI,sc->arpcom.ac_enaddr); + + if (error) { + if (GTeth_debug>0) printk("!"); + return error; + } + + sc->sc_flags &= ~GE_ALLMULTI; + if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) == 0) + sc->sc_pcr &= ~ETH_EPCR_PM; + /* see lib/include/netinet/if_ether.h */ + ETHER_FIRST_MULTI(step, &sc->arpcom, enm); + while (enm != NULL) { + if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { + /* Frames are received regardless of their destinatin address */ + sc->sc_flags |= GE_ALLMULTI; + sc->sc_pcr |= ETH_EPCR_PM; + } else { + /* Frames are only received if the destinatin address is found + * in the hash table + */ + error = GTeth_hash_entry_op(sc, GE_HASH_ADD, + GE_RXPRIO_MEDLO, enm->enm_addrlo); + if (error == ENOSPC) break; + } + ETHER_NEXT_MULTI(step, enm); + } +#ifdef GT_DEBUG + printk(")\n"); +#endif + return error; +} + +static void GTeth_hash_init(struct GTeth_softc *sc) +{ + void *hash_mem; + + if (GTeth_debug>0) printk("GTeth_hash_init("); + /* MOTLoad defualt : 512 bytes of address filtering, which + * requires 16KB of memory + */ +#if 1 + hash_mem = rtems_bsdnet_malloc(HASH_DRAM_SIZE + HASH_ALIGN, M_FREE, M_NOWAIT); + sc->sc_hashtable =(void *)(((long)hash_mem+ HASH_ALIGN) & ~HASH_ALIGN); +#else + /* only for test */ + hash_mem = 0x68F000; + sc->sc_hashtable =(unsigned long long *)hash_mem; +#endif + sc->sc_hashmask = HASH_DRAM_SIZE - 1; + + memset((void *)sc->sc_hashtable, 0,HASH_DRAM_SIZE); +#ifdef GT_DEBUG + printk("hashtable addr:%x, mask %x)\n", sc->sc_hashtable,sc->sc_hashmask); +#endif +} + +static void GT64260eth_error(struct GTeth_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + unsigned int intr_status= sc->intr_errsts[sc->intr_err_ptr1]; + + /* read and reset the status; because this is written + * by the ISR, we must disable interrupts here + */ + if (intr_status) { + printk("%s%d: ICR = 0x%x ", + ifp->if_name, ifp->if_unit, intr_status); +#if 1 + if (intr_status & INTR_RX_ERROR) { + printk("Rxq error, if_ierrors %d\n", + ifp->if_ierrors); + } +#endif + /* Rx error is handled in GT64260eth_rx() */ + if (intr_status & INTR_TX_ERROR) { + ifp->if_oerrors++; + printk("Txq error, if_oerrors %d\n",ifp->if_oerrors); + } + } + else + printk("%s%d: Ghost interrupt ?\n",ifp->if_name, + ifp->if_unit); + sc->intr_errsts[sc->intr_err_ptr1++]=0; + sc->intr_err_ptr1 %= INTR_ERR_SIZE; /* Till Straumann */ +} + + +/* The daemon does all of the work; RX, TX and cleaning up buffers/descriptors */ +static void GT64260eth_daemon(void *arg) +{ + struct GTeth_softc *sc = (struct GTeth_softc*)arg; + rtems_event_set events; + struct mbuf *m=0; + struct ifnet *ifp=&sc->arpcom.ac_if; + +#if 0 + /* see comments in GT64260eth_init(); in newer versions of + * rtems, we hold the network semaphore at this point + */ + rtems_semaphore_release(sc->daemonSync); +#endif + + /* NOTE: our creator possibly holds the bsdnet_semaphore. + * since that has PRIORITY_INVERSION enabled, our + * subsequent call to bsdnet_event_receive() will + * _not_ release it. It's still in posession of our + * owner. + * This is different from how killing this task + * is handled. + */ + + for (;;) { + /* sleep until there's work to be done */ + /* Note: bsdnet_event_receive() acquires + * the global bsdnet semaphore for + * mutual exclusion. + */ + rtems_bsdnet_event_receive(ALL_EVENTS, + RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + if (KILL_EVENT & events) break; + +#ifndef GE_NORX + if (events & RX_EVENT) GT64260eth_rx(sc); +#endif +#if 0 + printk("%x ", inb(ETH0_EPSR)); + if ( ((i++) % 15)==0) printk("\n"); +#endif + + /* clean up and try sending packets */ + do { + if (sc->txq_nactive) GTeth_txq_done(sc); + + while (sc->txq_free>0) { + if (sc->txq_free>TXQ_HiLmt_OFF) { + m=0; + IF_DEQUEUE(&ifp->if_snd,m); + if (m==0) break; + GT64260eth_sendpacket(sc, m); + } + else { + GTeth_txq_done(sc); + break; + } + } + /* we leave this loop + * - either because there's no free buffer + * (m=0 initializer && !sc->txq_free) + * - or there's nothing to send (IF_DEQUEUE + * returned 0 + */ + } while (m); + + ifp->if_flags &= ~IFF_OACTIVE; + + /* Log errors and other uncommon events. */ + if (events & ERR_EVENT) GT64260eth_error(sc); + } /* end for(;;) { rtems_bsdnet_event_receive() .....*/ + + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + + /* shut down the hardware */ + GT64260eth_stop_hw(sc); + /* flush the output queue */ + for (;;) { + IF_DEQUEUE(&ifp->if_snd,m); + if (!m) break; + m_freem(m); + } + /* as of 'rtems_bsdnet_event_receive()' we own the + * networking semaphore + */ + rtems_bsdnet_semaphore_release(); + rtems_semaphore_release(sc->daemonSync); + + /* Note that I dont use sc->daemonTid here - + * theoretically, that variable could already + * hold a newly created TID + */ + rtems_task_delete(RTEMS_SELF); +} + diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.h b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.h new file mode 100644 index 0000000000..52ea42c39e --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260eth.h @@ -0,0 +1,140 @@ +/* GT64260eth.h + * + * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc. + * All rights reserved. + * + * RTEMS/Mvme5500 port 2004 by S. Kate Feng, , + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Allegro Networks, Inc., and Wasabi Systems, Inc. + * 4. The name of Allegro Networks, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * 5. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND + * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC. + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too long decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 32 +#define GT_NEXTTX(x) ((x + 1) % TX_RING_SIZE ) +#define TX_QUARTER_FULL TX_RING_SIZE/2 +#define TX_HALF_FULL TX_RING_SIZE/2 +#define RX_RING_SIZE 16 +#define HASH_TABLE_SIZE 16 +#define HASH_DRAM_SIZE HASH_TABLE_SIZE*1024 /* size of DRAM for hash table */ +#define INTR_ERR_SIZE 16 + +enum GTeth_txprio { + GE_TXPRIO_HI=1, + GE_TXPRIO_LO=0, + GE_TXPRIO_NONE=2 +}; +enum GTeth_rxprio { + GE_RXPRIO_HI=3, + GE_RXPRIO_MEDHI=2, + GE_RXPRIO_MEDLO=1, + GE_RXPRIO_LO=0 +}; + +struct GTeth_softc { + struct GTeth_desc txq_desc[TX_RING_SIZE]; /* transmit descriptor memory */ + struct GTeth_desc rxq_desc[RX_RING_SIZE]; /* receive descriptor memory */ + struct mbuf* txq_mbuf[TX_RING_SIZE]; /* transmit buffer memory */ + struct mbuf* rxq_mbuf[RX_RING_SIZE]; /* receive buffer memory */ + struct GTeth_softc *next_module; + volatile unsigned int intr_errsts[INTR_ERR_SIZE]; /* capture the right intr_status */ + unsigned int intr_err_ptr1; /* ptr used in GTeth_error() */ + unsigned int intr_err_ptr2; /* ptr used in ISR */ + struct ifqueue txq_pendq; /* these are ready to go to the GT */ + unsigned int txq_pending; + unsigned int txq_lo; /* next to be given to GT DMA */ + unsigned int txq_fi; /* next to be free */ + unsigned int txq_to_cpu; /* next to be returned to CPU */ + unsigned int txq_ei_gapcount; /* counter until next EI */ + unsigned int txq_nactive; /* number of active descriptors */ + unsigned int txq_nintr; /* number of txq desc. send TX_EVENT */ + unsigned int txq_outptr; /* where to put next transmit packet */ + unsigned int txq_inptr; /* start of 1st queued tx packet */ + unsigned int txq_free; /* free Tx queue slots. */ + unsigned txq_intrbits; /* bits to write to EIMR */ + unsigned txq_esdcmrbits; /* bits to write to ESDCMR */ + unsigned txq_epsrbits; /* bits to test with EPSR */ + + caddr_t txq_ectdp; /* offset to cur. tx desc ptr reg */ + unsigned long txq_desc_busaddr; /* bus addr of tx descriptors */ + caddr_t txq_buf_busaddr; /* bus addr of tx buffers */ + + struct mbuf *rxq_curpkt; /* mbuf for current packet */ + struct GTeth_desc *rxq_head_desc; /* rxq head descriptor */ + unsigned int rxq_fi; /* next to be returned to CPU */ + unsigned int rxq_active; /* # of descriptors given to GT */ + unsigned rxq_intrbits; /* bits to write to EIMR */ + unsigned long rxq_desc_busaddr; /* bus addr of rx descriptors */ + + struct arpcom arpcom; /* rtems if structure, contains ifnet */ + int sc_macno; /* which mac? 0, 1, or 2 */ + + unsigned int sc_tickflags; + #define GE_TICK_TX_IFSTART 0x0001 + #define GE_TICK_RX_RESTART 0x0002 + unsigned int sc_flags; + #define GE_ALLMULTI 0x0001 + #define GE_PHYSTSCHG 0x0002 + #define GE_RXACTIVE 0x0004 + unsigned sc_pcr; /* current EPCR value */ + unsigned sc_pcxr; /* current EPCXR value */ + unsigned sc_intrmask; /* current EIMR value */ + unsigned sc_idlemask; /* suspended EIMR bits */ + unsigned sc_max_frame_length; /* maximum frame length */ + unsigned rx_buf_sz; + + /* Hash table related members */ + unsigned long long *sc_hashtable; + unsigned int sc_hashmask; /* 0x1ff or 0x1fff */ + + rtems_id daemonTid; + rtems_id daemonSync; /* synchronization with the daemon */ + /* statistics */ + struct { + volatile unsigned long rxInterrupts; + + volatile unsigned long txInterrupts; + unsigned long txMultiBuffPacket; + unsigned long txMultiMaxLen; + unsigned long txSinglMaxLen; + unsigned long txMultiMaxLoop; + unsigned long txBuffMaxLen; + unsigned long length_errors; + unsigned long frame_errors; + unsigned long crc_errors; + unsigned long or_errors; /* overrun error */ + } stats; +}; diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260ethreg.h b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260ethreg.h new file mode 100644 index 0000000000..efa9ebf0e0 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/GT64260ethreg.h @@ -0,0 +1,880 @@ +/* $NetBSD: GT64260ethreg.h,v 1.2 2003/03/17 16:41:16 matt Exp $ */ +/* $Id$ */ + +/* + * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Allegro Networks, Inc., and Wasabi Systems, Inc. + * 4. The name of Allegro Networks, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * 5. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND + * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC. + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_GTETHREG_H_ +#define _DEV_GTETHREG_H_ + +#define ETH__BIT(bit) (1U << (bit)) +#define ETH__LLBIT(bit) (1ULL << (bit)) +#define ETH__MASK(bit) (ETH__BIT(bit) - 1) +#define ETH__LLMASK(bit) (ETH__LLBIT(bit) - 1) +#define ETH__GEN(n, off) (0x2400+((n) << 10)+(ETH__ ## off)) +#define ETH__EXT(data, bit, len) (((data) >> (bit)) & ETH__MASK(len)) +#define ETH__LLEXT(data, bit, len) (((data) >> (bit)) & ETH__LLMASK(len)) +#define ETH__CLR(data, bit, len) ((data) &= ~(ETH__MASK(len) << (bit))) +#define ETH__INS(new, bit) ((new) << (bit)) +#define ETH__LLINS(new, bit) ((unsigned long long)(new) << (bit)) + +/* + * Descriptors used for both receive & transmit data. Note that the descriptor + * must start on a 4LW boundary. Since the GT accesses the descriptor as + * two 64-bit quantities, we must present them 32bit quantities in the right + * order based on endianess. + */ + +struct GTeth_desc { +#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN /* for mvme5500 */ + unsigned ed_lencnt; /* Buffer size is hi 16 bits; Byte count (rx) is lo 16 */ + unsigned ed_cmdsts; /* command (hi16)/status (lo16) bits */ + unsigned ed_nxtptr; /* next descriptor (must be 4LW aligned) */ + unsigned ed_bufptr; /* pointer to packet buffer */ +#endif +#if defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN + unsigned ed_cmdsts; /* command (hi16)/status (lo16) bits */ + unsigned ed_lencnt; /* length is hi 16 bits; count (rx) is lo 16 */ + unsigned ed_bufptr; /* pointer to packet buffer */ + unsigned ed_nxtptr; /* next descriptor (must be 4LW aligned) */ +#endif +}; + +/* Ethernet 0 address control (Low), Offset: 0xf200 */ +#define RxBSnoopEn ETH__BIT(6) /* Rx buffer snoop enable,1=enable*/ +#define TxBSnoopEn ETH__BIT(14) /* Tx buffer snoop enable */ +#define RxDSnoopEn ETH__BIT(22) /* Rx descriptor snoop enable */ +#define TxDSnoopEn ETH__BIT(30) /* Tx descriptor snoop enable */ + +/* Ethernet 0 address control (High), Offset: 0xf204 */ +#define HashSnoopEn ETH__BIT(6) /* Hash Table snoop enable */ + +/* */ +#define GT_CUU_Eth0_AddrCtrlLow 0xf200 +#define GT_CUU_Eth0_AddrCtrlHigh 0xf204 + +/* Table 578: Ethernet TX Descriptor - Command/Status word + * All bits except F, EI, AM, O are only valid if TX_CMD_L is also set, + * otherwise should be 0 (tx). + */ + +#define TX_STS_LC ETH__BIT(5) /* Late Collision */ +#define TX_STS_UR ETH__BIT(6) /* Underrun error */ +#define TX_STS_RL ETH__BIT(8) /* Retransmit Limit (excession coll) */ +#define TX_STS_COL ETH__BIT(9) /* Collision Occurred */ +#define TX_STS_RC(v) ETH__GETBITS(v, 10, 4) /* Retransmit Count */ +#define TX_STS_ES ETH__BIT(15) /* Error Summary (LC|UR|RL) */ +#define TX_CMD_L ETH__BIT(16) /* Last - End Of Packet */ +#define TX_CMD_F ETH__BIT(17) /* First - Start Of Packet */ +#define TX_CMD_P ETH__BIT(18) /* Pad Packet */ +#define TX_CMD_GC ETH__BIT(22) /* Generate CRC */ +#define TX_CMD_EI ETH__BIT(23) /* Enable Interrupt */ +#define TX_CMD_AM ETH__BIT(30) /* Auto Mode */ +#define TX_CMD_O ETH__BIT(31) /* Ownership (1=GT 0=CPU) */ + +#define TX_CMD_FIRST (TX_CMD_F|TX_CMD_O) +#define TX_CMD_LAST (TX_CMD_L|TX_CMD_GC|TX_CMD_P|TX_CMD_O) + +/* Table 608: Ethernet RX Descriptor - Command/Status Word + * All bits except F, EI, AM, O are only valid if RX_CMD_L is also set, + * otherwise should be ignored (rx). + */ +#define RX_STS_CE ETH__BIT(0) /* CRC Error */ +#define RX_STS_COL ETH__BIT(1) /* Collision sensed during reception */ +#define RX_STS_LC ETH__BIT(5) /* Late Collision (Reserved) */ +#define RX_STS_OR ETH__BIT(6) /* Overrun Error */ +#define RX_STS_MFL ETH__BIT(7) /* Max Frame Len Error */ +#define RX_STS_SF ETH__BIT(8) /* Short Frame Error (< 64 bytes) */ +#define RX_STS_FT ETH__BIT(11) /* Frame Type (1 = 802.3) */ +#define RX_STS_M ETH__BIT(12) /* Missed Frame */ +#define RX_STS_HE ETH__BIT(13) /* Hash Expired (manual match) */ +#define RX_STS_IGMP ETH__BIT(14) /* IGMP Packet */ +#define RX_STS_ES ETH__BIT(15) /* Error Summary (CE|COL|LC|OR|MFL|SF) */ +#define RX_CMD_L ETH__BIT(16) /* Last - End Of Packet */ +#define RX_CMD_F ETH__BIT(17) /* First - Start Of Packet */ +#define RX_CMD_EI ETH__BIT(23) /* Enable Interrupt */ +#define RX_CMD_AM ETH__BIT(30) /* Auto Mode */ +#define RX_CMD_O ETH__BIT(31) /* Ownership (1=GT 0=CPU) */ + +/* Table 586: Hash Table Entry Fields + */ +#define HSH_V ETH__LLBIT(0) /* Entry is valid */ +#define HSH_S ETH__LLBIT(1) /* Skip this entry */ +#define HSH_RD ETH__LLBIT(2) /* Receive(1) / Discard (0) */ +#define HSH_R ETH__LLBIT(2) /* Receive(1) */ +#define HSH_PRIO_GET(v) ETH__LLEXT(v, 51, 2) +#define HSH_PRIO_INS(v) ETH__LLINS(v, 51) +#define HSH_ADDR_MASK 0x7fffff8LLU +#define HSH_LIMIT 12 + + +#define ETH_EPAR 0x2000 /* PHY Address Register */ +#define ETH_ESMIR 0x2010 /* SMI Register */ + +#define ETH_BASE_ETH0 0x2400 /* Ethernet0 Register Base */ +#define ETH_BASE_ETH1 0x2800 /* Ethernet1 Register Base */ +#define ETH_BASE_ETH2 0x2c00 /* Ethernet2 Register Base */ +#define ETH_SIZE 0x0400 /* Register Space */ + +#define ETH__EBASE 0x0000 /* Base of Registers */ +#define ETH__EPCR 0x0000 /* Port Config. Register */ +#define ETH__EPCXR 0x0008 /* Port Config. Extend Reg */ +#define ETH__EPCMR 0x0010 /* Port Command Register */ +#define ETH__EPSR 0x0018 /* Port Status Register */ +#define ETH__ESPR 0x0020 /* Port Serial Parameters Reg */ +#define ETH__EHTPR 0x0028 /* Port Hash Table Pointer Reg*/ +#define ETH__EFCSAL 0x0030 /* Flow Control Src Addr Low */ +#define ETH__EFCSAH 0x0038 /* Flow Control Src Addr High */ +#define ETH__ESDCR 0x0040 /* SDMA Configuration Reg */ +#define ETH__ESDCMR 0x0048 /* SDMA Command Register */ +#define ETH__EICR 0x0050 /* Interrupt Cause Register */ +#define ETH__EIMR 0x0058 /* Interrupt Mask Register */ +#define ETH__EFRDP0 0x0080 /* First Rx Desc Pointer 0 */ +#define ETH__EFRDP1 0x0084 /* First Rx Desc Pointer 1 */ +#define ETH__EFRDP2 0x0088 /* First Rx Desc Pointer 2 */ +#define ETH__EFRDP3 0x008c /* First Rx Desc Pointer 3 */ +#define ETH__ECRDP0 0x00a0 /* Current Rx Desc Pointer 0 */ +#define ETH__ECRDP1 0x00a4 /* Current Rx Desc Pointer 1 */ +#define ETH__ECRDP2 0x00a8 /* Current Rx Desc Pointer 2 */ +#define ETH__ECRDP3 0x00ac /* Current Rx Desc Pointer 3 */ +#define ETH__ECTDP0 0x00e0 /* Current Tx Desc Pointer 0 */ +#define ETH__ECTDP1 0x00e4 /* Current Tx Desc Pointer 1 */ +#define ETH__EDSCP2P0L 0x0060 /* IP Differentiated Services + CodePoint to Priority0 low */ +#define ETH__EDSCP2P0H 0x0064 /* IP Differentiated Services + CodePoint to Priority0 high*/ +#define ETH__EDSCP2P1L 0x0068 /* IP Differentiated Services + CodePoint to Priority1 low */ +#define ETH__EDSCP2P1H 0x006c /* IP Differentiated Services + CodePoint to Priority1 high*/ +#define ETH__EVPT2P 0x0068 /* VLAN Prio. Tag to Priority */ +#define ETH__EMIBCTRS 0x0100 /* MIB Counters */ + +/* SKF : we are only concerned with the Ethernet0 for the mvme5500 board */ +#define ETH0_EBASE 0x2400 /* Base of Registers */ +#define ETH0_EPCR 0x2400 /* Port Config. Register */ +#define ETH0_EPCXR 0x2408 /* Port Config. Extend Reg */ +#define ETH0_EPCMR 0x2410 /* Port Command Register */ +#define ETH0_EPSR 0x2418 /* Port Status Register */ +#define ETH0_ESPR 0x2420 /* Port Serial Parameters Reg */ +#define ETH0_EHTPR 0x2428 /* Port Hash Table Pointer Reg*/ +#define ETH0_EFCSAL 0x2430 /* Flow Control Src Addr Low */ +#define ETH0_EFCSAH 0x2438 /* Flow Control Src Addr High */ +#define ETH0_ESDCR 0x2440 /* SDMA Configuration Reg */ +#define ETH0_ESDCMR 0x2448 /* SDMA Command Register */ +#define ETH0_EICR 0x2450 /* Interrupt Cause Register */ +#define ETH0_EIMR 0x2458 /* Interrupt Mask Register */ +#define ETH0_EFRDP0 0x2480 /* First Rx Desc Pointer 0 */ +#define ETH0_EFRDP1 0x2484 /* First Rx Desc Pointer 1 */ +#define ETH0_EFRDP2 0x2488 /* First Rx Desc Pointer 2 */ +#define ETH0_EFRDP3 0x248c /* First Rx Desc Pointer 3 */ +#define ETH0_ECRDP0 0x24a0 /* Current Rx Desc Pointer 0 */ +#define ETH0_ECRDP1 0x24a4 /* Current Rx Desc Pointer 1 */ +#define ETH0_ECRDP2 0x24a8 /* Current Rx Desc Pointer 2 */ +#define ETH0_ECRDP3 0x24ac /* Current Rx Desc Pointer 3 */ +#define ETH0_ECTDP0 0x24e0 /* Current Tx Desc Pointer 0 */ +#define ETH0_ECTDP1 0x24e4 /* Current Tx Desc Pointer 1 */ +#define ETH0_EDSCP2P0L 0x2460 /* IP Differentiated Services + CodePoint to Priority0 low */ +#define ETH0_EDSCP2P0H 0x2464 /* IP Differentiated Services + CodePoint to Priority0 high*/ +#define ETH0_EDSCP2P1L 0x2468 /* IP Differentiated Services + CodePoint to Priority1 low */ +#define ETH0_EDSCP2P1H 0x246c /* IP Differentiated Services + CodePoint to Priority1 high*/ +#define ETH0_EVPT2P 0x2468 /* VLAN Prio. Tag to Priority */ +#define ETH0_EMIBCTRS 0x2500 /* MIB Counters */ + +#define ETH_BASE(n) ETH__GEN(n, EBASE) +#define ETH_EPCR(n) ETH__GEN(n, EPCR) /* Port Config. Register */ +#define ETH_EPCXR(n) ETH__GEN(n, EPCXR) /* Port Config. Extend Reg */ +#define ETH_EPCMR(n) ETH__GEN(n, EPCMR) /* Port Command Register */ +#define ETH_EPSR(n) ETH__GEN(n, EPSR) /* Port Status Register */ +#define ETH_ESPR(n) ETH__GEN(n, ESPR) /* Port Serial Parameters Reg */ +#define ETH_EHTPR(n) ETH__GEN(n, EHPTR) /* Port Hash Table Pointer Reg*/ +#define ETH_EFCSAL(n) ETH__GEN(n, EFCSAL) /* Flow Control Src Addr Low */ +#define ETH_EFCSAH(n) ETH__GEN(n, EFCSAH) /* Flow Control Src Addr High */ +#define ETH_ESDCR(n) ETH__GEN(n, ESDCR) /* SDMA Configuration Reg */ +#define ETH_ESDCMR(n) ETH__GEN(n, ESDCMR) /* SDMA Command Register */ +#define ETH_EICR(n) ETH__GEN(n, EICR) /* Interrupt Cause Register */ +#define ETH_EIMR(n) ETH__GEN(n, EIMR) /* Interrupt Mask Register */ +#define ETH_EFRDP0(n) ETH__GEN(n, EFRDP0) /* First Rx Desc Pointer 0 */ +#define ETH_EFRDP1(n) ETH__GEN(n, EFRDP1) /* First Rx Desc Pointer 1 */ +#define ETH_EFRDP2(n) ETH__GEN(n, EFRDP2) /* First Rx Desc Pointer 2 */ +#define ETH_EFRDP3(n) ETH__GEN(n, EFRDP3) /* First Rx Desc Pointer 3 */ +#define ETH_ECRDP0(n) ETH__GEN(n, ECRDP0) /* Current Rx Desc Pointer 0 */ +#define ETH_ECRDP1(n) ETH__GEN(n, ECRDP1) /* Current Rx Desc Pointer 1 */ +#define ETH_ECRDP2(n) ETH__GEN(n, ECRDP2) /* Current Rx Desc Pointer 2 */ +#define ETH_ECRDP3(n) ETH__GEN(n, ECRDP3) /* Current Rx Desc Pointer 3 */ +#define ETH_ECTDP0(n) ETH__GEN(n, ECTDP0) /* Current Tx Desc Pointer 0 */ +#define ETH_ECTDP1(n) ETH__GEN(n, ECTDP1) /* Current Tx Desc Pointer 1 */ +#define ETH_EDSCP2P0L(n) ETH__GEN(n, EDSCP2P0L) /* IP Differentiated Services + CodePoint to Priority0 low */ +#define ETH_EDSCP2P0H(n) ETH__GEN(n, EDSCP2P0H) /* IP Differentiated Services + CodePoint to Priority0 high*/ +#define ETH_EDSCP2P1L(n) ETH__GEN(n, EDSCP2P1L) /* IP Differentiated Services + CodePoint to Priority1 low */ +#define ETH_EDSCP2P1H(n) ETH__GEN(n, EDSCP1P1H) /* IP Differentiated Services + CodePoint to Priority1 high*/ +#define ETH_EVPT2P(n) ETH__GEN(n, EVPT2P) /* VLAN Prio. Tag to Priority */ +#define ETH_EMIBCTRS(n) ETH__GEN(n, EMIBCTRS) /* MIB Counters */ + +#define ETH_EPAR_PhyAD_GET(v, n) (((v) >> ((n) * 5)) & 0x1f) + +#define ETH_ESMIR_READ(phy, reg) (ETH__INS(phy, 16)|\ + ETH__INS(reg, 21)|\ + ETH_ESMIR_ReadOpcode) +#define ETH_ESMIR_WRITE(phy, reg, val) (ETH__INS(phy, 16)|\ + ETH__INS(reg, 21)|\ + ETH__INS(val, 0)|\ + ETH_ESMIR_WriteOpcode) +#define ETH_ESMIR_Value_GET(v) ETH__EXT(v, 0, 16) +#define ETH_ESMIR_WriteOpcode 0 +#define ETH_ESMIR_ReadOpcode ETH__BIT(26) +#define ETH_ESMIR_ReadValid ETH__BIT(27) +#define ETH_ESMIR_Busy ETH__BIT(28) + +/* + * Table 597: Port Configuration Register (PCR) + * 00:00 PM Promiscuous mode + * 0: Normal mode (Frames are only received if the + * destination address is found in the hash + * table) + * 1: Promiscuous mode (Frames are received + * regardless of their destination address. + * Errored frames are discarded unless the Port + * Configuration register's PBF bit is set) + * 01:01 RBM Reject Broadcast Mode + * 0: Receive broadcast address + * 1: Reject frames with broadcast address + * Overridden by the promiscuous mode. + * 02:02 PBF Pass Bad Frames + * (0: Normal mode, 1: Pass bad Frames) + * The Ethernet receiver passes to the CPU errored + * frames (like fragments and collided packets) + * that are normally rejected. + * NOTE: Frames are only passed if they + * successfully pass address filtering. + * 06:03 Reserved + * 07:07 EN Enable (0: Disabled, 1: Enable) + * When enabled, the ethernet port is ready to + * transmit/receive. + * 09:08 LPBK Loop Back Mode + * 00: Normal mode + * 01: Internal loop back mode (TX data is looped + * back to the RX lines. No transition is seen + * on the interface pins) + * 10: External loop back mode (TX data is looped + * back to the RX lines and also transmitted + * out to the MII interface pins) + * 11: Reserved + * 10:10 FC Force Collision + * 0: Normal mode. + * 1: Force Collision on any TX frame. + * For RXM test (in Loopback mode). + * 11:11 Reserved. + * 12:12 HS Hash Size + * 0: 8K address filtering + * (256KB of memory space required). + * 1: 512 address filtering + * ( 16KB of memory space required). + * 13:13 HM Hash Mode (0: Hash Func. 0; 1: Hash Func. 1) + * 14:14 HDM Hash Default Mode + * 0: Discard addresses not found in address table + * 1: Pass addresses not found in address table + * 15:15 HD Duplex Mode (0: Half Duplex, 1: Full Duplex) + * NOTE: Valid only when auto-negotiation for + * duplex mode is disabled. + * 30:16 Reserved + * 31:31 ACCS Accelerate Slot Time + * (0: Normal mode, 1: Reserved) + */ +#define ETH_EPCR_PM ETH__BIT(0) +#define ETH_EPCR_RBM ETH__BIT(1) +#define ETH_EPCR_PBF ETH__BIT(2) +#define ETH_EPCR_EN ETH__BIT(7) +#define ETH_EPCR_LPBK_GET(v) ETH__BIT(v, 8, 2) +#define ETH_EPCR_LPBK_Normal 0 +#define ETH_EPCR_LPBK_Internal 1 +#define ETH_EPCR_LPBK_External 2 +#define ETH_EPCR_FC ETH__BIT(10) + +#define ETH_EPCR_HS ETH__BIT(12) +#define ETH_EPCR_HS_8K 0 +#define ETH_EPCR_HS_512 ETH_EPCR_HS + +#define ETH_EPCR_HM ETH__BIT(13) +#define ETH_EPCR_HM_0 0 +#define ETH_EPCR_HM_1 ETH_EPCR_HM + +#define ETH_EPCR_HDM ETH__BIT(14) +#define ETH_EPCR_HDM_Discard 0 +#define ETH_EPCR_HDM_Pass ETH_EPCR_HDM + +#define ETH_EPCR_HD_Half 0 +#define ETH_EPCR_HD_Full ETH_EPCR_HD_Full + +#define ETH_EPCR_ACCS ETH__BIT(31) + + + +/* + * Table 598: Port Configuration Extend Register (PCXR) + * 00:00 IGMP IGMP Packets Capture Enable + * 0: IGMP packets are treated as normal Multicast + * packets. + * 1: IGMP packets on IPv4/Ipv6 over Ethernet/802.3 + * are trapped and sent to high priority RX + * queue. + * 01:01 SPAN Spanning Tree Packets Capture Enable + * 0: BPDU (Bridge Protocol Data Unit) packets are + * treated as normal Multicast packets. + * 1: BPDU packets are trapped and sent to high + * priority RX queue. + * 02:02 PAR Partition Enable (0: Normal, 1: Partition) + * When more than 61 collisions occur while + * transmitting, the port enters Partition mode. + * It waits for the first good packet from the + * wire and then goes back to Normal mode. Under + * Partition mode it continues transmitting, but + * it does not receive. + * 05:03 PRIOtx Priority weight in the round-robin between high + * and low priority TX queues. + * 000: 1 pkt from HIGH, 1 pkt from LOW. + * 001: 2 pkt from HIGH, 1 pkt from LOW. + * 010: 4 pkt from HIGH, 1 pkt from LOW. + * 011: 6 pkt from HIGH, 1 pkt from LOW. + * 100: 8 pkt from HIGH, 1 pkt from LOW. + * 101: 10 pkt from HIGH, 1 pkt from LOW. + * 110: 12 pkt from HIGH, 1 pkt from LOW. + * 111: All pkt from HIGH, 0 pkt from LOW. LOW is + * served only if HIGH is empty. + * NOTE: If the HIGH queue is emptied before + * finishing the count, the count is reset + * until the next first HIGH comes in. + * 07:06 PRIOrx Default Priority for Packets Received on this + * Port (00: Lowest priority, 11: Highest priority) + * 08:08 PRIOrx_Override Override Priority for Packets Received on this + * Port (0: Do not override, 1: Override with + * field) + * 09:09 DPLXen Enable Auto-negotiation for Duplex Mode + * (0: Enable, 1: Disable) + * 11:10 FCTLen Enable Auto-negotiation for 802.3x Flow-control + * 0: Enable; When enabled, 1 is written (through + * SMI access) to the PHY's register 4 bit 10 + * to advertise flow-control capability. + * 1: Disable; Only enables flow control after the + * PHY address is set by the CPU. When changing + * the PHY address the flow control + * auto-negotiation must be disabled. + * 11:11 FLP Force Link Pass + * (0: Force Link Pass, 1: Do NOT Force Link pass) + * 12:12 FCTL 802.3x Flow-Control Mode (0: Enable, 1: Disable) + * NOTE: Only valid when auto negotiation for flow + * control is disabled. + * 13:13 Reserved + * 15:14 MFL Max Frame Length + * Maximum packet allowed for reception (including + * CRC): 00: 1518 bytes, 01: 1536 bytes, + * 10: 2048 bytes, 11: 64K bytes + * 16:16 MIBclrMode MIB Counters Clear Mode (0: Clear, 1: No effect) + * 17:17 MIBctrMode Reserved. (MBZ) + * 18:18 Speed Port Speed (0: 10Mbit/Sec, 1: 100Mbit/Sec) + * NOTE: Only valid if SpeedEn bit is set. + * 19:19 SpeedEn Enable Auto-negotiation for Speed + * (0: Enable, 1: Disable) + * 20:20 RMIIen RMII enable + * 0: Port functions as MII port + * 1: Port functions as RMII port + * 21:21 DSCPen DSCP enable + * 0: IP DSCP field decoding is disabled. + * 1: IP DSCP field decoding is enabled. + * 31:22 Reserved + */ +#define ETH_EPCXR_IGMP ETH__BIT(0) +#define ETH_EPCXR_SPAN ETH__BIT(1) +#define ETH_EPCXR_PAR ETH__BIT(2) +#define ETH_EPCXR_PRIOtx_GET(v) ETH__EXT(v, 3, 3) +#define ETH_EPCXR_PRIOrx_GET(v) ETH__EXT(v, 3, 3) +#define ETH_EPCXR_PRIOrx_Override ETH__BIT(8) +#define ETH_EPCXR_DLPXen ETH__BIT(9) +#define ETH_EPCXR_FCTLen ETH__BIT(10) +#define ETH_EPCXR_FLP ETH__BIT(11) +#define ETH_EPCXR_FCTL ETH__BIT(12) +#define ETH_EPCXR_MFL_GET(v) ETH__EXT(v, 14, 2) +#define ETH_EPCXR_MFL_1518 0 +#define ETH_EPCXR_MFL_1536 1 +#define ETH_EPCXR_MFL_2048 2 +#define ETH_EPCXR_MFL_64K 3 +#define ETH_EPCXR_MIBclrMode ETH__BIT(16) +#define ETH_EPCXR_MIBctrMode ETH__BIT(17) +#define ETH_EPCXR_Speed ETH__BIT(18) +#define ETH_EPCXR_SpeedEn ETH__BIT(19) +#define ETH_EPCXR_RMIIEn ETH__BIT(20) +#define ETH_EPCXR_DSCPEn ETH__BIT(21) + + + +/* + * Table 599: Port Command Register (PCMR) + * 14:00 Reserved + * 15:15 FJ Force Jam / Flow Control + * When in half-duplex mode, the CPU uses this bit + * to force collisions on the Ethernet segment. + * When the CPU recognizes that it is going to run + * out of receive buffers, it can force the + * transmitter to send jam frames, forcing + * collisions on the wire. To allow transmission + * on the Ethernet segment, the CPU must clear the + * FJ bit when more resources are available. When + * in full-duplex and flow-control is enabled, this + * bit causes the port's transmitter to send + * flow-control PAUSE packets. The CPU must reset + * this bit when more resources are available. + * 31:16 Reserved + */ + +#define ETH_EPCMR_FJ ETH__BIT(15) + + +/* + * Table 600: Port Status Register (PSR) -- Read Only + * 00:00 Speed Indicates Port Speed (0: 10Mbs, 1: 100Mbs) + * 01:01 Duplex Indicates Port Duplex Mode (0: Half, 1: Full) + * 02:02 Fctl Indicates Flow-control Mode + * (0: enabled, 1: disabled) + * 03:03 Link Indicates Link Status (0: down, 1: up) + * 04:04 Pause Indicates that the port is in flow-control + * disabled state. This bit is set when an IEEE + * 802.3x flow-control PAUSE (XOFF) packet is + * received (assuming that flow-control is + * enabled and the port is in full-duplex mode). + * Reset when XON is received, or when the XOFF + * timer has expired. + * 05:05 TxLow Tx Low Priority Status + * Indicates the status of the low priority + * transmit queue: (0: Stopped, 1: Running) + * 06:06 TxHigh Tx High Priority Status + * Indicates the status of the high priority + * transmit queue: (0: Stopped, 1: Running) + * 07:07 TXinProg TX in Progress + * Indicates that the port's transmitter is in an + * active transmission state. + * 31:08 Reserved + */ +#define ETH_EPSR_Speed ETH__BIT(0) +#define ETH_EPSR_Duplex ETH__BIT(1) +#define ETH_EPSR_Fctl ETH__BIT(2) +#define ETH_EPSR_Link ETH__BIT(3) +#define ETH_EPSR_Pause ETH__BIT(4) +#define ETH_EPSR_TxLow ETH__BIT(5) +#define ETH_EPSR_TxHigh ETH__BIT(6) +#define ETH_EPSR_TXinProg ETH__BIT(7) + + +/* + * Table 601: Serial Parameters Register (SPR) + * 01:00 JAM_LENGTH Two bits to determine the JAM Length + * (in Backpressure) as follows: + * 00 = 12K bit-times + * 01 = 24K bit-times + * 10 = 32K bit-times + * 11 = 48K bit-times + * 06:02 JAM_IPG Five bits to determine the JAM IPG. + * The step is four bit-times. The value may vary + * between 4 bit time to 124. + * 11:07 IPG_JAM_TO_DATA Five bits to determine the IPG JAM to DATA. + * The step is four bit-times. The value may vary + * between 4 bit time to 124. + * 16:12 IPG_DATA Inter-Packet Gap (IPG) + * The step is four bit-times. The value may vary + * between 12 bit time to 124. + * NOTE: These bits may be changed only when the + * Ethernet ports is disabled. + * 21:17 Data_Blind Data Blinder + * The number of nibbles from the beginning of the + * IPG, in which the IPG counter is restarted when + * detecting a carrier activity. Following this + * value, the port enters the Data Blinder zone and + * does not reset the IPG counter. This ensures + * fair access to the medium. + * The default is 10 hex (64 bit times - 2/3 of the + * default IPG). The step is 4 bit-times. Valid + * range is 3 to 1F hex nibbles. + * NOTE: These bits may be only changed when the + * Ethernet port is disabled. + * 22:22 Limit4 The number of consecutive packet collisions that + * occur before the collision counter is reset. + * 0: The port resets its collision counter after + * 16 consecutive retransmit trials and + * restarts the Backoff algorithm. + * 1: The port resets its collision counter and + * restarts the Backoff algorithm after 4 + * consecutive transmit trials. + * 31:23 Reserved + */ +#define ETH_ESPR_JAM_LENGTH_GET(v) ETH__EXT(v, 0, 2) +#define ETH_ESPR_JAM_IPG_GET(v) ETH__EXT(v, 2, 5) +#define ETH_ESPR_IPG_JAM_TO_DATA_GET(v) ETH__EXT(v, 7, 5) +#define ETH_ESPR_IPG_DATA_GET(v) ETH__EXT(v, 12, 5) +#define ETH_ESPR_Data_Bilnd_GET(v) ETH__EXT(v, 17, 5) +#define ETH_ESPR_Limit4(v) ETH__BIT(22) + +/* + * Table 602: Hash Table Pointer Register (HTPR) + * 31:00 HTP 32-bit pointer to the address table. + * Bits [2:0] must be set to zero. + */ + +/* + * Table 603: Flow Control Source Address Low (FCSAL) + * 15:0 SA[15:0] Source Address + * The least significant bits of the source + * address for the port. This address is used for + * Flow Control. + * 31:16 Reserved + */ + +/* + * Table 604: Flow Control Source Address High (FCSAH) + * 31:0 SA[47:16] Source Address + * The most significant bits of the source address + * for the port. This address is used for Flow + * Control. + */ + + +/* + * Table 605: SDMA Configuration Register (SDCR) + * 01:00 Reserved + * 05:02 RC Retransmit Count + * Sets the maximum number of retransmits per + * packet. After executing retransmit for RC + * times, the TX SDMA closes the descriptor with a + * Retransmit Limit error indication and processes + * the next packet. When RC is set to 0, the + * number of retransmits is unlimited. In this + * case, the retransmit process is only terminated + * if CPU issues an Abort command. + * 06:06 BLMR Big/Little Endian Receive Mode + * The DMA supports Big or Little Endian + * configurations on a per channel basis. The BLMR + * bit only affects data transfer to memory. + * 0: Big Endian + * 1: Little Endian + * 07:07 BLMT Big/Little Endian Transmit Mode + * The DMA supports Big or Little Endian + * configurations on a per channel basis. The BLMT + * bit only affects data transfer from memory. + * 0: Big Endian + * 1: Little Endian + * 08:08 POVR PCI Override + * When set, causes the SDMA to direct all its + * accesses in PCI_0 direction and overrides + * normal address decoding process. + * 09:09 RIFB Receive Interrupt on Frame Boundaries + * When set, the SDMA Rx generates interrupts only + * on frame boundaries (i.e. after writing the + * frame status to the descriptor). + * 11:10 Reserved + * 13:12 BSZ Burst Size + * Sets the maximum burst size for SDMA + * transactions: + * 00: Burst is limited to 1 64bit words. + * 01: Burst is limited to 2 64bit words. + * 10: Burst is limited to 4 64bit words. + * 11: Burst is limited to 8 64bit words. + * 31:14 Reserved + */ +#define ETH_ESDCR_RC_GET(v) ETH__EXT(v, 2, 4) +#define ETH_ESDCR_BLMR ETH__BIT(6) +#define ETH_ESDCR_BLMT ETH__BIT(7) +#define ETH_ESDCR_POVR ETH__BIT(8) +#define ETH_ESDCR_RIFB ETH__BIT(9) +#define ETH_ESDCR_BSZ_GET(v) ETH__EXT(v, 12, 2) +#define ETH_ESDCR_BSZ_SET(v, n) (ETH__CLR(v, 12, 2),\ + (v) |= ETH__INS(n, 12)) +#define ETH_ESDCR_BSZ_1 0 +#define ETH_ESDCR_BSZ_2 1 +#define ETH_ESDCR_BSZ_4 2 +#define ETH_ESDCR_BSZ_8 3 + +#define ETH_ESDCR_BSZ_Strings { "1 64-bit word", "2 64-bit words", \ + "4 64-bit words", "8 64-bit words" } + +/* + * Table 606: SDMA Command Register (SDCMR) + * 06:00 Reserved + * 07:07 ERD Enable RX DMA. + * Set to 1 by the CPU to cause the SDMA to start + * a receive process. Cleared when the CPU issues + * an Abort Receive command. + * 14:08 Reserved + * 15:15 AR Abort Receive + * Set to 1 by the CPU to abort a receive SDMA + * operation. When the AR bit is set, the SDMA + * aborts its current operation and moves to IDLE. + * No descriptor is closed. The AR bit is cleared + * upon entering IDLE. After setting the AR bit, + * the CPU must poll the bit to verify that the + * abort sequence is completed. + * 16:16 STDH Stop TX High + * Set to 1 by the CPU to stop the transmission + * process from the high priority queue at the end + * of the current frame. An interrupt is generated + * when the stop command has been executed. + * Writing 1 to STDH resets TXDH bit. + * Writing 0 to this bit has no effect. + * 17:17 STDL Stop TX Low + * Set to 1 by the CPU to stop the transmission + * process from the low priority queue at the end + * of the current frame. An interrupt is generated + * when the stop command has been executed. + * Writing 1 to STDL resets TXDL bit. + * Writing 0 to this bit has no effect. + * 22:18 Reserved + * 23:23 TXDH Start Tx High + * Set to 1 by the CPU to cause the SDMA to fetch + * the first descriptor and start a transmit + * process from the high priority Tx queue. + * Writing 1 to TXDH resets STDH bit. + * Writing 0 to this bit has no effect. + * 24:24 TXDL Start Tx Low + * Set to 1 by the CPU to cause the SDMA to fetch + * the first descriptor and start a transmit + * process from the low priority Tx queue. + * Writing 1 to TXDL resets STDL bit. + * Writing 0 to this bit has no effect. + * 30:25 Reserved + * 31:31 AT Abort Transmit + * Set to 1 by the CPU to abort a transmit DMA + * operation. When the AT bit is set, the SDMA + * aborts its current operation and moves to IDLE. + * No descriptor is closed. Cleared upon entering + * IDLE. After setting AT bit, the CPU must poll + * it in order to verify that the abort sequence + * is completed. + */ +#define ETH_ESDCMR_ERD ETH__BIT(7) +#define ETH_ESDCMR_AR ETH__BIT(15) +#define ETH_ESDCMR_STDH ETH__BIT(16) +#define ETH_ESDCMR_STDL ETH__BIT(17) +#define ETH_ESDCMR_TXDH ETH__BIT(23) +#define ETH_ESDCMR_TXDL ETH__BIT(24) +#define ETH_ESDCMR_AT ETH__BIT(31) + +/* + * Table 607: Interrupt Cause Register (ICR) + * 00:00 RxBuffer Rx Buffer Return + * Indicates an Rx buffer returned to CPU ownership + * or that the port finished reception of a Rx + * frame in either priority queues. + * NOTE: In order to get a Rx Buffer return per + * priority queue, use bit 19:16. This bit is + * set upon closing any Rx descriptor which + * has its EI bit set. To limit the + * interrupts to frame (rather than buffer) + * boundaries, the user must set SDMA + * Configuration register's RIFB bit. When + * the RIFB bit is set, an interrupt + * generates only upon closing the first + * descriptor of a received packet, if this + * descriptor has it EI bit set. + * 01:01 Reserved + * 02:02 TxBufferHigh Tx Buffer for High priority Queue + * Indicates a Tx buffer returned to CPU ownership + * or that the port finished transmission of a Tx + * frame. + * NOTE: This bit is set upon closing any Tx + * descriptor which has its EI bit set. To + * limit the interrupts to frame (rather than + * buffer) boundaries, the user must set EI + * only in the last descriptor. + * 03:03 TxBufferLow Tx Buffer for Low Priority Queue + * Indicates a Tx buffer returned to CPU ownership + * or that the port finished transmission of a Tx + * frame. + * NOTE: This bit is set upon closing any Tx + * descriptor which has its EI bit set. To + * limit the interrupts to frame (rather than + * buffer) boundaries, the user must set EI + * only in the last descriptor. + * 05:04 Reserved + * 06:06 TxEndHigh Tx End for High Priority Queue + * Indicates that the Tx DMA stopped processing the + * high priority queue after stop command, or that + * it reached the end of the high priority + * descriptor chain. + * 07:07 TxEndLow Tx End for Low Priority Queue + * Indicates that the Tx DMA stopped processing the + * low priority queue after stop command, or that + * it reached the end of the low priority + * descriptor chain. + * 08:08 RxError Rx Resource Error + * Indicates a Rx resource error event in one of + * the priority queues. + * NOTE: To get a Rx Resource Error Indication per + * priority queue, use bit 23:20. + * 09:09 Reserved + * 10:10 TxErrorHigh Tx Resource Error for High Priority Queue + * Indicates a Tx resource error event during + * packet transmission from the high priority queue + * 11:11 TxErrorLow Tx Resource Error for Low Priority Queue + * Indicates a Tx resource error event during + * packet transmission from the low priority queue + * 12:12 RxOVR Rx Overrun + * Indicates an overrun event that occurred during + * reception of a packet. + * 13:13 TxUdr Tx Underrun + * Indicates an underrun event that occurred during + * transmission of packet from either queue. + * 15:14 Reserved + * 16:16 RxBuffer-Queue[0] Rx Buffer Return in Priority Queue[0] + * Indicates a Rx buffer returned to CPU ownership + * or that the port completed reception of a Rx + * frame in a receive priority queue[0] + * 17:17 RxBuffer-Queue[1] Rx Buffer Return in Priority Queue[1] + * Indicates a Rx buffer returned to CPU ownership + * or that the port completed reception of a Rx + * frame in a receive priority queue[1]. + * 18:18 RxBuffer-Queue[2] Rx Buffer Return in Priority Queue[2] + * Indicates a Rx buffer returned to CPU ownership + * or that the port completed reception of a Rx + * frame in a receive priority queue[2]. + * 19:19 RxBuffer-Queue[3] Rx Buffer Return in Priority Queue[3] + * Indicates a Rx buffer returned to CPU ownership + * or that the port completed reception of a Rx + * frame in a receive priority queue[3]. + * 20:20 RxError-Queue[0] Rx Resource Error in Priority Queue[0] + * Indicates a Rx resource error event in receive + * priority queue[0]. + * 21:21 RxError-Queue[1] Rx Resource Error in Priority Queue[1] + * Indicates a Rx resource error event in receive + * priority queue[1]. + * 22:22 RxError-Queue[2] Rx Resource Error in Priority Queue[2] + * Indicates a Rx resource error event in receive + * priority queue[2]. + * 23:23 RxError-Queue[3] Rx Resource Error in Priority Queue[3] + * Indicates a Rx resource error event in receive + * priority queue[3]. + * 27:24 Reserved + * 28:29 MIIPhySTC MII PHY Status Change + * Indicates a status change reported by the PHY + * connected to this port. Set when the MII + * management interface block identifies a change + * in PHY's register 1. + * 29:29 SMIdone SMI Command Done + * Indicates that the SMI completed a MII + * management command (either read or write) that + * was initiated by the CPU writing to the SMI + * register. + * 30:30 Reserved + * 31:31 EtherIntSum Ethernet Interrupt Summary + * This bit is a logical OR of the (unmasked) bits + * [30:04] in the Interrupt Cause register. + */ + +#define ETH_IR_RxBuffer ETH__BIT(0) +#define ETH_IR_TxBufferHigh ETH__BIT(2) +#define ETH_IR_TxBufferLow ETH__BIT(3) +#define ETH_IR_TxEndHigh ETH__BIT(6) +#define ETH_IR_TxEndLow ETH__BIT(7) +#define ETH_IR_RxError ETH__BIT(8) +#define ETH_IR_TxErrorHigh ETH__BIT(10) +#define ETH_IR_TxErrorLow ETH__BIT(11) +#define ETH_IR_RxOVR ETH__BIT(12) +#define ETH_IR_TxUdr ETH__BIT(13) +#define ETH_IR_RxBuffer_0 ETH__BIT(16) +#define ETH_IR_RxBuffer_1 ETH__BIT(17) +#define ETH_IR_RxBuffer_2 ETH__BIT(18) +#define ETH_IR_RxBuffer_3 ETH__BIT(19) +#define ETH_IR_RxBuffer_GET(v) ETH__EXT(v, 16, 4) +#define ETH_IR_RxError_0 ETH__BIT(20) +#define ETH_IR_RxError_1 ETH__BIT(21) +#define ETH_IR_RxError_2 ETH__BIT(22) +#define ETH_IR_RxError_3 ETH__BIT(23) +#define ETH_IR_RxError_GET(v) ETH__EXT(v, 20, 4) +#define ETH_IR_RxBits (ETH_IR_RxBuffer_0|\ + ETH_IR_RxBuffer_1|\ + ETH_IR_RxBuffer_2|\ + ETH_IR_RxBuffer_3|\ + ETH_IR_RxError_0|\ + ETH_IR_RxError_1|\ + ETH_IR_RxError_2|\ + ETH_IR_RxError_3) +#define ETH_IR_MIIPhySTC ETH__BIT(28) +#define ETH_IR_SMIdone ETH__BIT(29) +#define ETH_IR_EtherIntSum (1<<31) +#define ETH_IR_Summary (1<<31) +#define ETH_IR_ErrorSum 0x803d00 +#define INTR_RX_ERROR 0x801100 +#define INTR_TX_ERROR 0x002c00 + +/* + * Table 608: Interrupt Mask Register (IMR) + * 31:00 Various Mask bits for the Interrupt Cause register. + */ + +/* + * Table 609: IP Differentiated Services CodePoint to Priority0 low (DSCP2P0L), + * 31:00 Priority0_low The LSB priority bits for DSCP[31:0] entries. + */ + +/* + * Table 610: IP Differentiated Services CodePoint to Priority0 high (DSCP2P0H) + * 31:00 Priority0_high The LSB priority bits for DSCP[63:32] entries. + */ + +/* + * Table 611: IP Differentiated Services CodePoint to Priority1 low (DSCP2P1L) + * 31:00 Priority1_low The MSB priority bits for DSCP[31:0] entries. + */ + +/* + * Table 612: IP Differentiated Services CodePoint to Priority1 high (DSCP2P1H) + * 31:00 Priority1_high The MSB priority bit for DSCP[63:32] entries. + */ + +/* + * Table 613: VLAN Priority Tag to Priority (VPT2P) + * 07:00 Priority0 The LSB priority bits for VLAN Priority[7:0] + * entries. + * 15:08 Priority1 The MSB priority bits for VLAN Priority[7:0] + * entries. + * 31:16 Reserved + */ +#endif /* _DEV_GTETHREG_H_ */ diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/Makefile.am b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/Makefile.am new file mode 100644 index 0000000000..1e00aaad5b --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_100MHz/Makefile.am @@ -0,0 +1,46 @@ +## +## $Id$ +## + +VPATH = @srcdir@: + +INCLUDES = -I @srcdir@/../GT64260 + +C_FILES = GT64260eth.c +include_bspdir = $(includedir)/bsp +include_bsp_HEADERS = GT64260eth.h GT64260ethreg.h + +H_FILES = GT64260eth.h GT64260ethreg.h + +C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) + +EXTRA_DIST = GT64260eth.c + +OBJS = $(C_O_FILES) + +include $(top_srcdir)/../../../../../../automake/compile.am +include $(top_srcdir)/../../../../../../automake/lib.am + +CFLAGS += -msoft-float + +# +# (OPTIONAL) Add local stuff here using += +# + +$(PROJECT_INCLUDE)/bsp: + $(mkinstalldirs) $< + +$(PROJECT_INCLUDE)/bsp/GT64260eth.h: GT64260eth.h + $(INSTALL_DATA) $< $@ + +$(PROJECT_INCLUDE)/bsp/GT64260ethreg.h: GT64260ethreg.h + $(INSTALL_DATA) $< $@ + + +# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile +PREINSTALL_FILES = $(PROJECT_INCLUDE)/bsp $(PROJECT_INCLUDE)/bsp/GT64260eth.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/GT64260ethreg.h + +all-local: $(ARCH) $(PREINSTALL_FILES) $(OBJS) + +include $(top_srcdir)/../../../../../../automake/local.am diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/Makefile.am b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/Makefile.am new file mode 100644 index 0000000000..9511e4822e --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/Makefile.am @@ -0,0 +1,45 @@ +## +## $Id$ +## + +VPATH = @srcdir@: + +INCLUDES = -I @srcdir@/../GT64260 + +C_FILES = if_wm.c pci_map.c +include_bspdir = $(includedir)/bsp +include_bsp_HEADERS = if_wmreg.h pcireg.h + +H_FILES = if_wmreg.h pcireg.h + +C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) + +EXTRA_DIST = if_wm.c pci_map.c + +OBJS = $(C_O_FILES) + +include $(top_srcdir)/../../../../../../automake/compile.am +include $(top_srcdir)/../../../../../../automake/lib.am + +CFLAGS += -msoft-float + +# +# (OPTIONAL) Add local stuff here using += +# + +$(PROJECT_INCLUDE)/bsp: + $(mkinstalldirs) $< + +$(PROJECT_INCLUDE)/bsp/if_wmreg.h: if_wmreg.h + $(INSTALL_DATA) $< $@ + +$(PROJECT_INCLUDE)/bsp/pcireg.h: pcireg.h + $(INSTALL_DATA) $< $@ + +# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/if_wmreg.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/pcireg.h + +all-local: $(ARCH) $(PREINSTALL_FILES) $(OBJS) + +include $(top_srcdir)/../../../../../../automake/local.am diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/POSSIBLEBUG b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/POSSIBLEBUG new file mode 100644 index 0000000000..b3a139a4ec --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/POSSIBLEBUG @@ -0,0 +1,4 @@ +S. Kate Feng , Sept. 06, 2007 + +This driver boots smoothly with the 1GHZ media. +It might not boot with the 10/100MHZ media. diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wm.c b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wm.c new file mode 100644 index 0000000000..453da7d9b1 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wm.c @@ -0,0 +1,1556 @@ +/* + * Copyright (c) 2004,2005 RTEMS/Mvme5500 port by S. Kate Feng + * Brookhaven National Laboratory, All rights reserved + * + * Acknowledgements: + * netBSD : Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. + * Jason R. Thorpe for Wasabi Systems, Inc. + * Intel : NDA document + * + * Some notes from the author, S. Kate Feng : + * + * 1) The error reporting routine i82544EI_error() employs two pointers + * for the error report buffer. One for the ISR and another one for + * the error report. + * 2) Enable the hardware Auto-Negotiation state machine. + * 3) Set Big Endian mode in the WMREG_CTRL so that we do not need htole32 + * because PPC is big endian mode. + * However, the data packet structure defined in if_wmreg.h + * should be redefined for the big endian mode. + * 4) To ensure the cache coherence, the MOTLoad had the PCI + * snoop control registers (0x1f00) set to "snoop to WB region" for + * the entire 512MB of memory. + * 5) MOTLoad default : + * little endian mode, cache line size is 32 bytes, no checksum control, + * hardware auto-neg. state machine disabled. PCI control "snoop + * to WB region", MII mode (PHY) instead of TBI mode. + * 6) We currently only use 32-bit (instead of 64-bit) DMA addressing. + * 7) Support for checksum offloading and TCP segmentation offload will + * be available for releasing in 2008, upon request, if I still believe. + * + */ + +#define BYTE_ORDER BIG_ENDIAN + +#define INET + +#include +#include /* printk */ +#include /* printf for statistics */ +#include + +#include /* inp & friends */ +#include /* registers.h is included here */ +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include /* SIOCADDMULTI, SIOC... */ +#include +#include +#include +#include + +#ifdef INET +#include +#endif + +#include +#include +#include +#include +#define WMREG_RADV 0x282c /* Receive Interrupt Absolute Delay Timer */ + +/*#define CKSUM_OFFLOAD*/ + +#define ETHERTYPE_FLOWCONTROL 0x8808 /* 802.3x flow control packet */ + +#define i82544EI_TASK_NAME "IGHZ" +#define SOFTC_ALIGN 4095 + +#define INTR_ERR_SIZE 16 + +/*#define WM_DEBUG*/ +#ifdef WM_DEBUG +#define WM_DEBUG_LINK 0x01 +#define WM_DEBUG_TX 0x02 +#define WM_DEBUG_RX 0x04 +#define WM_DEBUG_GMII 0x08 +int wm_debug = WM_DEBUG_TX|WM_DEBUG_RX|WM_DEBUG_LINK; + +#define DPRINTF(x, y) if (wm_debug & (x)) printk y +#else +#define DPRINTF(x, y) /* nothing */ +#endif /* WM_DEBUG */ + +/* RTEMS event to kill the daemon */ +#define KILL_EVENT RTEMS_EVENT_1 +/* RTEMS event to (re)start the transmitter */ +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 +/* RTEMS events used by the ISR */ +#define RX_EVENT RTEMS_EVENT_3 +#define TX_EVENT RTEMS_EVENT_4 +#define ERR_EVENT RTEMS_EVENT_5 +#define INIT_EVENT RTEMS_EVENT_6 + +#define ALL_EVENTS (KILL_EVENT|START_TRANSMIT_EVENT|RX_EVENT|TX_EVENT|ERR_EVENT|INIT_EVENT) + + +#define NTXDESC 128 +#define NTXDESC_MASK (NTXDESC - 1) +#define WM_NEXTTX(x) (((x) + 1) & NTXDESC_MASK) + +#define NRXDESC 64 +#define NRXDESC_MASK (NRXDESC - 1) +#define WM_NEXTRX(x) (((x) + 1) & NRXDESC_MASK) +#define WM_PREVRX(x) (((x) - 1) & NRXDESC_MASK) + +#define WM_CDOFF(x) offsetof(struct wm_control_data, x) +#define WM_CDTXOFF(x) WM_CDOFF(sc_txdescs[(x)]) +#define WM_CDRXOFF(x) WM_CDOFF(sc_rxdescs[(x)]) + +#define TXQ_HiLmt_OFF 64 + +static uint32_t TxDescCmd; + +/* + * Software state per device. + */ +struct wm_softc { + wiseman_txdesc_t sc_txdescs[NTXDESC]; /* transmit descriptor memory */ + wiseman_rxdesc_t sc_rxdescs[NRXDESC]; /* receive descriptor memory */ + struct mbuf *txs_mbuf[NTXDESC]; /* transmit buffer memory */ + struct mbuf *rxs_mbuf[NRXDESC]; /* receive buffer memory */ + struct wm_softc *next_module; + volatile unsigned int intr_errsts[INTR_ERR_SIZE]; /* intr_status */ + unsigned int intr_err_ptr1; /* ptr used in i82544EI_error() */ + unsigned int intr_err_ptr2; /* ptr used in ISR */ + int txs_firstdesc; /* first descriptor in packet */ + int txs_lastdesc; /* last descriptor in packet */ + int txs_ndesc; /* # of descriptors used */ + unsigned sc_membase; /* Memory space base address */ + unsigned sc_memsize; /* Memory space size */ + + char dv_xname[16]; /* external name (name + unit) */ + void *sc_sdhook; /* shutdown hook */ + struct arpcom arpcom; /* rtems if structure, contains ifnet */ + int sc_flags; /* flags; see below */ + int sc_bus_speed; /* PCI/PCIX bus speed */ + int sc_flowflags; /* 802.3x flow control flags */ + + void *sc_ih; /* interrupt cookie */ + + int sc_ee_addrbits; /* EEPROM address bits */ + rtems_id daemonTid; + rtems_id daemonSync; /* synchronization with the daemon */ + + int txq_next; /* next Tx descriptor ready for transmitting */ + uint32_t txq_nactive; /* number of active TX descriptors */ + uint32_t txq_fi; /* next free Tx descriptor */ + uint32_t txq_free; /* number of free Tx jobs */ + uint32_t sc_txctx_ipcs; /* cached Tx IP cksum ctx */ + uint32_t sc_txctx_tucs; /* cached Tx TCP/UDP cksum ctx */ + + int sc_rxptr; /* next ready Rx descriptor/queue ent */ + int sc_rxdiscard; + int sc_rxlen; + uint32_t sc_ctrl; /* prototype CTRL register */ +#if 0 + uint32_t sc_ctrl_ext; /* prototype CTRL_EXT register */ +#endif + uint32_t sc_icr; /* prototype interrupt bits */ + uint32_t sc_tctl; /* prototype TCTL register */ + uint32_t sc_rctl; /* prototype RCTL register */ + uint32_t sc_tipg; /* prototype TIPG register */ + uint32_t sc_fcrtl; /* prototype FCRTL register */ + + int sc_mchash_type; /* multicast filter offset */ + + /* statistics */ + struct { + volatile unsigned long rxInterrupts; + volatile unsigned long txInterrupts; + unsigned long txMultiBuffPacket; + unsigned long txMultiMaxLen; + unsigned long txSinglMaxLen; + unsigned long txMultiMaxLoop; + unsigned long txBuffMaxLen; + unsigned long linkInterrupts; + unsigned long length_errors; + unsigned long frame_errors; + unsigned long crc_errors; + unsigned long rxOvrRunInterrupts; /* Rx overrun interrupt */ + unsigned long rxSeqErr; + unsigned long rxC_ordered; + unsigned long ghostInterrupts; + unsigned long linkStatusChng; + } stats; +}; + +/* our memory address seen from the PCI bus should be 1:1 */ +#define htole32(x) le32toh(x) +#define le32toh(x) CPU_swap_u32((unsigned int) x) +#define le16toh(x) CPU_swap_u16(x) + +/* sc_flags */ +#define WM_F_HAS_MII 0x01 /* has MII */ +/* 82544 EI does not perform EEPROM handshake, EEPROM interface is not SPI */ +#define WM_F_EEPROM_HANDSHAKE 0x02 /* requires EEPROM handshake */ +#define WM_F_EEPROM_SPI 0x04 /* EEPROM is SPI */ +#define WM_F_IOH_VALID 0x10 /* I/O handle is valid */ +#define WM_F_BUS64 0x20 /* bus is 64-bit */ +#define WM_F_PCIX 0x40 /* bus is PCI-X */ + +#define CSR_READ(sc,reg) in_le32((volatile unsigned *)(sc->sc_membase+reg)) +#define CSR_WRITE(sc,reg,val) out_le32((volatile unsigned *)(sc->sc_membase+reg), val) + +#define WM_CDTXADDR(sc) ( (uint32_t) &sc->sc_txdescs[0] ) +#define WM_CDRXADDR(sc) ( (uint32_t) &sc->sc_rxdescs[0] ) + +static struct wm_softc *root_i82544EI_dev = NULL; + +static void i82544EI_ifstart(struct ifnet *ifp); +static int wm_ioctl(struct ifnet *ifp, u_long cmd,uint32_t data); +static void i82544EI_ifinit(void *arg); +static void wm_stop(struct ifnet *ifp, int disable); + +static void wm_rxdrain(struct wm_softc *sc); +static int wm_add_rxbuf(struct wm_softc *sc, int idx); +static int wm_read_eeprom(struct wm_softc *sc,int word,int wordcnt, uint16_t *data); +static void i82544EI_daemon(void *arg); +static void wm_set_filter(struct wm_softc *sc); + +static void i82544EI_isr(); +static void i82544EI_sendpacket(struct wm_softc *sc, struct mbuf *m); +extern int pci_mem_find(), pci_io_find(), pci_get_capability(); +extern char * ether_sprintf1(); + +static void i82544EI_irq_on(const rtems_irq_connect_data *irq) +{ + struct wm_softc *sc; + unsigned int irqMask= ICR_TXDW | ICR_LSC | ICR_RXSEQ | ICR_RXDMT0 | ICR_RXO | ICR_RXT0 | ICR_RXCFG; + + for (sc= root_i82544EI_dev; sc; sc= sc-> next_module) { + CSR_WRITE(sc,WMREG_IMS,(CSR_READ(sc,WMREG_IMS)| irqMask) ); + return; + } +} + +static void i82544EI_irq_off(const rtems_irq_connect_data *irq) +{ + struct wm_softc *sc; + unsigned int irqMask= ICR_TXDW | ICR_LSC | ICR_RXSEQ | ICR_RXDMT0 | ICR_RXO | ICR_RXT0 |ICR_RXCFG ; + + for (sc= root_i82544EI_dev; sc; sc= sc-> next_module) { + CSR_WRITE(sc,WMREG_IMS, (CSR_READ(sc,WMREG_IMS) & ~irqMask) ); + return; + } +} + +static int i82544EI_irq_is_on(const rtems_irq_connect_data *irq) +{ + return(CSR_READ(root_i82544EI_dev,WMREG_ICR) & root_i82544EI_dev->sc_icr); +} + +static rtems_irq_connect_data i82544IrqData={ + BSP_GPP_82544_IRQ, + (rtems_irq_hdl) i82544EI_isr, + (rtems_irq_enable) i82544EI_irq_on, + (rtems_irq_disable) i82544EI_irq_off, + (rtems_irq_is_enabled) i82544EI_irq_is_on, +}; + +int rtems_i82544EI_driver_attach(struct rtems_bsdnet_ifconfig *config, int attach) +{ + struct wm_softc *sc; + struct ifnet *ifp; + uint8_t enaddr[ETHER_ADDR_LEN]; + uint16_t myea[ETHER_ADDR_LEN / 2], cfg1, cfg2, swdpin; + unsigned reg; + int b,d,f; /* PCI bus/device/function */ + int unit; + void *softc_mem; + char *name; + + unit = rtems_bsdnet_parse_driver_name(config, &name); + if (unit < 0) return 0; + + printk("\nEthernet driver name %s unit %d \n",name, unit); + printk("Copyright (c) 2004,2005 S. Kate Feng (RTEMS/mvme5500 port)\n"); + + /* Make sure certain elements e.g. descriptor lists are aligned.*/ + softc_mem = rtems_bsdnet_malloc(sizeof(*sc) + SOFTC_ALIGN, M_FREE, M_NOWAIT); + + /* Check for the very unlikely case of no memory. */ + if (softc_mem == NULL) + rtems_panic("i82544EI: OUT OF MEMORY"); + + sc = (void *)(((long)softc_mem + SOFTC_ALIGN) & ~SOFTC_ALIGN); + memset(sc, 0, sizeof(*sc)); + + sprintf(sc->dv_xname, "%s%d", name, unit); + + if (pci_find_device(PCI_VENDOR_ID_INTEL,PCI_DEVICE_INTEL_82544EI_COPPER, + unit-1,&b, &d, &f)) + rtems_panic("i82544EI device ID not found\n"); + +#if WM_DEBUG + printk("82544EI:b%d, d%d, f%d\n", b, d,f); +#endif + + /* Memory-mapped acccess is required for normal operation.*/ + if ( pci_mem_find(b,d,f,PCI_MAPREG_START, &sc->sc_membase, &sc->sc_memsize)) + rtems_panic("i82544EI: unable to map memory space\n"); + +#ifdef WM_DEBUG + printk("Memory base addr 0x%x\n", sc->sc_membase); + printk("txdesc[0] addr:0x%x, rxdesc[0] addr:0x%x, sizeof sc %d\n",&sc->sc_txdescs[0], &sc->sc_rxdescs[0], sizeof(*sc)); +#endif + + + sc->sc_ctrl |=CSR_READ(sc,WMREG_CTRL); + /* + * Determine a few things about the bus we're connected to. + */ + reg = CSR_READ(sc,WMREG_STATUS); + if (reg & STATUS_BUS64) sc->sc_flags |= WM_F_BUS64; + sc->sc_bus_speed = (reg & STATUS_PCI66) ? 66 : 33; +#ifdef WM_DEBUG + printk("%s%d: %d-bit %dMHz PCI bus\n",name, unit, + (sc->sc_flags & WM_F_BUS64) ? 64 : 32, sc->sc_bus_speed); +#endif + + /* + * Setup some information about the EEPROM. + */ + + sc->sc_ee_addrbits = 6; + +#ifdef WM_DEBUG + printk("%s%d: %u word (%d address bits) MicroWire EEPROM\n", + name, unit, 1U << sc->sc_ee_addrbits, + sc->sc_ee_addrbits); +#endif + + /* + * Read the Ethernet address from the EEPROM. + */ + if (wm_read_eeprom(sc, EEPROM_OFF_MACADDR, + sizeof(myea) / sizeof(myea[0]), myea)) + rtems_panic("i82544ei 1GHZ ethernet: unable to read Ethernet address"); + + enaddr[0] = myea[0] & 0xff; + enaddr[1] = myea[0] >> 8; + enaddr[2] = myea[1] & 0xff; + enaddr[3] = myea[1] >> 8; + enaddr[4] = myea[2] & 0xff; + enaddr[5] = myea[2] >> 8; + + + memcpy(sc->arpcom.ac_enaddr, enaddr, ETHER_ADDR_LEN); +#ifdef WM_DEBUG + printk("%s: Ethernet address %s\n", sc->dv_xname, + ether_sprintf1(enaddr)); +#endif + + /* + * Read the config info from the EEPROM, and set up various + * bits in the control registers based on their contents. + */ + if (wm_read_eeprom(sc, EEPROM_OFF_CFG1, 1, &cfg1)) { + printk("%s: unable to read CFG1 from EEPROM\n",sc->dv_xname); + return(0); + } + if (wm_read_eeprom(sc, EEPROM_OFF_CFG2, 1, &cfg2)) { + printk("%s: unable to read CFG2 from EEPROM\n",sc->dv_xname); + return(0); + } + if (wm_read_eeprom(sc, EEPROM_OFF_SWDPIN, 1, &swdpin)) { + printk("%s: unable to read SWDPIN from EEPROM\n",sc->dv_xname); + return(0); + } + + if (cfg1 & EEPROM_CFG1_ILOS) sc->sc_ctrl |= CTRL_ILOS; + sc->sc_ctrl|=((swdpin >> EEPROM_SWDPIN_SWDPIO_SHIFT) & 0xf) << + CTRL_SWDPIO_SHIFT; + sc->sc_ctrl |= ((swdpin >> EEPROM_SWDPIN_SWDPIN_SHIFT) & 0xf) << + CTRL_SWDPINS_SHIFT; + + CSR_WRITE(sc,WMREG_CTRL, sc->sc_ctrl); +#if 0 + CSR_WRITE(sc,WMREG_CTRL_EXT, sc->sc_ctrl_ext); +#endif + + ifp = &sc->arpcom.ac_if; + /* set this interface's name and unit */ + ifp->if_unit = unit; + ifp->if_name = name; + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_mtu = config->mtu ? config->mtu : ETHERMTU; + ifp->if_ioctl = wm_ioctl; + ifp->if_start = i82544EI_ifstart; + /* ifp->if_watchdog = wm_watchdog;*/ + ifp->if_init = i82544EI_ifinit; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + ifp->if_output = ether_output; + + /* create the synchronization semaphore */ + if (RTEMS_SUCCESSFUL != rtems_semaphore_create( + rtems_build_name('I','G','H','Z'),0,0,0,&sc->daemonSync)) + rtems_panic("i82544EI: semaphore creation failed"); + + sc->next_module = root_i82544EI_dev; + root_i82544EI_dev = sc; + + /* Attach the interface. */ + if_attach(ifp); + ether_ifattach(ifp); +#ifdef WM_DEBUG + printk("82544EI: Ethernet driver has been attached (handle 0x%08x,ifp 0x%08x)\n",sc, ifp); +#endif + + return(1); +} + +/* + * i82544EI_ifstart: [ifnet interface function] + * + * Start packet transmission on the interface. + */ +static void +i82544EI_ifstart(struct ifnet *ifp) +{ + struct wm_softc *sc = ifp->if_softc; + +#ifdef WM_DEBUG + printk("i82544EI_ifstart("); +#endif + + if ((ifp->if_flags & IFF_RUNNING) == 0) { +#ifdef WM_DEBUG + printk("IFF_RUNNING==0\n"); +#endif + return; + } + + ifp->if_flags |= IFF_OACTIVE; + rtems_event_send (sc->daemonTid, START_TRANSMIT_EVENT); +#ifdef WM_DEBUG + printk(")\n"); +#endif +} + +static void i82544EI_stats(struct wm_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + + printf(" Rx Interrupts:%-8u\n", sc->stats.rxInterrupts); + printf(" Receive Packets:%-8u\n", CSR_READ(sc,WMREG_GPRC)); + printf(" Receive Overrun:%-8u\n", sc->stats.rxOvrRunInterrupts); + printf(" Receive errors:%-8u\n", CSR_READ(sc,WMREG_RXERRC)); + printf(" Rx sequence error:%-8u\n", sc->stats.rxSeqErr); + printf(" Rx /C/ ordered:%-8u\n", sc->stats.rxC_ordered); + printf(" Rx Length Errors:%-8u\n", CSR_READ(sc,WMREG_RLEC)); + printf(" Tx Interrupts:%-8u\n", sc->stats.txInterrupts); +#if 0 + printf("Multi-BuffTx Packets:%-8u\n", sc->stats.txMultiBuffPacket); + printf("Multi-BuffTx max len:%-8u\n", sc->stats.txMultiMaxLen); + printf("SingleBuffTx max len:%-8u\n", sc->stats.txSinglMaxLen); + printf("Multi-BuffTx maxloop:%-8u\n", sc->stats.txMultiMaxLoop); + printf("Tx buffer max len :%-8u\n", sc->stats.txBuffMaxLen); +#endif + printf(" Transmitt Packets:%-8u\n", CSR_READ(sc,WMREG_GPTC)); + printf(" Transmitt errors:%-8u\n", ifp->if_oerrors); + printf(" Active Txqs:%-8u\n", sc->txq_nactive); + printf(" collisions:%-8u\n", CSR_READ(sc,WMREG_COLC)); + printf(" Crc Errors:%-8u\n", CSR_READ(sc,WMREG_CRCERRS)); + printf(" Link Status Change:%-8u\n", sc->stats.linkStatusChng); +} + +/* + * wm_ioctl: [ifnet interface function] + * + * Handle control requests from the operator. + */ +static int wm_ioctl(struct ifnet *ifp, u_long cmd,uint32_t data) +{ + struct wm_softc *sc = ifp->if_softc; + int error=0; + + switch (cmd) { + default: + error = ether_ioctl(ifp, cmd, data); + if (error == ENETRESET) { + /* + * Multicast list has changed; set the hardware filter + * accordingly. + */ + wm_set_filter(sc); + error = 0; + } + break; + case SIO_RTEMS_SHOW_STATS: + i82544EI_stats(sc); + break; + } + + /* Try to get more packets going.*/ + i82544EI_ifstart(ifp); + return (error); +} + +/* + * wm_isr: + * + * Interrupt service routine. + */ +static void i82544EI_isr() +{ + volatile struct wm_softc *sc = root_i82544EI_dev; + uint32_t icr; + rtems_event_set events=0; + + /* Reading the WMREG_ICR clears the interrupt bits */ + icr = CSR_READ(sc,WMREG_ICR); + + if ( icr & (ICR_RXDMT0|ICR_RXT0)) { + sc->stats.rxInterrupts++; + events |= RX_EVENT; + } + + if (icr & ICR_TXDW) { + sc->stats.txInterrupts++; + events |= TX_EVENT; + } + /* Rx overrun : no available receive buffer + * or PCI receive bandwidth inadequate. + */ + if (icr & ICR_RXO) { + sc->stats.rxOvrRunInterrupts++; + events |= INIT_EVENT; + } + if (icr & ICR_RXSEQ) /* framing error */ { + sc->intr_errsts[sc->intr_err_ptr2++]=icr; + sc->intr_err_ptr2 %=INTR_ERR_SIZE; /* Till Straumann */ + events |= ERR_EVENT; + sc->stats.rxSeqErr++; + } + if ( !icr) sc->stats.ghostInterrupts++; + + if (icr & ICR_LSC) sc->stats.linkStatusChng++; + if (icr & ICR_RXCFG) sc->stats.rxC_ordered++; + + rtems_event_send(sc->daemonTid, events); +} + +/* + * i82544EI_sendpacket: + * + * Helper; handle transmit interrupts. + */ +static void i82544EI_sendpacket(struct wm_softc *sc, struct mbuf *m) +{ + +#ifdef WM_DEBUG_TX + printk("sendpacket("); +#endif + + if ( !(m->m_next)) { /* single buffer packet */ + sc->txs_mbuf[sc->txq_next]= m; + /* Note: we currently only use 32-bit DMA addresses. */ + sc->sc_txdescs[sc->txq_next].wtx_addr.wa_low = htole32(mtod(m, void*)); + sc->sc_txdescs[sc->txq_next].wtx_cmdlen =htole32(TxDescCmd | m->m_len); + sc->txs_lastdesc= sc->txq_next; + sc->txq_next = WM_NEXTTX(sc->txq_next); + sc->txq_nactive++; + sc->txq_free--; + } + else /* multiple mbufs in this packet */ + { + struct mbuf *mtp, *mdest; + volatile unsigned char *pt; + int len, y, loop=0; + +#ifdef WM_DEBUG_TX + printk("multi mbufs "); +#endif + mtp = m; + while ( mtp) { + MGETHDR(mdest, M_WAIT, MT_DATA); + MCLGET(mdest, M_WAIT); + pt = (volatile unsigned char *)mdest->m_data; + for ( len=0;mtp;mtp=mtp->m_next) { + loop++; + /* Each descriptor gets a 2k (MCLBYTES) buffer, although + * the length of each descriptor can be up to 16288 bytes. + * For packets which fill more than one buffer ( >2k), we + * chain them together. + * : This effective for packets > 2K + * The other way is effective for packets < 2K + */ + if ( ((y=(len+mtp->m_len)) > sizeof(union mcluster))) { + printk(">2048, use next descriptor\n"); + break; + } + memcpy((void *)pt,(char *)mtp->m_data, mtp->m_len); + pt += mtp->m_len; + len += mtp->m_len; +#if 0 + sc->stats.txSinglMaxLen= MAX(mtp->m_len, sc->stats.txSinglMaxLen); +#endif + } /* end for loop */ + mdest->m_len=len; + sc->txs_mbuf[sc->txq_next] = mdest; + /* Note: we currently only use 32-bit DMA addresses. */ + sc->sc_txdescs[sc->txq_next].wtx_addr.wa_low = htole32(mtod(mdest, void*)); + sc->sc_txdescs[sc->txq_next].wtx_cmdlen = htole32(TxDescCmd|mdest->m_len); + sc->txs_lastdesc = sc->txq_next; + sc->txq_next = WM_NEXTTX(sc->txq_next); + sc->txq_nactive ++; + if (sc->txq_free) + sc->txq_free--; + else + rtems_panic("i8254EI : no more free descriptors"); +#if 0 + sc->stats.txMultiMaxLen= MAX(mdest->m_len, sc->stats.txMultiMaxLen); + sc->stats.txMultiBuffPacket++; +#endif + } /* end for while */ + /* free old mbuf chain */ +#if 0 + sc->stats.txMultiMaxLoop=MAX(loop, sc->stats.txMultiMaxLoop); +#endif + m_freem(m); + m=0; + } /* end multiple mbufs */ + + DPRINTF(WM_DEBUG_TX,("%s: TX: desc %d: cmdlen 0x%08x\n", sc->dv_xname, + sc->txs_lastdesc, le32toh(sc->sc_txdescs[sc->txs_lastdesc].wtx_cmdlen))); + DPRINTF(WM_DEBUG_TX,("status 0x%08x\n",sc->sc_txdescs[sc->txq_fi].wtx_fields.wtxu_status)); + + memBar(); + + /* This is the location where software writes the first NEW descriptor */ + CSR_WRITE(sc,WMREG_TDT, sc->txq_next); + + DPRINTF(WM_DEBUG_TX,("%s: addr 0x%08x, TX: TDH %d, TDT %d\n",sc->dv_xname, + le32toh(sc->sc_txdescs[sc->txs_lastdesc].wtx_addr.wa_low), CSR_READ(sc,WMREG_TDH), + CSR_READ(sc,WMREG_TDT))); + + DPRINTF(WM_DEBUG_TX,("%s: TX: finished transmitting packet, job %d\n", + sc->dv_xname, sc->txq_next)); + +} + +static void i82544EI_txq_free(struct wm_softc *sc, uint8_t status) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + + /* We might use the statistics registers instead of variables + * to keep tack of the network statistics + */ + + /* statistics */ + ifp->if_opackets++; + + if (status & (WTX_ST_EC|WTX_ST_LC)) { + ifp->if_oerrors++; + + if (status & WTX_ST_LC) + printf("%s: late collision\n", sc->dv_xname); + else if (status & WTX_ST_EC) { + ifp->if_collisions += 16; + printf("%s: excessive collisions\n", sc->dv_xname); + } + } + /* Free the original mbuf chain */ + m_freem(sc->txs_mbuf[sc->txq_fi]); + sc->txs_mbuf[sc->txq_fi] = 0; + sc->sc_txdescs[sc->txq_fi].wtx_fields.wtxu_status=0; + + sc->txq_free ++; + sc->txq_fi = WM_NEXTTX(sc->txq_fi); + --sc->txq_nactive; +} + +static void i82544EI_txq_done(struct wm_softc *sc) +{ + uint8_t status; + + /* + * Go through the Tx list and free mbufs for those + * frames which have been transmitted. + */ + while ( sc->txq_nactive > 0) { + status = sc->sc_txdescs[sc->txq_fi].wtx_fields.wtxu_status; + if ((status & WTX_ST_DD) == 0) break; + i82544EI_txq_free(sc, status); + DPRINTF(WM_DEBUG_TX,("%s: TX: job %d done\n", + sc->dv_xname, sc->txq_fi)); + } +} + +static void wm_init_rxdesc(struct wm_softc *sc, int x) +{ + wiseman_rxdesc_t *__rxd = &(sc)->sc_rxdescs[(x)]; + struct mbuf *m; + + m = sc->rxs_mbuf[x]; + + __rxd->wrx_addr.wa_low=htole32(mtod(m, void*)); + __rxd->wrx_addr.wa_high = 0; + __rxd->wrx_len = 0; + __rxd->wrx_cksum = 0; + __rxd->wrx_status = 0; + __rxd->wrx_errors = 0; + __rxd->wrx_special = 0; + /* Receive Descriptor Tail: add Rx desc. to H/W free list */ + CSR_WRITE(sc,WMREG_RDT, (x)); +} + +static void i82544EI_rx(struct wm_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + int i, len; + uint8_t status, errors; + struct ether_header *eh; + +#ifdef WM_DEBUG + printk("i82544EI_rx()\n"); +#endif + + for (i = sc->sc_rxptr;; i = WM_NEXTRX(i)) { + DPRINTF(WM_DEBUG_RX, ("%s: RX: checking descriptor %d\n", + sc->dv_xname, i)); + + status = sc->sc_rxdescs[i].wrx_status; + errors = sc->sc_rxdescs[i].wrx_errors; + len = le16toh(sc->sc_rxdescs[i].wrx_len); + m = sc->rxs_mbuf[i]; + + if ((status & WRX_ST_DD) == 0) break; /* descriptor not done */ + + if (sc->sc_rxdiscard) { + printk("RX: discarding contents of descriptor %d\n", i); + wm_init_rxdesc(sc, i); + if (status & WRX_ST_EOP) { + /* Reset our state. */ + printk("RX: resetting rxdiscard -> 0\n"); + sc->sc_rxdiscard = 0; + } + continue; + } + + /* + * If an error occurred, update stats and drop the packet. + */ + if (errors &(WRX_ER_CE|WRX_ER_SE|WRX_ER_SEQ|WRX_ER_CXE|WRX_ER_RXE)) { + ifp->if_ierrors++; + if (errors & WRX_ER_SE) + printk("%s: symbol error\n",sc->dv_xname); + else if (errors & WRX_ER_SEQ) + printk("%s: receive sequence error\n",sc->dv_xname); + else if (errors & WRX_ER_CE) + printk("%s: CRC error\n",sc->dv_xname); + m_freem(m); + goto give_it_back; + } + + /* + * No errors. Receive the packet. + * + * Note, we have configured the chip to include the + * CRC with every packet. + */ + m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); + + DPRINTF(WM_DEBUG_RX,("%s: RX: buffer at %p len %d\n", + sc->dv_xname, m->m_data, len)); + + + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + /* Pass it on. */ + ifp->if_ipackets++; + + give_it_back: + /* Add a new receive buffer to the ring.*/ + if (wm_add_rxbuf(sc, i) != 0) { + /* + * Failed, throw away what we've done so + * far, and discard the rest of the packet. + */ + printk("Failed in wm_add_rxbuf(), drop packet\n"); + ifp->if_ierrors++; + wm_init_rxdesc(sc, i); + if ((status & WRX_ST_EOP) == 0) + sc->sc_rxdiscard = 1; + m_freem(m); + } + } /* end for */ + + /* Update the receive pointer. */ + sc->sc_rxptr = i; + DPRINTF(WM_DEBUG_RX, ("%s: RX: rxptr -> %d\n", sc->dv_xname, i)); +} + +static int i82544EI_init_hw(struct wm_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + int i,error; + uint8_t cksumfields; + + /* Cancel any pending I/O. */ + wm_stop(ifp, 0); + + /* Initialize the error buffer ring */ + sc->intr_err_ptr1=0; + sc->intr_err_ptr2=0; + for (i=0; i< INTR_ERR_SIZE; i++) sc->intr_errsts[i]=0; + + /* Initialize the transmit descriptor ring. */ + memset(sc->sc_txdescs, 0, sizeof(sc->sc_txdescs)); + sc->txq_free = NTXDESC; + sc->txq_next = 0; + sc->txs_lastdesc = 0; + sc->txq_next = 0; + sc->txq_free = NTXDESC; + sc->txq_nactive = 0; + + sc->sc_txctx_ipcs = 0xffffffff; + sc->sc_txctx_tucs = 0xffffffff; + + CSR_WRITE(sc,WMREG_TBDAH, 0); + CSR_WRITE(sc,WMREG_TBDAL, WM_CDTXADDR(sc)); +#ifdef WM_DEBUG + printk("TBDAL 0x%x, TDLEN %d\n", WM_CDTXADDR(sc), sizeof(sc->sc_txdescs)); +#endif + CSR_WRITE(sc,WMREG_TDLEN, sizeof(sc->sc_txdescs)); + CSR_WRITE(sc,WMREG_TDH, 0); + CSR_WRITE(sc,WMREG_TDT, 0); + CSR_WRITE(sc,WMREG_TIDV, 64 ); + CSR_WRITE(sc,WMREG_TADV, 128); + + CSR_WRITE(sc,WMREG_TXDCTL, TXDCTL_PTHRESH(0) | + TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0)); + CSR_WRITE(sc,WMREG_RXDCTL, RXDCTL_PTHRESH(0) | + RXDCTL_HTHRESH(0) | RXDCTL_WTHRESH(1) | RXDCTL_GRAN ); + + CSR_WRITE(sc,WMREG_TQSA_LO, 0); + CSR_WRITE(sc,WMREG_TQSA_HI, 0); + + /* + * Set up checksum offload parameters for + * this packet. + */ +#ifdef CKSUM_OFFLOAD + if (m0->m_pkthdr.csum_flags & + (M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4)) { + if (wm_tx_cksum(sc, txs, &TxDescCmd,&cksumfields) != 0) { + /* Error message already displayed. */ + continue; + } + } else { +#endif + TxDescCmd = 0; + cksumfields = 0; +#ifdef CKSUM_OFFLOAD + } +#endif + + TxDescCmd |= WTX_CMD_EOP|WTX_CMD_IFCS|WTX_CMD_RS; + + /* Initialize the transmit job descriptors. */ + for (i = 0; i < NTXDESC; i++) { + sc->txs_mbuf[i] = 0; + sc->sc_txdescs[i].wtx_fields.wtxu_options=cksumfields; + sc->sc_txdescs[i].wtx_addr.wa_high = 0; + sc->sc_txdescs[i].wtx_addr.wa_low = 0; + sc->sc_txdescs[i].wtx_cmdlen = htole32(TxDescCmd); + } + + /* + * Initialize the receive descriptor and receive job + * descriptor rings. + */ + memset(sc->sc_rxdescs, 0, sizeof(sc->sc_rxdescs)); + CSR_WRITE(sc,WMREG_RDBAH, 0); + CSR_WRITE(sc,WMREG_RDBAL, WM_CDRXADDR(sc)); + CSR_WRITE(sc,WMREG_RDLEN, sizeof(sc->sc_rxdescs)); + CSR_WRITE(sc,WMREG_RDH, 0); + CSR_WRITE(sc,WMREG_RDT, 0); + CSR_WRITE(sc,WMREG_RDTR, 0 |RDTR_FPD); + CSR_WRITE(sc, WMREG_RADV, 256); + + for (i = 0; i < NRXDESC; i++) { + if (sc->rxs_mbuf[i] == NULL) { + if ((error = wm_add_rxbuf(sc, i)) != 0) { + printk("%s%d: unable to allocate or map rx buffer" + "%d, error = %d\n",ifp->if_name,ifp->if_unit, i, error); + /* + * XXX Should attempt to run with fewer receive + * XXX buffers instead of just failing. + */ + wm_rxdrain(sc); + return(error); + } + } else { + printk("sc->rxs_mbuf[%d] not NULL.\n", i); + wm_init_rxdesc(sc, i); + } + } + sc->sc_rxptr = 0; + sc->sc_rxdiscard = 0; + + /* + * Clear out the VLAN table -- we don't use it (yet). + */ + CSR_WRITE(sc,WMREG_VET, 0); + for (i = 0; i < WM_VLAN_TABSIZE; i++) + CSR_WRITE(sc,WMREG_VFTA + (i << 2), 0); + + /* + * Set up flow-control parameters. + * + * XXX Values could probably stand some tuning. + */ + CSR_WRITE(sc,WMREG_FCAL, FCAL_CONST);/*safe,even though MOTLOAD 0x00c28001 */ + CSR_WRITE(sc,WMREG_FCAH, FCAH_CONST);/*safe,even though MOTLOAD 0x00000100 */ + CSR_WRITE(sc,WMREG_FCT, ETHERTYPE_FLOWCONTROL);/*safe,even though MOTLoad 0x8808 */ + + + /* safe,even though MOTLoad default all 0 */ + sc->sc_fcrtl = FCRTL_DFLT; + + CSR_WRITE(sc,WMREG_FCRTH, FCRTH_DFLT); + CSR_WRITE(sc,WMREG_FCRTL, sc->sc_fcrtl); + CSR_WRITE(sc,WMREG_FCTTV, FCTTV_DFLT); + + sc->sc_ctrl &= ~CTRL_VME; + /*sc->sc_ctrl |= CTRL_TFCE | CTRL_RFCE;*/ + /* enable Big Endian Mode for the powerPC + sc->sc_ctrl |= CTRL_BEM;*/ + + /* Write the control registers. */ + CSR_WRITE(sc,WMREG_CTRL, sc->sc_ctrl); +#if 0 + CSR_WRITE(sc,WMREG_CTRL_EXT, sc->sc_ctrl_ext); +#endif + + /* MOTLoad : WMREG_RXCSUM (0x5000)= 0, no Rx checksum offloading */ + + /* + * Set up the interrupt registers. + */ + CSR_WRITE(sc,WMREG_IMC, 0xffffffffU); + /* Reading the WMREG_ICR clears the interrupt bits */ + CSR_READ(sc,WMREG_ICR); + + /* printf("WMREG_IMS 0x%x\n", CSR_READ(sc,WMREG_IMS));*/ + + sc->sc_icr = ICR_TXDW | ICR_LSC | ICR_RXSEQ | ICR_RXCFG | ICR_RXDMT0 | ICR_RXO | ICR_RXT0; + + CSR_WRITE(sc,WMREG_IMS, sc->sc_icr); + + /* Set up the inter-packet gap. */ + CSR_WRITE(sc,WMREG_TIPG, sc->sc_tipg); + +#if 0 /* XXXJRT */ + /* Set the VLAN ethernetype. */ + CSR_WRITE(sc,WMREG_VET, ETHERTYPE_VLAN); +#endif + + /* + * Set up the transmit control register; we start out with + * a collision distance suitable for FDX, but update it when + * we resolve the media type. + */ + sc->sc_tctl = TCTL_EN | TCTL_PSP | TCTL_CT(TX_COLLISION_THRESHOLD) | + TCTL_COLD(TX_COLLISION_DISTANCE_FDX) | TCTL_RTLC; /*transmitter enable*/ + + /* + * Set up the receive control register; we actually program + * the register when we set the receive filter. Use multicast + * address offset type 0. + * + * Only the i82544 has the ability to strip the incoming + * CRC, so we don't enable that feature. (TODO) + */ + sc->sc_mchash_type = 0; + sc->sc_rctl = RCTL_EN | RCTL_LBM_NONE | RCTL_RDMTS_1_2 | RCTL_LPE | + RCTL_DPF | RCTL_MO(sc->sc_mchash_type); + + /* (MCLBYTES == 2048) */ + sc->sc_rctl |= RCTL_2k; + +#ifdef WM_DEBUG + printk("RDBAL 0x%x,RDLEN %d, RDT %d\n",CSR_READ(sc,WMREG_RDBAL),CSR_READ(sc,WMREG_RDLEN), CSR_READ(sc,WMREG_RDT)); +#endif + + /* Set the receive filter. */ + wm_set_filter(sc); + + CSR_WRITE(sc,WMREG_TCTL, sc->sc_tctl); + + /* Map and establish our interrupt. */ + if (!BSP_install_rtems_irq_handler(&i82544IrqData)) + rtems_panic("1GHZ ethernet: unable to install ISR"); + + return(0); +} + +/* + * i82544EI_ifinit: [ifnet interface function] + * + * Initialize the interface. + */ +static void i82544EI_ifinit(void *arg) +{ + struct wm_softc *sc = (struct wm_softc*)arg; + +#ifdef WM_DEBUG + printk("i82544EI_ifinit(): daemon ID: 0x%08x)\n", sc->daemonTid); +#endif + if (sc->daemonTid) { +#ifdef WM_DEBUG + printk("i82544EI: daemon already up, doing nothing\n"); +#endif + return; + } + i82544EI_init_hw(sc); + + sc->daemonTid = rtems_bsdnet_newproc(i82544EI_TASK_NAME,4096,i82544EI_daemon,arg); + + /* ...all done! */ + sc->arpcom.ac_if.if_flags |= IFF_RUNNING; + +#ifdef WM_DEBUG + printk(")"); +#endif +} + +/* + * wm_txdrain: + * + * Drain the transmit queue. + */ +static void wm_txdrain(struct wm_softc *sc) +{ + int i; + + /* Release any queued transmit buffers. */ + for (i = 0; i < NTXDESC; i++) { + if (sc->txs_mbuf[i] != NULL) { + m_freem(sc->txs_mbuf[i]); + sc->txs_mbuf[i] = NULL; + } + } +} + +/* + * wm_rxdrain: + * + * Drain the receive queue. + */ +static void wm_rxdrain(struct wm_softc *sc) +{ + int i; + + for (i = 0; i < NRXDESC; i++) { + if (sc->rxs_mbuf[i] != NULL) { + m_freem(sc->rxs_mbuf[i]); + sc->rxs_mbuf[i] = NULL; + } + } +} + +static void i82544EI_tx_stop(struct wm_softc *sc) +{ + wm_txdrain(sc); +} + +static void i82544EI_rx_stop(struct wm_softc *sc) +{ + wm_rxdrain(sc); +} + +static void i82544EI_stop_hw(struct wm_softc *sc) +{ +#ifdef WM_DEBUG + printk("i82544EI_stop_hw("); +#endif + + /* remove our interrupt handler which will also + * disable interrupts at the MPIC and the device + * itself + */ + if (!BSP_remove_rtems_irq_handler(&i82544IrqData)) + rtems_panic("i82544EI: unable to remove IRQ handler!"); + + CSR_WRITE(sc,WMREG_IMS, 0); + + sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; + i82544EI_tx_stop(sc); + i82544EI_rx_stop(sc); +#ifdef WM_DEBUG + printk(")"); +#endif +} + +/* + * wm_stop: [ifnet interface function] + * + * Stop transmission on the interface. + */ +static void wm_stop(struct ifnet *ifp, int disable) +{ + struct wm_softc *sc = ifp->if_softc; + +#ifdef WM_DEBUG + printk("wm_stop("); +#endif + /* Stop the transmit and receive processes. */ + CSR_WRITE(sc,WMREG_TCTL, 0); + CSR_WRITE(sc,WMREG_RCTL, 0); + + wm_txdrain(sc); + wm_rxdrain(sc); + + /* Mark the interface as down */ + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); +#ifdef WM_DEBUG + printk(")\n"); +#endif +} + +/* + * wm_eeprom_sendbits: + * + * Send a series of bits to the EEPROM. + */ +static void wm_eeprom_sendbits(struct wm_softc *sc, uint32_t bits, int nbits) +{ + uint32_t reg; + int x; + + reg = CSR_READ(sc,WMREG_EECD); + + for (x = nbits; x > 0; x--) { + if (bits & (1U << (x - 1))) + reg |= EECD_DI; + else + reg &= ~EECD_DI; + CSR_WRITE(sc,WMREG_EECD, reg); + rtems_bsp_delay(2); + CSR_WRITE(sc,WMREG_EECD, reg | EECD_SK); + rtems_bsp_delay(2); + CSR_WRITE(sc,WMREG_EECD, reg); + rtems_bsp_delay(2); + } +} + +/* + * wm_eeprom_recvbits: + * + * Receive a series of bits from the EEPROM. + */ +static void wm_eeprom_recvbits(struct wm_softc *sc, uint32_t *valp, int nbits) +{ + uint32_t reg, val; + int x; + + reg = CSR_READ(sc,WMREG_EECD) & ~EECD_DI; + + val = 0; + for (x = nbits; x > 0; x--) { + CSR_WRITE(sc,WMREG_EECD, reg | EECD_SK); + rtems_bsp_delay(2); + if (CSR_READ(sc,WMREG_EECD) & EECD_DO) + val |= (1U << (x - 1)); + CSR_WRITE(sc,WMREG_EECD, reg); + rtems_bsp_delay(2); + } + *valp = val; +} + +/* + * wm_read_eeprom_uwire: + * + * Read a word from the EEPROM using the MicroWire protocol. + * + * (The 82544EI Gigabit Ethernet Controller is compatible with + * most MicroWire interface, serial EEPROM devices.) + */ +static int wm_read_eeprom_uwire(struct wm_softc *sc, int word, int wordcnt, uint16_t *data) +{ + uint32_t reg, val; + int i; + + for (i = 0; i < wordcnt; i++) { + /* Clear SK and DI. */ + reg = CSR_READ(sc,WMREG_EECD) & ~(EECD_SK | EECD_DI); + CSR_WRITE(sc,WMREG_EECD, reg); + + /* Set CHIP SELECT. */ + reg |= EECD_CS; + CSR_WRITE(sc,WMREG_EECD, reg); + rtems_bsp_delay(2); + + /* Shift in the READ command. */ + wm_eeprom_sendbits(sc, UWIRE_OPC_READ, 3); + + /* Shift in address. */ + wm_eeprom_sendbits(sc, word + i, sc->sc_ee_addrbits); + + /* Shift out the data. */ + wm_eeprom_recvbits(sc, &val, 16); + data[i] = val & 0xffff; + + /* Clear CHIP SELECT. */ + reg = CSR_READ(sc,WMREG_EECD) & ~EECD_CS; + CSR_WRITE(sc,WMREG_EECD, reg); + rtems_bsp_delay(2); + } + return (0); +} + +/* + * wm_acquire_eeprom: + * + * Perform the EEPROM handshake required on some chips. + */ +static int wm_acquire_eeprom(struct wm_softc *sc) +{ + uint32_t reg; + int x; + + reg = CSR_READ(sc,WMREG_EECD); + + /* Request EEPROM access. */ + reg |= EECD_EE_REQ; + CSR_WRITE(sc,WMREG_EECD, reg); + + /* ..and wait for it to be granted. */ + for (x = 0; x < 100; x++) { + reg = CSR_READ(sc,WMREG_EECD); + if (reg & EECD_EE_GNT) break; + rtems_bsp_delay(500); + } + if ((reg & EECD_EE_GNT) == 0) { + printk("Could not acquire EEPROM GNT x= %d\n", x); + reg &= ~EECD_EE_REQ; + CSR_WRITE(sc,WMREG_EECD, reg); + return (1); + } + + return (0); +} + +/* + * wm_read_eeprom: + * + * Read data from the serial EEPROM. + * 82544EI does not Perform the EEPROM handshake + */ +static int wm_read_eeprom(struct wm_softc *sc, int word, int wordcnt, uint16_t *data) +{ +#if 0 + /* base on the datasheet, this does not seem to be applicable */ + if (wm_acquire_eeprom(sc)) + return(1); +#endif + return(wm_read_eeprom_uwire(sc, word, wordcnt, data)); +} + +/* + * wm_add_rxbuf: + * + * Add a receive buffer to the indiciated descriptor. + */ +static int wm_add_rxbuf(struct wm_softc *sc, int idx) +{ + struct mbuf *m; + + MGETHDR(m, M_WAIT, MT_DATA); + if (m == NULL) return (ENOBUFS); + MCLGET(m, M_WAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + return (ENOBUFS); + } + m->m_pkthdr.rcvif = &sc->arpcom.ac_if; + sc->rxs_mbuf[idx] = m; + /* m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;*/ + wm_init_rxdesc(sc, idx); +#if 0 + printk("sc->rxs_mbuf[%d]= 0x%x, mbuf @ 0x%x\n", + idx, sc->rxs_mbuf[idx], le32toh(sc->sc_rxdescs[idx].wrx_addr.wa_low)); +#endif + return(0); +} + +/* + * wm_set_ral: + * + * Set an entery in the receive address list. + */ +static void +wm_set_ral(struct wm_softc *sc, const uint8_t *enaddr, int idx) +{ + uint32_t ral_lo, ral_hi; + + if (enaddr != NULL) { + ral_lo = enaddr[0]|(enaddr[1] << 8)|(enaddr[2] << 16)|(enaddr[3] << 24); + ral_hi = enaddr[4] | (enaddr[5] << 8); + ral_hi |= RAL_AV; + } else { + ral_lo = 0; + ral_hi = 0; + } + + CSR_WRITE(sc,WMREG_RAL_LO(WMREG_CORDOVA_RAL_BASE, idx),ral_lo); + CSR_WRITE(sc,WMREG_RAL_HI(WMREG_CORDOVA_RAL_BASE, idx),ral_hi); +} + +/* + * wm_mchash: + * + * Compute the hash of the multicast address for the 4096-bit + * multicast filter. + */ +static uint32_t +wm_mchash(struct wm_softc *sc, const uint8_t *enaddr) +{ + static const int lo_shift[4] = { 4, 3, 2, 0 }; + static const int hi_shift[4] = { 4, 5, 6, 8 }; + uint32_t hash; + + hash = (enaddr[4] >> lo_shift[sc->sc_mchash_type]) | + (((uint16_t) enaddr[5]) << hi_shift[sc->sc_mchash_type]); + + return (hash & 0xfff); +} + +/* + * wm_set_filter: Set up the receive filter. + */ +static void wm_set_filter(struct wm_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ether_multi *enm; + struct ether_multistep step; + uint32_t mta_reg; + uint32_t hash, reg, bit; + int i; + +#ifdef WM_DEBUG + printk("wm_set_filter("); +#endif + mta_reg = WMREG_CORDOVA_MTA; + sc->sc_rctl &= ~(RCTL_BAM | RCTL_UPE | RCTL_MPE); + + /* if (ifp->if_flags & IFF_BROADCAST)*/ + sc->sc_rctl |= RCTL_BAM; + if (ifp->if_flags & IFF_PROMISC) { + sc->sc_rctl |= RCTL_UPE; + goto allmulti; + } + + /* + * Set the station address in the first RAL slot, and + * clear the remaining slots. + */ + wm_set_ral(sc, sc->arpcom.ac_enaddr, 0); + for (i = 1; i < WM_RAL_TABSIZE; i++) + wm_set_ral(sc, NULL, i); + + /* Clear out the multicast table. */ + for (i = 0; i < WM_MC_TABSIZE; i++) + CSR_WRITE(sc,mta_reg + (i << 2), 0); + + ETHER_FIRST_MULTI(step, &sc->arpcom, enm); + while (enm != NULL) { + if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { + /* + * We must listen to a range of multicast addresses. + * For now, just accept all multicasts, rather than + * trying to set only those filter bits needed to match + * the range. (At this time, the only use of address + * ranges is for IP multicast routing, for which the + * range is big enough to require all bits set.) + */ + goto allmulti; + } + + hash = wm_mchash(sc, enm->enm_addrlo); + + reg = (hash >> 5) & 0x7f; + bit = hash & 0x1f; + + hash = CSR_READ(sc,mta_reg + (reg << 2)); + hash |= 1U << bit; + + /* XXX Hardware bug?? */ + if ((reg & 0xe) == 1) { + bit = CSR_READ(sc,mta_reg + ((reg - 1) << 2)); + CSR_WRITE(sc,mta_reg + (reg << 2), hash); + CSR_WRITE(sc,mta_reg + ((reg - 1) << 2), bit); + } else + CSR_WRITE(sc,mta_reg + (reg << 2), hash); + + ETHER_NEXT_MULTI(step, enm); + } + + ifp->if_flags &= ~IFF_ALLMULTI; + goto setit; + + allmulti: + ifp->if_flags |= IFF_ALLMULTI; + sc->sc_rctl |= RCTL_MPE; + + setit: + CSR_WRITE(sc,WMREG_RCTL, sc->sc_rctl); + +#ifdef WM_DEBUG + printk("RCTL 0x%x)\n", CSR_READ(sc,WMREG_RCTL)); +#endif +} + +static void i82544EI_error(struct wm_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + unsigned long intr_status= sc->intr_errsts[sc->intr_err_ptr1++]; + + /* read and reset the status; because this is written + * by the ISR, we must disable interrupts here + */ + sc->intr_err_ptr1 %=INTR_ERR_SIZE; /* Till Straumann */ + if (intr_status) { + printk("Error %s%d:", ifp->if_name, ifp->if_unit); + if (intr_status & ICR_RXSEQ) { + printk("Rxq framing error (ICR= %x), if_ierrors %d\n", + intr_status, ifp->if_ierrors); + } + } + else + printk("%s%d: Ghost interrupt ?\n",ifp->if_name,ifp->if_unit); +} + +void i82544EI_printStats() +{ + i82544EI_stats(root_i82544EI_dev); +} + +/* The daemon does all of the work; RX, TX and cleaning up buffers/descriptors */ +static void i82544EI_daemon(void *arg) +{ + struct wm_softc *sc = (struct wm_softc*)arg; + rtems_event_set events; + struct mbuf *m=0; + struct ifnet *ifp=&sc->arpcom.ac_if; + +#ifdef WM_DEBUG + printk("i82544EI_daemon()\n"); +#endif + + /* NOTE: our creator possibly holds the bsdnet_semaphore. + * since that has PRIORITY_INVERSION enabled, our + * subsequent call to bsdnet_event_receive() will + * _not_ release it. It's still in posession of our + * owner. + * This is different from how killing this task + * is handled. + */ + + for (;;) { + /* sleep until there's work to be done */ + /* Note: bsdnet_event_receive() acquires + * the global bsdnet semaphore for + * mutual exclusion. + */ + rtems_bsdnet_event_receive(ALL_EVENTS, + RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + if (KILL_EVENT & events) break; + + if (events & RX_EVENT) i82544EI_rx(sc); + + /* clean up and try sending packets */ + do { + i82544EI_txq_done(sc); + + while (sc->txq_free>0) { + if (sc->txq_free>TXQ_HiLmt_OFF) { + IF_DEQUEUE(&ifp->if_snd,m); + if (m==0) break; + i82544EI_sendpacket(sc, m); + } + else { + i82544EI_txq_done(sc); + break; + } + if (events & RX_EVENT) i82544EI_rx(sc); + } + /* we leave this loop + * - either because there's no free buffer + * (m=0 initializer && !sc->txq_free) + * - or there's nothing to send (IF_DEQUEUE + * returned 0 + */ + } while (m && sc->txq_free); + + ifp->if_flags &= ~IFF_OACTIVE; + + /* Log errors and other uncommon events. */ + if (events & ERR_EVENT) i82544EI_error(sc); + /* Rx overrun */ + if ( events & INIT_EVENT) { + printk("Warnning, Rx overrun. Make sure the old mbuf was free\n"); + i82544EI_ifinit(arg); + } + + } /* end for(;;) { rtems_bsdnet_event_receive() .....*/ + + printf("out of daemon\n"); + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + + /* shut down the hardware */ + i82544EI_stop_hw(sc); + /* flush the output queue */ + for (;;) { + IF_DEQUEUE(&ifp->if_snd,m); + if (!m) break; + m_freem(m); + } + /* as of 'rtems_bsdnet_event_receive()' we own the + * networking semaphore + */ + rtems_bsdnet_semaphore_release(); + rtems_semaphore_release(sc->daemonSync); + + /* Note that I dont use sc->daemonTid here - + * theoretically, that variable could already + * hold a newly created TID + */ + rtems_task_delete(RTEMS_SELF); +} diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wmreg.h b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wmreg.h new file mode 100644 index 0000000000..d0fd42f1ce --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/if_wmreg.h @@ -0,0 +1,737 @@ +/* $NetBSD: if_wmreg.h,v 1.22 2007/04/29 20:35:21 bouyer Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Register description for the Intel i82542 (``Wiseman''), + * i82543 (``Livengood''), and i82544 (``Cordova'') Gigabit + * Ethernet chips. + */ + +/* + * The wiseman supports 64-bit PCI addressing. This structure + * describes the address in descriptors. + */ +typedef struct wiseman_addr { + uint32_t wa_low; /* low-order 32 bits */ + uint32_t wa_high; /* high-order 32 bits */ +} __attribute__((__packed__)) wiseman_addr_t; + +/* + * The Wiseman receive descriptor. + * + * The receive descriptor ring must be aligned to a 4K boundary, + * and there must be an even multiple of 8 descriptors in the ring. + */ +typedef struct wiseman_rxdesc { + wiseman_addr_t wrx_addr; /* buffer address */ + + uint16_t wrx_len; /* buffer length */ + uint16_t wrx_cksum; /* checksum (starting at PCSS) */ + + uint8_t wrx_status; /* Rx status */ + uint8_t wrx_errors; /* Rx errors */ + uint16_t wrx_special; /* special field (VLAN, etc.) */ +} __attribute__((__packed__)) wiseman_rxdesc_t; + +/* wrx_status bits */ +#define WRX_ST_DD (1U << 0) /* descriptor done */ +#define WRX_ST_EOP (1U << 1) /* end of packet */ +#define WRX_ST_IXSM (1U << 2) /* ignore checksum indication */ +#define WRX_ST_VP (1U << 3) /* VLAN packet */ +#define WRX_ST_BPDU (1U << 4) /* ??? */ +#define WRX_ST_TCPCS (1U << 5) /* TCP checksum performed */ +#define WRX_ST_IPCS (1U << 6) /* IP checksum performed */ +#define WRX_ST_PIF (1U << 7) /* passed in-exact filter */ + +/* wrx_error bits */ +#define WRX_ER_CE (1U << 0) /* CRC error */ +#define WRX_ER_SE (1U << 1) /* symbol error */ +#define WRX_ER_SEQ (1U << 2) /* sequence error */ +#define WRX_ER_ICE (1U << 3) /* ??? */ +#define WRX_ER_CXE (1U << 4) /* carrier extension error */ +#define WRX_ER_TCPE (1U << 5) /* TCP checksum error */ +#define WRX_ER_IPE (1U << 6) /* IP checksum error */ +#define WRX_ER_RXE (1U << 7) /* Rx data error */ + +/* wrx_special field for VLAN packets */ +#define WRX_VLAN_ID(x) ((x) & 0x0fff) /* VLAN identifier */ +#define WRX_VLAN_CFI (1U << 12) /* Canonical Form Indicator */ +#define WRX_VLAN_PRI(x) (((x) >> 13) & 7)/* VLAN priority field */ + +/* + * The Wiseman transmit descriptor. + * + * The transmit descriptor ring must be aligned to a 4K boundary, + * and there must be an even multiple of 8 descriptors in the ring. + */ +typedef struct wiseman_tx_fields { + uint8_t wtxu_status; /* Tx status */ + uint8_t wtxu_options; /* options */ + uint16_t wtxu_vlan; /* VLAN info */ +} __attribute__((__packed__)) wiseman_txfields_t; +typedef struct wiseman_txdesc { + wiseman_addr_t wtx_addr; /* buffer address */ + uint32_t wtx_cmdlen; /* command and length */ + wiseman_txfields_t wtx_fields; /* fields; see below */ +} __attribute__((__packed__)) wiseman_txdesc_t; + +/* Commands for wtx_cmdlen */ +#define WTX_CMD_EOP (1U << 24) /* end of packet */ +#define WTX_CMD_IFCS (1U << 25) /* insert FCS */ +#define WTX_CMD_RS (1U << 27) /* report status */ +#define WTX_CMD_RPS (1U << 28) /* report packet sent */ +#define WTX_CMD_DEXT (1U << 29) /* descriptor extension */ +#define WTX_CMD_VLE (1U << 30) /* VLAN enable */ +#define WTX_CMD_IDE (1U << 31) /* interrupt delay enable */ + +/* Descriptor types (if DEXT is set) */ +#define WTX_DTYP_C (0U << 20) /* context */ +#define WTX_DTYP_D (1U << 20) /* data */ + +/* wtx_fields status bits */ +#define WTX_ST_DD (1U << 0) /* descriptor done */ +#define WTX_ST_EC (1U << 1) /* excessive collisions */ +#define WTX_ST_LC (1U << 2) /* late collision */ +#define WTX_ST_TU (1U << 3) /* transmit underrun */ + +/* wtx_fields option bits for IP/TCP/UDP checksum offload */ +#define WTX_IXSM (1U << 0) /* IP checksum offload */ +#define WTX_TXSM (1U << 1) /* TCP/UDP checksum offload */ + +/* Maximum payload per Tx descriptor */ +#define WTX_MAX_LEN 4096 + +/* + * The Livengood TCP/IP context descriptor. + */ +struct livengood_tcpip_ctxdesc { + uint32_t tcpip_ipcs; /* IP checksum context */ + uint32_t tcpip_tucs; /* TCP/UDP checksum context */ + uint32_t tcpip_cmdlen; + uint32_t tcpip_seg; /* TCP segmentation context */ +}; + +/* commands for context descriptors */ +#define WTX_TCPIP_CMD_TCP (1U << 24) /* 1 = TCP, 0 = UDP */ +#define WTX_TCPIP_CMD_IP (1U << 25) /* 1 = IPv4, 0 = IPv6 */ +#define WTX_TCPIP_CMD_TSE (1U << 26) /* segmentation context valid */ + +#define WTX_TCPIP_IPCSS(x) ((x) << 0) /* checksum start */ +#define WTX_TCPIP_IPCSO(x) ((x) << 8) /* checksum value offset */ +#define WTX_TCPIP_IPCSE(x) ((x) << 16) /* checksum end */ + +#define WTX_TCPIP_TUCSS(x) ((x) << 0) /* checksum start */ +#define WTX_TCPIP_TUCSO(x) ((x) << 8) /* checksum value offset */ +#define WTX_TCPIP_TUCSE(x) ((x) << 16) /* checksum end */ + +#define WTX_TCPIP_SEG_STATUS(x) ((x) << 0) +#define WTX_TCPIP_SEG_HDRLEN(x) ((x) << 8) +#define WTX_TCPIP_SEG_MSS(x) ((x) << 16) + +/* + * PCI config registers used by the Wiseman. + */ +#define WM_PCI_MMBA PCI_MAPREG_START +/* registers for FLASH access on ICH8 */ +#define WM_ICH8_FLASH 0x0014 + +/* + * Wiseman Control/Status Registers. + */ +#define WMREG_CTRL 0x0000 /* Device Control Register */ +#define CTRL_FD (1U << 0) /* full duplex */ +#define CTRL_BEM (1U << 1) /* big-endian mode */ +#define CTRL_PRIOR (1U << 2) /* 0 = receive, 1 = fair */ +#define CTRL_LRST (1U << 3) /* link reset */ +#define CTRL_ASDE (1U << 5) /* auto speed detect enable */ +#define CTRL_SLU (1U << 6) /* set link up */ +#define CTRL_ILOS (1U << 7) /* invert loss of signal */ +#define CTRL_SPEED(x) ((x) << 8) /* speed (Livengood) */ +#define CTRL_SPEED_10 CTRL_SPEED(0) +#define CTRL_SPEED_100 CTRL_SPEED(1) +#define CTRL_SPEED_1000 CTRL_SPEED(2) +#define CTRL_SPEED_MASK CTRL_SPEED(3) +#define CTRL_FRCSPD (1U << 11) /* force speed (Livengood) */ +#define CTRL_FRCFDX (1U << 12) /* force full-duplex (Livengood) */ +#define CTRL_D_UD_EN (1U << 13) /* Dock/Undock enable */ +#define CTRL_D_UD_POL (1U << 14) /* Defined polarity of Dock/Undock indication in SDP[0] */ +#define CTRL_F_PHY_R (1U << 15) /* Reset both PHY ports, through PHYRST_N pin */ +#define CTRL_EXT_LINK_EN (1U << 16) /* enable link status from external LINK_0 and LINK_1 pins */ +#define CTRL_SWDPINS_SHIFT 18 +#define CTRL_SWDPINS_MASK 0x0f +#define CTRL_SWDPIN(x) (1U << (CTRL_SWDPINS_SHIFT + (x))) +#define CTRL_SWDPIO_SHIFT 22 +#define CTRL_SWDPIO_MASK 0x0f +#define CTRL_SWDPIO(x) (1U << (CTRL_SWDPIO_SHIFT + (x))) +#define CTRL_RST (1U << 26) /* device reset */ +#define CTRL_RFCE (1U << 27) /* Rx flow control enable */ +#define CTRL_TFCE (1U << 28) /* Tx flow control enable */ +#define CTRL_VME (1U << 30) /* VLAN Mode Enable */ +#define CTRL_PHY_RESET (1U << 31) /* PHY reset (Cordova) */ + +#define WMREG_CTRL_SHADOW 0x0004 /* Device Control Register (shadow) */ + +#define WMREG_STATUS 0x0008 /* Device Status Register */ +#define STATUS_FD (1U << 0) /* full duplex */ +#define STATUS_LU (1U << 1) /* link up */ +#define STATUS_TCKOK (1U << 2) /* Tx clock running */ +#define STATUS_RBCOK (1U << 3) /* Rx clock running */ +#define STATUS_FUNCID_SHIFT 2 /* 82546 function ID */ +#define STATUS_FUNCID_MASK 3 /* ... */ +#define STATUS_TXOFF (1U << 4) /* Tx paused */ +#define STATUS_TBIMODE (1U << 5) /* fiber mode (Livengood) */ +#define STATUS_SPEED(x) ((x) << 6) /* speed indication */ +#define STATUS_SPEED_10 STATUS_SPEED(0) +#define STATUS_SPEED_100 STATUS_SPEED(1) +#define STATUS_SPEED_1000 STATUS_SPEED(2) +#define STATUS_ASDV(x) ((x) << 8) /* auto speed det. val. (Livengood) */ +#define STATUS_MTXCKOK (1U << 10) /* MTXD clock running */ +#define STATUS_PCI66 (1U << 11) /* 66MHz bus (Livengood) */ +#define STATUS_BUS64 (1U << 12) /* 64-bit bus (Livengood) */ +#define STATUS_PCIX_MODE (1U << 13) /* PCIX mode (Cordova) */ +#define STATUS_PCIXSPD(x) ((x) << 14) /* PCIX speed indication (Cordova) */ +#define STATUS_PCIXSPD_50_66 STATUS_PCIXSPD(0) +#define STATUS_PCIXSPD_66_100 STATUS_PCIXSPD(1) +#define STATUS_PCIXSPD_100_133 STATUS_PCIXSPD(2) +#define STATUS_PCIXSPD_MASK STATUS_PCIXSPD(3) + +#define WMREG_EECD 0x0010 /* EEPROM Control Register */ +#define EECD_SK (1U << 0) /* clock */ +#define EECD_CS (1U << 1) /* chip select */ +#define EECD_DI (1U << 2) /* data in */ +#define EECD_DO (1U << 3) /* data out */ +#define EECD_FWE(x) ((x) << 4) /* flash write enable control */ +#define EECD_FWE_DISABLED EECD_FWE(1) +#define EECD_FWE_ENABLED EECD_FWE(2) +#define EECD_EE_REQ (1U << 6) /* (shared) EEPROM request */ +#define EECD_EE_GNT (1U << 7) /* (shared) EEPROM grant */ +#define EECD_EE_PRES (1U << 8) /* EEPROM present */ +#define EECD_EE_SIZE (1U << 9) /* EEPROM size + (0 = 64 word, 1 = 256 word) */ +#define EECD_EE_AUTORD (1U << 9) /* auto read done */ +#define EECD_EE_ABITS (1U << 10) /* EEPROM address bits + (based on type) */ +#define EECD_EE_TYPE (1U << 13) /* EEPROM type + (0 = Microwire, 1 = SPI) */ +#define EECD_SEC1VAL (1U << 22) /* Sector One Valid */ + +#define UWIRE_OPC_ERASE 0x04 /* MicroWire "erase" opcode */ +#define UWIRE_OPC_WRITE 0x05 /* MicroWire "write" opcode */ +#define UWIRE_OPC_READ 0x06 /* MicroWire "read" opcode */ + +#define SPI_OPC_WRITE 0x02 /* SPI "write" opcode */ +#define SPI_OPC_READ 0x03 /* SPI "read" opcode */ +#define SPI_OPC_A8 0x08 /* opcode bit 3 == address bit 8 */ +#define SPI_OPC_WREN 0x06 /* SPI "set write enable" opcode */ +#define SPI_OPC_WRDI 0x04 /* SPI "clear write enable" opcode */ +#define SPI_OPC_RDSR 0x05 /* SPI "read status" opcode */ +#define SPI_OPC_WRSR 0x01 /* SPI "write status" opcode */ +#define SPI_MAX_RETRIES 5000 /* max wait of 5ms for RDY signal */ + +#define SPI_SR_RDY 0x01 +#define SPI_SR_WEN 0x02 +#define SPI_SR_BP0 0x04 +#define SPI_SR_BP1 0x08 +#define SPI_SR_WPEN 0x80 + +#define EEPROM_OFF_MACADDR 0x00 /* MAC address offset */ +#define EEPROM_OFF_CFG1 0x0a /* config word 1 */ +#define EEPROM_OFF_CFG2 0x0f /* config word 2 */ +#define EEPROM_OFF_SWDPIN 0x20 /* SWD Pins (Cordova) */ + +#define EEPROM_CFG1_LVDID (1U << 0) +#define EEPROM_CFG1_LSSID (1U << 1) +#define EEPROM_CFG1_PME_CLOCK (1U << 2) +#define EEPROM_CFG1_PM (1U << 3) +#define EEPROM_CFG1_ILOS (1U << 4) +#define EEPROM_CFG1_SWDPIO_SHIFT 5 +#define EEPROM_CFG1_SWDPIO_MASK (0xf << EEPROM_CFG1_SWDPIO_SHIFT) +#define EEPROM_CFG1_IPS1 (1U << 8) +#define EEPROM_CFG1_LRST (1U << 9) +#define EEPROM_CFG1_FD (1U << 10) +#define EEPROM_CFG1_FRCSPD (1U << 11) +#define EEPROM_CFG1_IPS0 (1U << 12) +#define EEPROM_CFG1_64_32_BAR (1U << 13) + +#define EEPROM_CFG2_CSR_RD_SPLIT (1U << 1) +#define EEPROM_CFG2_APM_EN (1U << 2) +#define EEPROM_CFG2_64_BIT (1U << 3) +#define EEPROM_CFG2_MAX_READ (1U << 4) +#define EEPROM_CFG2_DMCR_MAP (1U << 5) +#define EEPROM_CFG2_133_CAP (1U << 6) +#define EEPROM_CFG2_MSI_DIS (1U << 7) +#define EEPROM_CFG2_FLASH_DIS (1U << 8) +#define EEPROM_CFG2_FLASH_SIZE(x) (((x) & 3) >> 9) +#define EEPROM_CFG2_ANE (1U << 11) +#define EEPROM_CFG2_PAUSE(x) (((x) & 3) >> 12) +#define EEPROM_CFG2_ASDE (1U << 14) +#define EEPROM_CFG2_APM_PME (1U << 15) +#define EEPROM_CFG2_SWDPIO_SHIFT 4 +#define EEPROM_CFG2_SWDPIO_MASK (0xf << EEPROM_CFG2_SWDPIO_SHIFT) + +#define EEPROM_SWDPIN_MASK 0xdf +#define EEPROM_SWDPIN_SWDPIN_SHIFT 0 +#define EEPROM_SWDPIN_SWDPIO_SHIFT 8 + +#define WMREG_EERD 0x0014 /* EEPROM read */ +#define EERD_DONE 0x02 /* done bit */ +#define EERD_START 0x01 /* First bit for telling part to start operation */ +#define EERD_ADDR_SHIFT 2 /* Shift to the address bits */ +#define EERD_DATA_SHIFT 16 /* Offset to data in EEPROM read/write registers */ + +#define WMREG_CTRL_EXT 0x0018 /* Extended Device Control Register */ +#define CTRL_EXT_GPI_EN(x) (1U << (x)) /* gpin interrupt enable */ +#define CTRL_EXT_SWDPINS_SHIFT 4 +#define CTRL_EXT_SWDPINS_MASK 0x0d +#define CTRL_EXT_SWDPIN(x) (1U << (CTRL_EXT_SWDPINS_SHIFT + (x) - 4)) +#define CTRL_EXT_SWDPIO_SHIFT 8 +#define CTRL_EXT_SWDPIO_MASK 0x0d +#define CTRL_EXT_SWDPIO(x) (1U << (CTRL_EXT_SWDPIO_SHIFT + (x) - 4)) +#define CTRL_EXT_ASDCHK (1U << 12) /* ASD check */ +#define CTRL_EXT_EE_RST (1U << 13) /* EEPROM reset */ +#define CTRL_EXT_IPS (1U << 14) /* invert power state bit 0 */ +#define CTRL_EXT_SPD_BYPS (1U << 15) /* speed select bypass */ +#define CTRL_EXT_IPS1 (1U << 16) /* invert power state bit 1 */ +#define CTRL_EXT_RO_DIS (1U << 17) /* relaxed ordering disabled */ +#define CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define CTRL_EXT_LINK_MODE_GMII 0x00000000 +#define CTRL_EXT_LINK_MODE_TBI 0x00C00000 +#define CTRL_EXT_LINK_MODE_KMRN 0x00000000 +#define CTRL_EXT_LINK_MODE_SERDES 0x00C00000 + + +#define WMREG_MDIC 0x0020 /* MDI Control Register */ +#define MDIC_DATA(x) ((x) & 0xffff) +#define MDIC_REGADD(x) ((x) << 16) +#define MDIC_PHYADD(x) ((x) << 21) +#define MDIC_OP_WRITE (1U << 26) +#define MDIC_OP_READ (2U << 26) +#define MDIC_READY (1U << 28) +#define MDIC_I (1U << 29) /* interrupt on MDI complete */ +#define MDIC_E (1U << 30) /* MDI error */ + +#define WMREG_FCAL 0x0028 /* Flow Control Address Low */ +#define FCAL_CONST 0x00c28001 /* Flow Control MAC addr low */ + +#define WMREG_FCAH 0x002c /* Flow Control Address High */ +#define FCAH_CONST 0x00000100 /* Flow Control MAC addr high */ + +#define WMREG_FCT 0x0030 /* Flow Control Type */ + +#define WMREG_VET 0x0038 /* VLAN Ethertype */ + +#define WMREG_RAL_BASE 0x0040 /* Receive Address List */ +#define WMREG_CORDOVA_RAL_BASE 0x5400 +#define WMREG_RAL_LO(b, x) ((b) + ((x) << 3)) +#define WMREG_RAL_HI(b, x) (WMREG_RAL_LO(b, x) + 4) + /* + * Receive Address List: The LO part is the low-order 32-bits + * of the MAC address. The HI part is the high-order 16-bits + * along with a few control bits. + */ +#define RAL_AS(x) ((x) << 16) /* address select */ +#define RAL_AS_DEST RAL_AS(0) /* (cordova?) */ +#define RAL_AS_SOURCE RAL_AS(1) /* (cordova?) */ +#define RAL_RDR1 (1U << 30) /* put packet in alt. rx ring */ +#define RAL_AV (1U << 31) /* entry is valid */ + +#define WM_RAL_TABSIZE 16 +#define WM_ICH8_RAL_TABSIZE 7 + +#define WMREG_ICR 0x00c0 /* Interrupt Cause Register */ +#define ICR_TXDW (1U << 0) /* Tx desc written back */ +#define ICR_TXQE (1U << 1) /* Tx queue empty */ +#define ICR_LSC (1U << 2) /* link status change */ +#define ICR_RXSEQ (1U << 3) /* receive sequence error */ +#define ICR_RXDMT0 (1U << 4) /* Rx ring 0 nearly empty */ +#define ICR_RXO (1U << 6) /* Rx overrun */ +#define ICR_RXT0 (1U << 7) /* Rx ring 0 timer */ +#define ICR_MDAC (1U << 9) /* MDIO access complete */ +#define ICR_RXCFG (1U << 10) /* Receiving /C/ */ +#define ICR_GPI(x) (1U << (x)) /* general purpose interrupts */ +#define ICR_INT (1U << 31) /* device generated an interrupt */ + +#define WMREG_ITR 0x00c4 /* Interrupt Throttling Register */ +#define ITR_IVAL_MASK 0xffff /* Interval mask */ +#define ITR_IVAL_SHIFT 0 /* Interval shift */ + +#define WMREG_ICS 0x00c8 /* Interrupt Cause Set Register */ + /* See ICR bits. */ + +#define WMREG_IMS 0x00d0 /* Interrupt Mask Set Register */ + /* See ICR bits. */ + +#define WMREG_IMC 0x00d8 /* Interrupt Mask Clear Register */ + /* See ICR bits. */ + +#define WMREG_RCTL 0x0100 /* Receive Control */ +#define RCTL_EN (1U << 1) /* receiver enable */ +#define RCTL_SBP (1U << 2) /* store bad packets */ +#define RCTL_UPE (1U << 3) /* unicast promisc. enable */ +#define RCTL_MPE (1U << 4) /* multicast promisc. enable */ +#define RCTL_LPE (1U << 5) /* large packet enable */ +#define RCTL_LBM(x) ((x) << 6) /* loopback mode */ +#define RCTL_LBM_NONE RCTL_LBM(0) +#define RCTL_LBM_PHY RCTL_LBM(3) +#define RCTL_RDMTS(x) ((x) << 8) /* receive desc. min thresh size */ +#define RCTL_RDMTS_1_2 RCTL_RDMTS(0) +#define RCTL_RDMTS_1_4 RCTL_RDMTS(1) +#define RCTL_RDMTS_1_8 RCTL_RDMTS(2) +#define RCTL_RDMTS_MASK RCTL_RDMTS(3) +#define RCTL_MO(x) ((x) << 12) /* multicast offset */ +#define RCTL_BAM (1U << 15) /* broadcast accept mode */ +#define RCTL_2k (0 << 16) /* 2k Rx buffers */ +#define RCTL_1k (1 << 16) /* 1k Rx buffers */ +#define RCTL_512 (2 << 16) /* 512 byte Rx buffers */ +#define RCTL_256 (3 << 16) /* 256 byte Rx buffers */ +#define RCTL_BSEX_16k (1 << 16) /* 16k Rx buffers (BSEX) */ +#define RCTL_BSEX_8k (2 << 16) /* 8k Rx buffers (BSEX) */ +#define RCTL_BSEX_4k (3 << 16) /* 4k Rx buffers (BSEX) */ +#define RCTL_DPF (1U << 22) /* discard pause frames */ +#define RCTL_PMCF (1U << 23) /* pass MAC control frames */ +#define RCTL_BSEX (1U << 25) /* buffer size extension (Livengood) */ +#define RCTL_SECRC (1U << 26) /* strip Ethernet CRC */ + +#define WMREG_OLD_RDTR0 0x0108 /* Receive Delay Timer (ring 0) */ +#define WMREG_RDTR 0x2820 +#define RDTR_FPD (1U << 31) /* flush partial descriptor */ + +#define WMREG_RADV 0x282c /* Receive Interrupt Absolute Delay Timer */ + +#define WMREG_OLD_RDBAL0 0x0110 /* Receive Descriptor Base Low (ring 0) */ +#define WMREG_RDBAL 0x2800 + +#define WMREG_OLD_RDBAH0 0x0114 /* Receive Descriptor Base High (ring 0) */ +#define WMREG_RDBAH 0x2804 + +#define WMREG_OLD_RDLEN0 0x0118 /* Receive Descriptor Length (ring 0) */ +#define WMREG_RDLEN 0x2808 + +#define WMREG_OLD_RDH0 0x0120 /* Receive Descriptor Head (ring 0) */ +#define WMREG_RDH 0x2810 + +#define WMREG_OLD_RDT0 0x0128 /* Receive Descriptor Tail (ring 0) */ +#define WMREG_RDT 0x2818 + +#define WMREG_RXDCTL 0x2828 /* Receive Descriptor Control */ +#define RXDCTL_PTHRESH(x) ((x) << 0) /* prefetch threshold */ +#define RXDCTL_HTHRESH(x) ((x) << 8) /* host threshold */ +#define RXDCTL_WTHRESH(x) ((x) << 16) /* write back threshold */ +#define RXDCTL_GRAN (1U << 24) /* 0 = cacheline, 1 = descriptor */ + +#define WMREG_OLD_RDTR1 0x0130 /* Receive Delay Timer (ring 1) */ + +#define WMREG_OLD_RDBA1_LO 0x0138 /* Receive Descriptor Base Low (ring 1) */ + +#define WMREG_OLD_RDBA1_HI 0x013c /* Receive Descriptor Base High (ring 1) */ + +#define WMREG_OLD_RDLEN1 0x0140 /* Receive Drscriptor Length (ring 1) */ + +#define WMREG_OLD_RDH1 0x0148 + +#define WMREG_OLD_RDT1 0x0150 + +#define WMREG_OLD_FCRTH 0x0160 /* Flow Control Rx Threshold Hi (OLD) */ +#define WMREG_FCRTL 0x2160 /* Flow Control Rx Threshold Lo */ +#define FCRTH_DFLT 0x00008000 + +#define WMREG_OLD_FCRTL 0x0168 /* Flow Control Rx Threshold Lo (OLD) */ +#define WMREG_FCRTH 0x2168 /* Flow Control Rx Threhsold Hi */ +#define FCRTL_DFLT 0x00004000 +#define FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +#define WMREG_FCTTV 0x0170 /* Flow Control Transmit Timer Value */ +#define FCTTV_DFLT 0x00000600 + +#define WMREG_TXCW 0x0178 /* Transmit Configuration Word (TBI mode) */ + /* See MII ANAR_X bits. */ +#define TXCW_TxConfig (1U << 30) /* Tx Config */ +#define TXCW_ANE (1U << 31) /* Autonegotiate */ + +#define WMREG_RXCW 0x0180 /* Receive Configuration Word (TBI mode) */ + /* See MII ANLPAR_X bits. */ +#define RXCW_NC (1U << 26) /* no carrier */ +#define RXCW_IV (1U << 27) /* config invalid */ +#define RXCW_CC (1U << 28) /* config change */ +#define RXCW_C (1U << 29) /* /C/ reception */ +#define RXCW_SYNCH (1U << 30) /* synchronized */ +#define RXCW_ANC (1U << 31) /* autonegotiation complete */ + +#define WMREG_MTA 0x0200 /* Multicast Table Array */ +#define WMREG_CORDOVA_MTA 0x5200 + +#define WMREG_TCTL 0x0400 /* Transmit Control Register */ +#define TCTL_EN (1U << 1) /* transmitter enable */ +#define TCTL_PSP (1U << 3) /* pad short packets */ +#define TCTL_CT(x) (((x) & 0xff) << 4) /* 4:11 - collision threshold */ +#define TCTL_COLD(x) (((x) & 0x3ff) << 12) /* 12:21 - collision distance */ +#define TCTL_SWXOFF (1U << 22) /* software XOFF */ +#define TCTL_RTLC (1U << 24) /* retransmit on late collision */ +#define TCTL_NRTU (1U << 25) /* no retransmit on underrun */ +#define TCTL_MULR (1U << 28) /* multiple request */ + +#define TX_COLLISION_THRESHOLD 15 +#define TX_COLLISION_DISTANCE_HDX 512 +#define TX_COLLISION_DISTANCE_FDX 64 + +#define WMREG_TCTL_EXT 0x0404 /* Transmit Control Register */ +#define TCTL_EXT_BST_MASK 0x000003FF /* Backoff Slot Time */ +#define TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ + +#define DEFAULT_80003ES2LAN_TCTL_EXT_GCEX 0x00010000 + +#define WMREG_TQSA_LO 0x0408 + +#define WMREG_TQSA_HI 0x040c + +#define WMREG_TIPG 0x0410 /* Transmit IPG Register */ +#define TIPG_IPGT(x) (x) /* IPG transmit time */ +#define TIPG_IPGR1(x) ((x) << 10) /* IPG receive time 1 */ +#define TIPG_IPGR2(x) ((x) << 20) /* IPG receive time 2 */ + +#define TIPG_WM_DFLT (TIPG_IPGT(0x0a) | TIPG_IPGR1(0x02) | TIPG_IPGR2(0x0a)) +#define TIPG_LG_DFLT (TIPG_IPGT(0x06) | TIPG_IPGR1(0x08) | TIPG_IPGR2(0x06)) +#define TIPG_1000T_DFLT (TIPG_IPGT(0x08) | TIPG_IPGR1(0x08) | TIPG_IPGR2(0x06)) +#define TIPG_1000T_80003_DFLT \ + (TIPG_IPGT(0x08) | TIPG_IPGR1(0x02) | TIPG_IPGR2(0x07)) +#define TIPG_10_100_80003_DFLT \ + (TIPG_IPGT(0x09) | TIPG_IPGR1(0x02) | TIPG_IPGR2(0x07)) + +#define WMREG_TQC 0x0418 + +#define WMREG_EEWR 0x102c /* EEPROM write */ + +#define WMREG_RDFH 0x2410 /* Receive Data FIFO Head */ + +#define WMREG_RDFT 0x2418 /* Receive Data FIFO Tail */ + +#define WMREG_RDFHS 0x2420 /* Receive Data FIFO Head Saved */ + +#define WMREG_RDFTS 0x2428 /* Receive Data FIFO Tail Saved */ + +#define WMREG_TDFH 0x3410 /* Transmit Data FIFO Head */ + +#define WMREG_TDFT 0x3418 /* Transmit Data FIFO Tail */ + +#define WMREG_TDFHS 0x3420 /* Transmit Data FIFO Head Saved */ + +#define WMREG_TDFTS 0x3428 /* Transmit Data FIFO Tail Saved */ + +#define WMREG_TDFPC 0x3430 /* Transmit Data FIFO Packet Count */ + +#define WMREG_OLD_TBDAL 0x0420 /* Transmit Descriptor Base Lo */ +#define WMREG_TBDAL 0x3800 + +#define WMREG_OLD_TBDAH 0x0424 /* Transmit Descriptor Base Hi */ +#define WMREG_TBDAH 0x3804 + +#define WMREG_OLD_TDLEN 0x0428 /* Transmit Descriptor Length */ +#define WMREG_TDLEN 0x3808 + +#define WMREG_OLD_TDH 0x0430 /* Transmit Descriptor Head */ +#define WMREG_TDH 0x3810 + +#define WMREG_OLD_TDT 0x0438 /* Transmit Descriptor Tail */ +#define WMREG_TDT 0x3818 + +#define WMREG_OLD_TIDV 0x0440 /* Transmit Delay Interrupt Value */ +#define WMREG_TIDV 0x3820 + +#define WMREG_TXDCTL 0x3828 /* Trandmit Descriptor Control */ +#define TXDCTL_PTHRESH(x) ((x) << 0) /* prefetch threshold */ +#define TXDCTL_HTHRESH(x) ((x) << 8) /* host threshold */ +#define TXDCTL_WTHRESH(x) ((x) << 16) /* write back threshold */ + +#define WMREG_TADV 0x382c /* Transmit Absolute Interrupt Delay Timer */ + +#define WMREG_AIT 0x0458 /* Adaptive IFS Throttle */ + +#define WMREG_VFTA 0x0600 + +#define WM_MC_TABSIZE 128 +#define WM_ICH8_MC_TABSIZE 32 +#define WM_VLAN_TABSIZE 128 + +#define WMREG_PBA 0x1000 /* Packet Buffer Allocation */ +#define PBA_BYTE_SHIFT 10 /* KB -> bytes */ +#define PBA_ADDR_SHIFT 7 /* KB -> quadwords */ +#define PBA_8K 0x0008 +#define PBA_12K 0x000c +#define PBA_16K 0x0010 /* 16K, default Tx allocation */ +#define PBA_22K 0x0016 +#define PBA_24K 0x0018 +#define PBA_30K 0x001e +#define PBA_32K 0x0020 +#define PBA_40K 0x0028 +#define PBA_48K 0x0030 /* 48K, default Rx allocation */ + +#define WMREG_PBS 0x1000 /* Packet Buffer Size (ICH8 only ?) */ + +#define WMREG_TXDMAC 0x3000 /* Transfer DMA Control */ +#define TXDMAC_DPP (1U << 0) /* disable packet prefetch */ + +#define WMREG_TSPMT 0x3830 /* TCP Segmentation Pad and Minimum + Threshold (Cordova) */ +#define TSPMT_TSMT(x) (x) /* TCP seg min transfer */ +#define TSPMT_TSPBP(x) ((x) << 16) /* TCP seg pkt buf padding */ + +#define WMREG_RXCSUM 0x5000 /* Receive Checksum register */ +#define RXCSUM_PCSS 0x000000ff /* Packet Checksum Start */ +#define RXCSUM_IPOFL (1U << 8) /* IP checksum offload */ +#define RXCSUM_TUOFL (1U << 9) /* TCP/UDP checksum offload */ +#define RXCSUM_IPV6OFL (1U << 10) /* IPv6 checksum offload */ + +#define WMREG_RXERRC 0x400C /* receive error Count - R/clr */ +#define WMREG_COLC 0x4028 /* collision Count - R/clr */ +#define WMREG_XONRXC 0x4048 /* XON Rx Count - R/clr */ +#define WMREG_XONTXC 0x404c /* XON Tx Count - R/clr */ +#define WMREG_XOFFRXC 0x4050 /* XOFF Rx Count - R/clr */ +#define WMREG_XOFFTXC 0x4054 /* XOFF Tx Count - R/clr */ +#define WMREG_FCRUC 0x4058 /* Flow Control Rx Unsupported Count - R/clr */ + +#define WMREG_KUMCTRLSTA 0x0034 /* MAC-PHY interface - RW */ +#define KUMCTRLSTA_MASK 0x0000FFFF +#define KUMCTRLSTA_OFFSET 0x001F0000 +#define KUMCTRLSTA_OFFSET_SHIFT 16 +#define KUMCTRLSTA_REN 0x00200000 + +#define KUMCTRLSTA_OFFSET_FIFO_CTRL 0x00000000 +#define KUMCTRLSTA_OFFSET_CTRL 0x00000001 +#define KUMCTRLSTA_OFFSET_INB_CTRL 0x00000002 +#define KUMCTRLSTA_OFFSET_DIAG 0x00000003 +#define KUMCTRLSTA_OFFSET_TIMEOUTS 0x00000004 +#define KUMCTRLSTA_OFFSET_INB_PARAM 0x00000009 +#define KUMCTRLSTA_OFFSET_HD_CTRL 0x00000010 +#define KUMCTRLSTA_OFFSET_M2P_SERDES 0x0000001E +#define KUMCTRLSTA_OFFSET_M2P_MODES 0x0000001F + +/* FIFO Control */ +#define KUMCTRLSTA_FIFO_CTRL_RX_BYPASS 0x00000008 +#define KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800 + +/* In-Band Control */ +#define KUMCTRLSTA_INB_CTRL_LINK_TMOUT_DFLT 0x00000500 +#define KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010 + +/* Half-Duplex Control */ +#define KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004 +#define KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000 + +#define WMREG_MDPHYA 0x003C /* PHY address - RW */ + +#define WMREG_MANC2H 0x5860 /* Managment Control To Host - RW */ + +#define WMREG_SWSM 0x5b50 /* SW Semaphore */ +#define SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define SWSM_WMNG 0x00000004 /* Wake MNG Clock */ +#define SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ + +#define WMREG_SW_FW_SYNC 0x5b5c /* software-firmware semaphore */ +#define SWFW_EEP_SM 0x0001 /* eeprom access */ +#define SWFW_PHY0_SM 0x0002 /* first ctrl phy access */ +#define SWFW_PHY1_SM 0x0004 /* second ctrl phy access */ +#define SWFW_MAC_CSR_SM 0x0008 +#define SWFW_SOFT_SHIFT 0 /* software semaphores */ +#define SWFW_FIRM_SHIFT 16 /* firmware semaphores */ + +#define WMREG_EXTCNFCTR 0x0f00 /* Extended Configuration Control */ +#define EXTCNFCTR_PCIE_WRITE_ENABLE 0x00000001 +#define EXTCNFCTR_PHY_WRITE_ENABLE 0x00000002 +#define EXTCNFCTR_D_UD_ENABLE 0x00000004 +#define EXTCNFCTR_D_UD_LATENCY 0x00000008 +#define EXTCNFCTR_D_UD_OWNER 0x00000010 +#define EXTCNFCTR_MDIO_SW_OWNERSHIP 0x00000020 +#define EXTCNFCTR_MDIO_HW_OWNERSHIP 0x00000040 +#define EXTCNFCTR_EXT_CNF_POINTER 0x0FFF0000 +#define E1000_EXTCNF_CTRL_SWFLAG EXTCNFCTR_MDIO_SW_OWNERSHIP + +/* ich8 flash control */ +#define ICH_FLASH_COMMAND_TIMEOUT 5000 /* 5000 uSecs - adjusted */ +#define ICH_FLASH_ERASE_TIMEOUT 3000000 /* Up to 3 seconds - worst case */ +#define ICH_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles */ +#define ICH_FLASH_SEG_SIZE_256 256 +#define ICH_FLASH_SEG_SIZE_4K 4096 +#define ICH_FLASH_SEG_SIZE_64K 65536 + +#define ICH_CYCLE_READ 0x0 +#define ICH_CYCLE_RESERVED 0x1 +#define ICH_CYCLE_WRITE 0x2 +#define ICH_CYCLE_ERASE 0x3 + +#define ICH_FLASH_GFPREG 0x0000 +#define ICH_FLASH_HSFSTS 0x0004 /* Flash Status Register */ +#define HSFSTS_DONE 0x0001 /* Flash Cycle Done */ +#define HSFSTS_ERR 0x0002 /* Flash Cycle Error */ +#define HSFSTS_DAEL 0x0004 /* Direct Access error Log */ +#define HSFSTS_ERSZ_MASK 0x0018 /* Block/Sector Erase Size */ +#define HSFSTS_ERSZ_SHIFT 3 +#define HSFSTS_FLINPRO 0x0020 /* flash SPI cycle in Progress */ +#define HSFSTS_FLDVAL 0x4000 /* Flash Descriptor Valid */ +#define HSFSTS_FLLK 0x8000 /* Flash Configuration Lock-Down */ +#define ICH_FLASH_HSFCTL 0x0006 /* Flash control Register */ +#define HSFCTL_GO 0x0001 /* Flash Cycle Go */ +#define HSFCTL_CYCLE_MASK 0x0006 /* Flash Cycle */ +#define HSFCTL_CYCLE_SHIFT 1 +#define HSFCTL_BCOUNT_MASK 0x0300 /* Data Byte Count */ +#define HSFCTL_BCOUNT_SHIFT 8 +#define ICH_FLASH_FADDR 0x0008 +#define ICH_FLASH_FDATA0 0x0010 +#define ICH_FLASH_FRACC 0x0050 +#define ICH_FLASH_FREG0 0x0054 +#define ICH_FLASH_FREG1 0x0058 +#define ICH_FLASH_FREG2 0x005C +#define ICH_FLASH_FREG3 0x0060 +#define ICH_FLASH_FPR0 0x0074 +#define ICH_FLASH_FPR1 0x0078 +#define ICH_FLASH_SSFSTS 0x0090 +#define ICH_FLASH_SSFCTL 0x0092 +#define ICH_FLASH_PREOP 0x0094 +#define ICH_FLASH_OPTYPE 0x0096 +#define ICH_FLASH_OPMENU 0x0098 + +#define ICH_FLASH_REG_MAPSIZE 0x00A0 +#define ICH_FLASH_SECTOR_SIZE 4096 +#define ICH_GFPREG_BASE_MASK 0x1FFF +#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF + +/* start of Kate Feng added */ +#define WMREG_GPTC 0x4080 /* Good packets transmitted count */ +#define WMREG_GPRC 0x4074 /* Good packets received count */ +#define WMREG_CRCERRS 0x4000 /* CRC Error Count */ +#define WMREG_RLEC 0x4040 /* Receive Length Error Count */ +/* end of Kate Feng added */ diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pci_map.c b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pci_map.c new file mode 100644 index 0000000000..c238e637d0 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pci_map.c @@ -0,0 +1,131 @@ +/* $NetBSD: pci_map.c,v 1.12 2002/05/30 12:06:43 drochner Exp $ */ + +/*- + * Copyright (c) 2004, 2005 Brookhaven National Laboratory + * S. Kate Feng + * + * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum; by William R. Studenmund; by Jason R. Thorpe. + * + */ + +/* + * PCI device mapping. + */ + +#include +#include +#include +#include + +#include +#include + +int pci_io_find(int b, int d, int f, int reg,unsigned *basep,unsigned *sizep) +{ + uint32_t address, mask; + + if (reg < PCI_MAPREG_START || +#if 0 + /* + * Can't do this check; some devices have mapping registers + * way out in left field. + */ + reg >= PCI_MAPREG_END || +#endif + (reg & 3)) + rtems_panic("pci_io_find: bad request"); + + /* + * Section 6.2.5.1, `Address Maps', tells us that: + * + * 1) The builtin software should have already mapped the device in a + * reasonable way. + * + * 2) A device which wants 2^n bytes of memory will hardwire the bottom + * n bits of the address to 0. As recommended, we write all 1s and see + * what we get back. + */ + pci_read_config_dword(b,d,f,reg, &address); + if ( !(address & PCI_MAPREG_TYPE_IO)) return(1); + pci_write_config_dword(b,d,f,reg, 0xffffffff); + pci_read_config_dword(b,d,f,reg,&mask); + pci_write_config_dword(b,d,f,reg, address); + + if ( (*sizep = PCI_MAPREG_IO_SIZE(mask))== 0) { + printk("pci_io_find: void region\n"); + return(1); + } + *basep = PCI_MAPREG_IO_ADDR(address); + return(0); +} + +int pci_mem_find(int b, int d, int f, int reg, unsigned *basep,unsigned *sizep) +{ + uint32_t address, mask; + + if (reg < PCI_MAPREG_START || +#if 0 + /* + * Can't do this check; some devices have mapping registers + * way out in left field. + */ + reg >= PCI_MAPREG_END || +#endif + (reg & 3)) + rtems_panic("pci_mem_find: bad request"); + + pci_read_config_dword(b,d,f,reg, &address); + if (address & PCI_MAPREG_TYPE_IO) { + printk("pci_mem_find: expected type mem, found I/O\n"); + return(1); + } + + /* + * Section 6.2.5.1, `Address Maps', tells us that: + * + * 1) The builtin software should have already mapped the device in a + * reasonable way. + * + * 2) A device which wants 2^n bytes of memory will hardwire the bottom + * n bits of the address to 0. As recommended, we write all 1s and see + * what we get back. + */ + pci_write_config_dword(b,d,f,reg, 0xffffffff); + pci_read_config_dword(b,d,f,reg,&mask); + pci_write_config_dword(b,d,f,reg, address); + if ( (*sizep = PCI_MAPREG_MEM_SIZE(mask))== 0) { + printk("pci_io_find: void region\n"); + return (1); + } + *basep = PCI_MAPREG_MEM_ADDR(address); + return(0); +} + +int pci_get_capability(int b, int d, int f, int capid,int *offset,uint32_t *value) +{ + uint32_t reg, ofs; + + /* i82544EI PCI_CAPLISTPTR_REG */ + pci_read_config_dword(b,d,f,PCI_CAPLISTPTR_REG, ®); + ofs = PCI_CAPLIST_PTR(reg); + while (ofs != 0) { +#ifdef DIAGNOSTIC + if ((ofs & 3) || (ofs < 0x40)) + panic("pci_get_capability"); +#endif + pci_read_config_dword(b,d,f,ofs, ®); + if (PCI_CAPLIST_CAP(reg) == capid) { + if (offset) + *offset = ofs; + if (value) + *value = reg; + return (1); + } + ofs = PCI_CAPLIST_NEXT(reg); + } + return (0); +} diff --git a/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pcireg.h b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pcireg.h new file mode 100644 index 0000000000..4a31bbe621 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/network/if_1GHz/pcireg.h @@ -0,0 +1,384 @@ +/* $NetBSD: pcireg.h,v 1.44 2003/12/02 16:31:06 briggs Exp $ */ + +/* + * Copyright (c) 1995, 1996, 1999, 2000 + * Christopher G. Demetriou. All rights reserved. + * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * PCI Class and Revision Register; defines type and revision of device. + */ +#define PCI_CLASS_REG 0x08 + +#define PCI_CLASS_SHIFT 24 +#define PCI_CLASS_MASK 0xff +#define PCI_CLASS(cr) \ + (((cr) >> PCI_CLASS_SHIFT) & PCI_CLASS_MASK) + +#define PCI_SUBCLASS_SHIFT 16 +#define PCI_SUBCLASS_MASK 0xff +#define PCI_SUBCLASS(cr) \ + (((cr) >> PCI_SUBCLASS_SHIFT) & PCI_SUBCLASS_MASK) + +#define PCI_INTERFACE_SHIFT 8 +#define PCI_INTERFACE_MASK 0xff +#define PCI_INTERFACE(cr) \ + (((cr) >> PCI_INTERFACE_SHIFT) & PCI_INTERFACE_MASK) + +#define PCI_REVISION_SHIFT 0 +#define PCI_REVISION_MASK 0xff +#define PCI_REVISION(cr) \ + (((cr) >> PCI_REVISION_SHIFT) & PCI_REVISION_MASK) + +#define PCI_CLASS_CODE(mainclass, subclass, interface) \ + ((((mainclass) & PCI_CLASS_MASK) << PCI_CLASS_SHIFT) | \ + (((subclass) & PCI_SUBCLASS_MASK) << PCI_SUBCLASS_SHIFT) | \ + (((interface) & PCI_INTERFACE_MASK) << PCI_INTERFACE_SHIFT)) + +/* base classes */ +#define PCI_CLASS_PREHISTORIC 0x00 +#define PCI_CLASS_MASS_STORAGE 0x01 +#define PCI_CLASS_NETWORK 0x02 +#define PCI_CLASS_DISPLAY 0x03 +#define PCI_CLASS_MULTIMEDIA 0x04 +#define PCI_CLASS_MEMORY 0x05 +#define PCI_CLASS_BRIDGE 0x06 +#define PCI_CLASS_COMMUNICATIONS 0x07 +#define PCI_CLASS_SYSTEM 0x08 +#define PCI_CLASS_INPUT 0x09 +#define PCI_CLASS_DOCK 0x0a +#define PCI_CLASS_PROCESSOR 0x0b +#define PCI_CLASS_SERIALBUS 0x0c +#define PCI_CLASS_WIRELESS 0x0d +#define PCI_CLASS_I2O 0x0e +#define PCI_CLASS_SATCOM 0x0f +#define PCI_CLASS_CRYPTO 0x10 +#define PCI_CLASS_DASP 0x11 +#define PCI_CLASS_UNDEFINED 0xff + +/* 0x00 prehistoric subclasses */ +#define PCI_SUBCLASS_PREHISTORIC_MISC 0x00 +#define PCI_SUBCLASS_PREHISTORIC_VGA 0x01 + +/* 0x01 mass storage subclasses */ +#define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00 +#define PCI_SUBCLASS_MASS_STORAGE_IDE 0x01 +#define PCI_SUBCLASS_MASS_STORAGE_FLOPPY 0x02 +#define PCI_SUBCLASS_MASS_STORAGE_IPI 0x03 +#define PCI_SUBCLASS_MASS_STORAGE_RAID 0x04 +#define PCI_SUBCLASS_MASS_STORAGE_ATA 0x05 +#define PCI_SUBCLASS_MASS_STORAGE_SATA 0x06 +#define PCI_SUBCLASS_MASS_STORAGE_MISC 0x80 + +/* 0x02 network subclasses */ +#define PCI_SUBCLASS_NETWORK_ETHERNET 0x00 +#define PCI_SUBCLASS_NETWORK_TOKENRING 0x01 +#define PCI_SUBCLASS_NETWORK_FDDI 0x02 +#define PCI_SUBCLASS_NETWORK_ATM 0x03 +#define PCI_SUBCLASS_NETWORK_ISDN 0x04 +#define PCI_SUBCLASS_NETWORK_WORLDFIP 0x05 +#define PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP 0x06 +#define PCI_SUBCLASS_NETWORK_MISC 0x80 + +/* 0x03 display subclasses */ +#define PCI_SUBCLASS_DISPLAY_VGA 0x00 +#define PCI_SUBCLASS_DISPLAY_XGA 0x01 +#define PCI_SUBCLASS_DISPLAY_3D 0x02 +#define PCI_SUBCLASS_DISPLAY_MISC 0x80 + +/* 0x04 multimedia subclasses */ +#define PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00 +#define PCI_SUBCLASS_MULTIMEDIA_AUDIO 0x01 +#define PCI_SUBCLASS_MULTIMEDIA_TELEPHONY 0x02 +#define PCI_SUBCLASS_MULTIMEDIA_MISC 0x80 + +/* 0x05 memory subclasses */ +#define PCI_SUBCLASS_MEMORY_RAM 0x00 +#define PCI_SUBCLASS_MEMORY_FLASH 0x01 +#define PCI_SUBCLASS_MEMORY_MISC 0x80 + +/* 0x06 bridge subclasses */ +#define PCI_SUBCLASS_BRIDGE_HOST 0x00 +#define PCI_SUBCLASS_BRIDGE_ISA 0x01 +#define PCI_SUBCLASS_BRIDGE_EISA 0x02 +#define PCI_SUBCLASS_BRIDGE_MC 0x03 /* XXX _MCA? */ +#define PCI_SUBCLASS_BRIDGE_PCI 0x04 +#define PCI_SUBCLASS_BRIDGE_PCMCIA 0x05 +#define PCI_SUBCLASS_BRIDGE_NUBUS 0x06 +#define PCI_SUBCLASS_BRIDGE_CARDBUS 0x07 +#define PCI_SUBCLASS_BRIDGE_RACEWAY 0x08 +#define PCI_SUBCLASS_BRIDGE_STPCI 0x09 +#define PCI_SUBCLASS_BRIDGE_INFINIBAND 0x0a +#define PCI_SUBCLASS_BRIDGE_MISC 0x80 + +/* 0x07 communications subclasses */ +#define PCI_SUBCLASS_COMMUNICATIONS_SERIAL 0x00 +#define PCI_SUBCLASS_COMMUNICATIONS_PARALLEL 0x01 +#define PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL 0x02 +#define PCI_SUBCLASS_COMMUNICATIONS_MODEM 0x03 +#define PCI_SUBCLASS_COMMUNICATIONS_GPIB 0x04 +#define PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD 0x05 +#define PCI_SUBCLASS_COMMUNICATIONS_MISC 0x80 + +/* 0x08 system subclasses */ +#define PCI_SUBCLASS_SYSTEM_PIC 0x00 +#define PCI_SUBCLASS_SYSTEM_DMA 0x01 +#define PCI_SUBCLASS_SYSTEM_TIMER 0x02 +#define PCI_SUBCLASS_SYSTEM_RTC 0x03 +#define PCI_SUBCLASS_SYSTEM_PCIHOTPLUG 0x04 +#define PCI_SUBCLASS_SYSTEM_MISC 0x80 + +/* 0x09 input subclasses */ +#define PCI_SUBCLASS_INPUT_KEYBOARD 0x00 +#define PCI_SUBCLASS_INPUT_DIGITIZER 0x01 +#define PCI_SUBCLASS_INPUT_MOUSE 0x02 +#define PCI_SUBCLASS_INPUT_SCANNER 0x03 +#define PCI_SUBCLASS_INPUT_GAMEPORT 0x04 +#define PCI_SUBCLASS_INPUT_MISC 0x80 + +/* 0x0a dock subclasses */ +#define PCI_SUBCLASS_DOCK_GENERIC 0x00 +#define PCI_SUBCLASS_DOCK_MISC 0x80 + +/* 0x0b processor subclasses */ +#define PCI_SUBCLASS_PROCESSOR_386 0x00 +#define PCI_SUBCLASS_PROCESSOR_486 0x01 +#define PCI_SUBCLASS_PROCESSOR_PENTIUM 0x02 +#define PCI_SUBCLASS_PROCESSOR_ALPHA 0x10 +#define PCI_SUBCLASS_PROCESSOR_POWERPC 0x20 +#define PCI_SUBCLASS_PROCESSOR_MIPS 0x30 +#define PCI_SUBCLASS_PROCESSOR_COPROC 0x40 + +/* 0x0c serial bus subclasses */ +#define PCI_SUBCLASS_SERIALBUS_FIREWIRE 0x00 +#define PCI_SUBCLASS_SERIALBUS_ACCESS 0x01 +#define PCI_SUBCLASS_SERIALBUS_SSA 0x02 +#define PCI_SUBCLASS_SERIALBUS_USB 0x03 +#define PCI_SUBCLASS_SERIALBUS_FIBER 0x04 /* XXX _FIBRECHANNEL */ +#define PCI_SUBCLASS_SERIALBUS_SMBUS 0x05 +#define PCI_SUBCLASS_SERIALBUS_INFINIBAND 0x06 +#define PCI_SUBCLASS_SERIALBUS_IPMI 0x07 +#define PCI_SUBCLASS_SERIALBUS_SERCOS 0x08 +#define PCI_SUBCLASS_SERIALBUS_CANBUS 0x09 + +/* 0x0d wireless subclasses */ +#define PCI_SUBCLASS_WIRELESS_IRDA 0x00 +#define PCI_SUBCLASS_WIRELESS_CONSUMERIR 0x01 +#define PCI_SUBCLASS_WIRELESS_RF 0x10 +#define PCI_SUBCLASS_WIRELESS_BLUETOOTH 0x11 +#define PCI_SUBCLASS_WIRELESS_BROADBAND 0x12 +#define PCI_SUBCLASS_WIRELESS_802_11A 0x20 +#define PCI_SUBCLASS_WIRELESS_802_11B 0x21 +#define PCI_SUBCLASS_WIRELESS_MISC 0x80 + +/* 0x0e I2O (Intelligent I/O) subclasses */ +#define PCI_SUBCLASS_I2O_STANDARD 0x00 + +/* 0x0f satellite communication subclasses */ +/* PCI_SUBCLASS_SATCOM_??? 0x00 / * XXX ??? */ +#define PCI_SUBCLASS_SATCOM_TV 0x01 +#define PCI_SUBCLASS_SATCOM_AUDIO 0x02 +#define PCI_SUBCLASS_SATCOM_VOICE 0x03 +#define PCI_SUBCLASS_SATCOM_DATA 0x04 + +/* 0x10 encryption/decryption subclasses */ +#define PCI_SUBCLASS_CRYPTO_NETCOMP 0x00 +#define PCI_SUBCLASS_CRYPTO_ENTERTAINMENT 0x10 +#define PCI_SUBCLASS_CRYPTO_MISC 0x80 + +/* 0x11 data acquisition and signal processing subclasses */ +#define PCI_SUBCLASS_DASP_DPIO 0x00 +#define PCI_SUBCLASS_DASP_TIMEFREQ 0x01 +#define PCI_SUBCLASS_DASP_SYNC 0x10 +#define PCI_SUBCLASS_DASP_MGMT 0x20 +#define PCI_SUBCLASS_DASP_MISC 0x80 + +/* + * PCI BIST/Header Type/Latency Timer/Cache Line Size Register. + */ +#define PCI_BHLC_REG 0x0c + +#define PCI_BIST_SHIFT 24 +#define PCI_BIST_MASK 0xff +#define PCI_BIST(bhlcr) \ + (((bhlcr) >> PCI_BIST_SHIFT) & PCI_BIST_MASK) + +#define PCI_HDRTYPE_SHIFT 16 +#define PCI_HDRTYPE_MASK 0xff +#define PCI_HDRTYPE(bhlcr) \ + (((bhlcr) >> PCI_HDRTYPE_SHIFT) & PCI_HDRTYPE_MASK) + +#define PCI_HDRTYPE_TYPE(bhlcr) \ + (PCI_HDRTYPE(bhlcr) & 0x7f) +#define PCI_HDRTYPE_MULTIFN(bhlcr) \ + ((PCI_HDRTYPE(bhlcr) & 0x80) != 0) + +#define PCI_LATTIMER_SHIFT 8 +#define PCI_LATTIMER_MASK 0xff +#define PCI_LATTIMER(bhlcr) \ + (((bhlcr) >> PCI_LATTIMER_SHIFT) & PCI_LATTIMER_MASK) + +#define PCI_CACHELINE_SHIFT 0 +#define PCI_CACHELINE_MASK 0xff +#define PCI_CACHELINE(bhlcr) \ + (((bhlcr) >> PCI_CACHELINE_SHIFT) & PCI_CACHELINE_MASK) + +#define PCI_BHLC_CODE(bist,type,multi,latency,cacheline) \ + ((((bist) & PCI_BIST_MASK) << PCI_BIST_SHIFT) | \ + (((type) & PCI_HDRTYPE_MASK) << PCI_HDRTYPE_SHIFT) | \ + (((multi)?0x80:0) << PCI_HDRTYPE_SHIFT) | \ + (((latency) & PCI_LATTIMER_MASK) << PCI_LATTIMER_SHIFT) | \ + (((cacheline) & PCI_CACHELINE_MASK) << PCI_CACHELINE_SHIFT)) + +/* + * PCI header type + */ +#define PCI_HDRTYPE_DEVICE 0 +#define PCI_HDRTYPE_PPB 1 +#define PCI_HDRTYPE_PCB 2 + +/* + * Mapping registers + */ +#define PCI_MAPREG_START 0x10 +#define PCI_MAPREG_END 0x28 +#define PCI_MAPREG_ROM 0x30 +#define PCI_MAPREG_PPB_END 0x18 +#define PCI_MAPREG_PCB_END 0x14 + +#define PCI_MAPREG_TYPE(mr) \ + ((mr) & PCI_MAPREG_TYPE_MASK) +#define PCI_MAPREG_TYPE_MASK 0x00000001 + +#define PCI_MAPREG_TYPE_MEM 0x00000000 +#define PCI_MAPREG_TYPE_IO 0x00000001 +#define PCI_MAPREG_ROM_ENABLE 0x00000001 + +#define PCI_MAPREG_MEM_TYPE(mr) \ + ((mr) & PCI_MAPREG_MEM_TYPE_MASK) +#define PCI_MAPREG_MEM_TYPE_MASK 0x00000006 + +#define PCI_MAPREG_MEM_TYPE_32BIT 0x00000000 +#define PCI_MAPREG_MEM_TYPE_32BIT_1M 0x00000002 +#define PCI_MAPREG_MEM_TYPE_64BIT 0x00000004 + +#define PCI_MAPREG_MEM_PREFETCHABLE(mr) \ + (((mr) & PCI_MAPREG_MEM_PREFETCHABLE_MASK) != 0) +#define PCI_MAPREG_MEM_PREFETCHABLE_MASK 0x00000008 + +#define PCI_MAPREG_MEM_ADDR(mr) \ + ((mr) & PCI_MAPREG_MEM_ADDR_MASK) +#define PCI_MAPREG_MEM_SIZE(mr) \ + (PCI_MAPREG_MEM_ADDR(mr) & -PCI_MAPREG_MEM_ADDR(mr)) +#define PCI_MAPREG_MEM_ADDR_MASK 0xfffffff0 + +#define PCI_MAPREG_MEM64_ADDR(mr) \ + ((mr) & PCI_MAPREG_MEM64_ADDR_MASK) +#define PCI_MAPREG_MEM64_SIZE(mr) \ + (PCI_MAPREG_MEM64_ADDR(mr) & -PCI_MAPREG_MEM64_ADDR(mr)) +#define PCI_MAPREG_MEM64_ADDR_MASK 0xfffffffffffffff0ULL + +#define PCI_MAPREG_IO_ADDR(mr) \ + ((mr) & PCI_MAPREG_IO_ADDR_MASK) +#define PCI_MAPREG_IO_SIZE(mr) \ + (PCI_MAPREG_IO_ADDR(mr) & -PCI_MAPREG_IO_ADDR(mr)) +#define PCI_MAPREG_IO_ADDR_MASK 0xfffffffc + +#define PCI_MAPREG_SIZE_TO_MASK(size) \ + (-(size)) + +#define PCI_MAPREG_NUM(offset) \ + (((unsigned)(offset)-PCI_MAPREG_START)/4) + + +/* + * Cardbus CIS pointer (PCI rev. 2.1) + */ +#define PCI_CARDBUS_CIS_REG 0x28 + +/* + * Subsystem identification register; contains a vendor ID and a device ID. + * Types/macros for PCI_ID_REG apply. + * (PCI rev. 2.1) + */ +#define PCI_SUBSYS_ID_REG 0x2c + +/* + * capabilities link list (PCI rev. 2.2) + */ +#define PCI_CAPLISTPTR_REG 0x34 /* header type 0 */ +#define PCI_CARDBUS_CAPLISTPTR_REG 0x14 /* header type 2 */ +#define PCI_CAPLIST_PTR(cpr) ((cpr) & 0xff) +#define PCI_CAPLIST_NEXT(cr) (((cr) >> 8) & 0xff) +#define PCI_CAPLIST_CAP(cr) ((cr) & 0xff) + +#define PCI_CAP_RESERVED0 0x00 +#define PCI_CAP_PWRMGMT 0x01 +#define PCI_CAP_AGP 0x02 +#define PCI_CAP_VPD 0x03 +#define PCI_CAP_SLOTID 0x04 +#define PCI_CAP_MSI 0x05 +#define PCI_CAP_CPCI_HOTSWAP 0x06 +#define PCI_CAP_PCIX 0x07 +#define PCI_CAP_LDT 0x08 +#define PCI_CAP_VENDSPEC 0x09 +#define PCI_CAP_DEBUGPORT 0x0a +#define PCI_CAP_CPCI_RSRCCTL 0x0b +#define PCI_CAP_HOTPLUG 0x0c +#define PCI_CAP_AGP8 0x0e +#define PCI_CAP_SECURE 0x0f +#define PCI_CAP_PCIEXPRESS 0x10 +#define PCI_CAP_MSIX 0x11 + +/* + * Vital Product Data; access via capability pointer (PCI rev 2.2). + */ +#define PCI_VPD_ADDRESS_MASK 0x7fff +#define PCI_VPD_ADDRESS_SHIFT 16 +#define PCI_VPD_ADDRESS(ofs) \ + (((ofs) & PCI_VPD_ADDRESS_MASK) << PCI_VPD_ADDRESS_SHIFT) +#define PCI_VPD_DATAREG(ofs) ((ofs) + 4) +#define PCI_VPD_OPFLAG 0x80000000 + +/* + * Power Management Capability; access via capability pointer. + */ + +/* Power Management Capability Register */ +#define PCI_PMCR 0x02 +#define PCI_PMCR_D1SUPP 0x0200 +#define PCI_PMCR_D2SUPP 0x0400 +/* Power Management Control Status Register */ +#define PCI_PMCSR 0x04 +#define PCI_PMCSR_STATE_MASK 0x03 +#define PCI_PMCSR_STATE_D0 0x00 +#define PCI_PMCSR_STATE_D1 0x01 +#define PCI_PMCSR_STATE_D2 0x02 +#define PCI_PMCSR_STATE_D3 0x03 + diff --git a/c/src/lib/libbsp/powerpc/mvme5500/pci/pci.c b/c/src/lib/libbsp/powerpc/mvme5500/pci/pci.c index ed8532ec04..729c8a0640 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/pci/pci.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/pci/pci.c @@ -34,8 +34,8 @@ #include #include -/* #define PCI_DEBUG 1 */ -/* #define PCI_PRINT 1 */ +#define PCI_DEBUG 0 +#define PCI_PRINT 0 /* allow for overriding these definitions */ #ifndef PCI_CONFIG_ADDR @@ -251,11 +251,6 @@ int pci_initialize() unsigned char ucBusNumber, ucSlotNumber, ucFnNumber, ucNumFuncs; unsigned int ulHeader; unsigned int pcidata, ulClass, ulDeviceID; -#if PCI_DEBUG - unsigned short sdata; - unsigned int data; -#endif - pci_interface(); diff --git a/c/src/lib/libbsp/powerpc/mvme5500/pci/pci_interface.c b/c/src/lib/libbsp/powerpc/mvme5500/pci/pci_interface.c index c1a56775d4..f19f9bc69c 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/pci/pci_interface.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/pci/pci_interface.c @@ -1,11 +1,15 @@ /* pci_interface.c * - * Copyright 2004, Brookhaven National Laboratory and - * Shuchen Kate Feng + * Copyright 2004, 2006, 2007 All rights reserved. (NDA items) + * Brookhaven National Laboratory and Shuchen Kate Feng * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution. * + * 8/17/2006 : S. Kate Feng + * uses in_le32()/out_le32(), instead of inl()/outl() so that + * it is easier to be ported. + * */ #include #include /* printk */ @@ -15,15 +19,16 @@ #include #include +#define REG32_READ(reg) in_le32((volatile unsigned int *)(GT64260_REG_BASE+reg)) +#define REG32_WRITE(data, reg) out_le32((volatile unsigned int *)(GT64260_REG_BASE+reg), data) + #define PCI_DEBUG 0 /* Please reference the GT64260B datasheet, for the PCI interface, * Synchronization Barriers and PCI ordering. * * Some PCI devices require Synchronization Barriers or PCI ordering - * for synchronization. For example, the VME-OMS58 motor controller we - * used at NSLS requires either enhanced CPU Synchronization Barrier - * or PCI-ordering (only one mechanism allowed. See section 11.1.2). + * for synchronization (only one mechanism allowed. See section 11.1.2). * To use the former mechanism(default), one needs to call * CPU0_PciEnhanceSync() or CPU1_PciEnhanceSync() to perform software * synchronization between the CPU and PCI activities. @@ -39,12 +44,11 @@ * function correctly. * */ -#define PCI_ORDERING +/*#define PCI_ORDERING*/ -/*#define PCI_DEADLOCK*/ +#define EN_SYN_BAR /* take MOTLoad default for enhanced SYN Barrier mode */ -/* So far, I do not see the need to disable the address pipelining. -#define DIS_ADDR_PIPELINE*/ +/*#define PCI_DEADLOCK*/ #ifdef PCI_ORDERING #define PCI_ACCCTLBASEL_VALUE 0x01009000 @@ -86,40 +90,18 @@ void pciAccessInit(); void pci_interface() { - unsigned int data; - -#if (defined(PCI_ORDERING)||defined(DIS_ADDR_PIPELINE)) - data = inl(0); /* needed : read to flush */ - /* MOTLOad default disables Configuration and I/O Read Sync Barrier - * which is needed for enhanced CPU sync. barrier */ -#ifdef PCI_ORDERING - /* enable Configuration Read Sync Barrier and IO read Sync Barrier*/ - data &= ~ConfIOSBDis; -#endif -#ifdef DIS_ADDR_PIPELINE - data &= ~ADDR_PIPELINE; - -#if PCI_DEBUG - printk("data %x\n", data); -#endif -#endif - outl(data, 0); - /* read polling of the register until the new data is being read */ - while ( inl(0)!=data); -#endif #ifdef PCI_DEADLOCK - outl(0x07fff600, CNT_SYNC_REG); + REG32_WRITE(0x07fff600, CNT_SYNC_REG); #endif #ifdef PCI_ORDERING - outl(0xc0060002, DLOCK_ORDER_REG); - outl(0x07fff600, CNT_SYNC_REG); -#else - outl(inl(PCI_CMD_CNTL)|PCI_COMMAND_SB_DIS, PCI_CMD_CNTL); + /* Let's leave this to be MOTLOad deafult : 0x80070000 + REG32_WRITE(0xc0070000, DLOCK_ORDER_REG);*/ + /* Leave the CNT_SYNC_REG b/c MOTload default had the SyncBarMode set to 1 */ #endif /* asserts SERR upon various detection */ - outl(0x3fffff, 0xc28); + REG32_WRITE(0x3fffff, 0xc28); pciAccessInit(); } @@ -133,13 +115,14 @@ void pciAccessInit() /* MOTLoad combines the two banks of SDRAM into * one PCI access control because the top = 0x1ff */ - data = inl(GT_SCS0_Low_Decode) & 0xfff; + data = REG32_READ(GT_SCS0_Low_Decode) & 0xfff; data |= PCI_ACCCTLBASEL_VALUE; data &= ~0x300000; - outl(data, PCI0_ACCESS_CNTL_BASE0_LOW+(PciLocal * 0x80)); + REG32_WRITE(data, PCI0_ACCESS_CNTL_BASE0_LOW+(PciLocal * 0x80)); #if PCI_DEBUG - printk("PCI%d_ACCESS_CNTL_BASE0_LOW 0x%x\n",PciLocal,inl(PCI_ACCESS_CNTL_BASE0_LOW+(PciLocal * 0x80))); + printk("PCI%d_ACCESS_CNTL_BASE0_LOW 0x%x\n",PciLocal,REG32_READ(PCI_ACCESS_CNTL_BASE0_LOW+(PciLocal * 0x80))); #endif + } } @@ -152,14 +135,14 @@ void pciAccessInit() */ void CPU0_PciEnhanceSync(unsigned int syncVal) { - outl(syncVal,CPU0_SYNC_TRIGGER); - while (inl(CPU0_SYNC_VIRTUAL)); + REG32_WRITE(syncVal,CPU0_SYNC_TRIGGER); + while (REG32_READ(CPU0_SYNC_VIRTUAL)); } void CPU1_PciEnhanceSync(unsigned int syncVal) { - outl(syncVal,CPU1_SYNC_TRIGGER); - while (inl(CPU1_SYNC_VIRTUAL)); + REG32_WRITE(syncVal,CPU1_SYNC_TRIGGER); + while (REG32_READ(CPU1_SYNC_VIRTUAL)); } /* Currently, if PCI_ordering is used for synchronization, configuration diff --git a/c/src/lib/libbsp/powerpc/mvme5500/pci/pcifinddevice.c b/c/src/lib/libbsp/powerpc/mvme5500/pci/pcifinddevice.c index 9fcdd61ae2..c3b677d015 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/pci/pcifinddevice.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/pci/pcifinddevice.c @@ -1,56 +1,11 @@ /* pcifinddevice.c * + * Copyright 2001, Till Straumann * * find a particular PCI device * (we assume, the firmware configured the PCI bus[es] for us) * - */ - -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann , 2001, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ -/* * Kate Feng , modified it to support the mvme5500 board. * */ diff --git a/c/src/lib/libbsp/powerpc/mvme5500/preinstall.am b/c/src/lib/libbsp/powerpc/mvme5500/preinstall.am index 8caab7ae5e..06011b64f2 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/preinstall.am +++ b/c/src/lib/libbsp/powerpc/mvme5500/preinstall.am @@ -19,12 +19,12 @@ PREINSTALL_FILES = CLEANFILES += $(PREINSTALL_FILES) $(PROJECT_LIB)/$(dirstamp): - @$(MKDIR_P) $(PROJECT_LIB) + @$(mkdir_p) $(PROJECT_LIB) @: > $(PROJECT_LIB)/$(dirstamp) PREINSTALL_DIRS += $(PROJECT_LIB)/$(dirstamp) $(PROJECT_INCLUDE)/$(dirstamp): - @$(MKDIR_P) $(PROJECT_INCLUDE) + @$(mkdir_p) $(PROJECT_INCLUDE) @: > $(PROJECT_INCLUDE)/$(dirstamp) PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp) @@ -49,7 +49,7 @@ $(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/ PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h $(PROJECT_INCLUDE)/bsp/$(dirstamp): - @$(MKDIR_P) $(PROJECT_INCLUDE)/bsp + @$(mkdir_p) $(PROJECT_INCLUDE)/bsp @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp) PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp) @@ -61,9 +61,9 @@ $(PROJECT_INCLUDE)/bsp/uart.h: ../../powerpc/shared/console/uart.h $(PROJECT_INC $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/uart.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/uart.h -$(PROJECT_INCLUDE)/bsp/vme_am_defs.h: ../../shared/vmeUniverse/vme_am_defs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vme_am_defs.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vme_am_defs.h +$(PROJECT_INCLUDE)/bsp/consoleIo.h: ../../powerpc/shared/console/consoleIo.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/consoleIo.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/consoleIo.h $(PROJECT_INCLUDE)/bsp/gtpcireg.h: pci/gtpcireg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gtpcireg.h @@ -106,14 +106,22 @@ $(PROJECT_INCLUDE)/bsp/VPD.h: GT64260/VPD.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/VPD.h if HAS_NETWORKING -$(PROJECT_INCLUDE)/bsp/GT64260eth.h: network/GT64260eth.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) +$(PROJECT_INCLUDE)/bsp/GT64260eth.h: network/if_100MHz/GT64260eth.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/GT64260eth.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/GT64260eth.h -$(PROJECT_INCLUDE)/bsp/GT64260ethreg.h: network/GT64260ethreg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) +$(PROJECT_INCLUDE)/bsp/GT64260ethreg.h: network/if_100MHz/GT64260ethreg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/GT64260ethreg.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/GT64260ethreg.h +$(PROJECT_INCLUDE)/bsp/if_wmreg.h: network/if_1GHz/if_wmreg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/if_wmreg.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/if_wmreg.h + +$(PROJECT_INCLUDE)/bsp/pcireg.h: network/if_1GHz/pcireg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/pcireg.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/pcireg.h endif + $(PROJECT_INCLUDE)/bsp/VME.h: ../../shared/vmeUniverse/VME.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/VME.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/VME.h @@ -126,6 +134,10 @@ $(PROJECT_INCLUDE)/bsp/vmeUniverse.h: ../../shared/vmeUniverse/vmeUniverse.h $(P $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vmeUniverse.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vmeUniverse.h +$(PROJECT_INCLUDE)/bsp/vme_am_defs.h: ../../shared/vmeUniverse/vme_am_defs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vme_am_defs.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vme_am_defs.h + $(PROJECT_INCLUDE)/bsp/vmeUniverseDMA.h: ../../shared/vmeUniverse/vmeUniverseDMA.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vmeUniverseDMA.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vmeUniverseDMA.h diff --git a/c/src/lib/libbsp/powerpc/mvme5500/start/preload.S b/c/src/lib/libbsp/powerpc/mvme5500/start/preload.S index 8262f41d7c..9da4b1ca7d 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/start/preload.S +++ b/c/src/lib/libbsp/powerpc/mvme5500/start/preload.S @@ -1,9 +1,8 @@ /* - * Mini-loader for the SVGM and MVME5500 BSP. + * Mini-loader for the SVGM BSP. * * $Id$ * - * Copyright (C) 2003, 2004 * Author: Till Straumann, 10/2001 * * Some ideas are borrowed from the powerpc/shared/bootloader @@ -11,9 +10,8 @@ * Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es * Copyright (C) 1999 Eric Valette. valette@crf.canon.fr * - * - * The SVGM firmware is unable to load the RTEMS image below - * 0x2000 (I believe their stack is growing below 0x1000) ? + * The SMON firmware is unable to load the RTEMS image below + * 0x2000 (I believe their stack is growing below 0x1000). * * The code provided by this file is responsible for the performing * the following steps: @@ -23,13 +21,11 @@ * b) will not be overwritten by the moved image * nor the final BSS segment (rtems clears BSS * before saving the command line). - * 2) Initialize and setup the memory controller to prepare the - * SDRAM before moving the image to it. - * 3) Move the entire image (including this very file) to + * 2) Move the entire image (including this very file) to * its final location starting at 0x0000. * It is important to note that _NO_STACK_ is available * during this step. Also, there is probably no return to - * Monitor because relocating RTEMS will destroy vital Monitor + * SMON because relocating RTEMS will destroy vital SMON * data (such as its stack). * 3) Flush the cache to make sure the relocated image is actually * in memory. @@ -44,10 +40,10 @@ * * * Calling convention: - * R1: Monitor SP + * R1: SMON SP * R3: command line string start * R4: command line string end + 1 - * R5: where Monitor put the image + * R5: where SMON put the image * if R5 is 0, the preloader will use its entry point * as the image starting address. * See NOTE below. @@ -74,10 +70,7 @@ * */ #if 0 -/* TODO: I dont know where the appropriate CPU model is to be defined - * when including this to get PPC_CACHE_ALIGNMENT I get an error... - */ -#include +#include #else #ifndef PPC_CACHE_ALIGNMENT #define PPC_CACHE_ALIGNMENT 32 @@ -90,8 +83,8 @@ /* Note that major modifications may be needed * if DESTINATION_ADDR is not 0 */ -#define KERNELBASE 0x0 -#define INITIAL_STACK 0x78 /* 8-byte aligned */ +#define KERNELBASE 0x0 +#define INITIAL_STACK 0x78 /* 8-byte aligned */ #define CACHE_LINE_SIZE PPC_CACHE_ALIGNMENT /* autodetect doesn't work, see below */ #define ASSUME_RTEMS_INSTALLS_VECTORS /* assume we need not load vectors */ #define DONT_USE_R5_ENTRY /* always dynamically determine the address we're running from */ @@ -108,10 +101,8 @@ preload: /* find out where we are */ bl here here: - /* MOTLoad had MSR_EE turned on. Disable it.*/ - mfmsr r0 - xori r0, r0, MSR_EE - mtmsr r0 + xor r0,r0,r0 + mtmsr r0 /* clear MSR to known state */ mflr r5 addi r5,r5,-(here-preload) lis r27,_edata@h @@ -147,10 +138,9 @@ here: add r16, r5, r27 /* image end + 1 */ cmpw r16, r18 bge ishighenough - mr r16,r18 /* __rtems_end is higher than - * the image end - * (without bss) - */ + mr r16,r18 /* __rtems_end is higher than the image end + * (without bss) + */ ishighenough: cmpw r16, r3 /* destination start > current string start ? */ ble leaveparms /* string already after dst, leave it */ @@ -165,7 +155,7 @@ leaveparms: add r7, r6, r17 /* destination + strlen */ #ifndef CACHE_LINE_SIZE - /* Oh well, Monitor firmware has inhibited the cache, so this + /* Oh well, SMON has inhibited the cache, so this * nice routine doesn't work... */ /* figure out the cache line size */ @@ -187,7 +177,7 @@ leaveparms: li r16,CACHE_LINE_SIZE #endif - lis r3,preload@h + lis r3,preload@h ori r3,r3,preload@l mr r4,r5 /* from-addr */ li r5,_preload_size/* this is never > 16k */ @@ -218,19 +208,19 @@ return_here: /* OK, now everything should be in place. * we are ready to start... */ - /* R6: start of command line */ - /* R7: end of command line +1 */ - + /* setup initial stack for rtems early boot */ - lis r1, INITIAL_STACK + li r1,INITIAL_STACK /* disable the MMU and fire up rtems */ mfmsr r0 - ori r0,r0,MSR_IR|MSR_DR|MSR_IP + ori r0,r0,MSR_IR|MSR_DR|MSR_IP|MSR_ME xori r0,r0,MSR_IR|MSR_DR mtsrr1 r0 lis r0,__rtems_entry_point@h ori r0,r0,__rtems_entry_point@l mtsrr0 r0 + /* R6: start of command line */ + /* R7: end of command line +1 */ rfi /* domove(to, from, nbytes): @@ -238,7 +228,7 @@ return_here: * move a R5 bytes from R4 to R3 and flush * the caches for the destination memory * region. R16 provides the cache line size. - * DESTROYS: R0, R17, R18, CTR, CR + * DESTROYS: R0, R17, R18, CTR, CR */ domove: addi r0,r5,3 /* convert to word count */ @@ -258,18 +248,18 @@ domove: beq 3f /* nothing to do */ #endif #if defined(CACHE_LINE_SIZE) && CACHE_LINE_SIZE > 0 - add r17,r3,r5 /* target end pointer */ + add r17,r3,r5 /* target end pointer */ subi r0,r16,1 - add r17,r17,r0 + add r17,r17,r0 andc r17,r17,r0 /* cache aligned target end pointer */ - mr r18,r3 + mr r18,r3 2: cmpw r18,r17 dcbst 0,r18 /* write out data cache line */ icbi 0,r18 /* invalidate corresponding i-cache line */ - add r18,r18,r16 - blt 2b - sync /* make sure data is written back */ - isync /* invalidate possibly preloaded instructions */ + add r18,r18,r16 + blt 2b + sync /* make sure data is written back */ + isync /* invalidate possibly preloaded instructions */ #endif 3: blr diff --git a/c/src/lib/libbsp/powerpc/mvme5500/startup/bspclean.c b/c/src/lib/libbsp/powerpc/mvme5500/startup/bspclean.c index 04e3c0ea0f..1100ddfcd1 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/startup/bspclean.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/startup/bspclean.c @@ -7,10 +7,12 @@ void bsp_cleanup(void) { #if AUTO_BOOT + /* Till Straumann for SVGM */ void rtemsReboot(); rtemsReboot(); #else + /* Kate Feng for the MVME5500 */ printk("\nPrinting a stack trace for your convenience :-)\n"); CPU_print_stack(); printk("RTEMS terminated; Boot manually or turn on AUTO_BOOT.\n"); diff --git a/c/src/lib/libbsp/powerpc/mvme5500/startup/bspstart.c b/c/src/lib/libbsp/powerpc/mvme5500/startup/bspstart.c index c7b8b68b3b..c9d8375359 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/startup/bspstart.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/startup/bspstart.c @@ -14,14 +14,13 @@ * Modified to support the MCP750. * Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr * - * Modified to support the Synergy VGM & Motorola PowerPC boards. - * Many thanks to Till Straumann for providing assistance to port the - * BSP_pgtbl_xxx(). - * (C) by Till Straumann, , 2002, 2004 - * - * Modified to support the MVME5500 board - * (C) by S. Kate Feng , 2003, 2004 + * Modified to support the Synergy VGM & Motorola PowerPC boards + * (C) by Till Straumann, , 2002, 2004, 2005 * + * Modified to support the MVME5500 board. + * Also, the settings of L1, L2, and L3 caches is not necessary here. + * (C) by Brookhaven National Lab., S. Kate Feng , 2003, 2004, 2005 + * * $Id$ */ @@ -62,19 +61,11 @@ /* there is no public Workspace_Free() variant :-( */ #include -uint32_t -_bsp_sbrk_init(uint32_t heap_start, uint32_t *heap_size_p); - -/* provide access to the command line parameters */ -char *BSP_commandline_string = 0; - BSP_output_char_function_type BSP_output_char = BSP_output_char_via_serial; extern void _return_to_ppcbug(); extern unsigned long __rtems_end[]; -extern void L1_caches_enables(); extern unsigned get_L1CR(), get_L2CR(), get_L3CR(); -extern unsigned set_L2CR(unsigned); extern void bsp_cleanup(void); extern Triv121PgTbl BSP_pgtbl_setup(); extern void BSP_pgtbl_activate(); @@ -112,6 +103,11 @@ unsigned int BSP_mem_size; /* * PCI Bus Frequency */ +/* + * Start of the heap + */ +unsigned int BSP_heap_start; + unsigned int BSP_bus_frequency; /* * processor clock frequency @@ -123,23 +119,17 @@ unsigned int BSP_processor_frequency; unsigned int BSP_time_base_divisor; unsigned char ConfVPD_buff[200]; +#define CMDLINE_BUF_SIZE 2048 + +static char cmdline_buf[CMDLINE_BUF_SIZE]; +char *BSP_commandline_string = cmdline_buf; + /* * system init stack and soft ir stack size */ #define INIT_STACK_SIZE 0x1000 #define INTR_STACK_SIZE CONFIGURE_INTERRUPT_STACK_MEMORY -/* calculate the heap start */ -static unsigned long -heapStart(void) -{ -unsigned long rval; - rval = ((uint32_t) __rtems_end) +INIT_STACK_SIZE + INTR_STACK_SIZE; - if (rval & (CPU_ALIGNMENT-1)) - rval = (rval + CPU_ALIGNMENT) & ~(CPU_ALIGNMENT-1); - return rval; -} - void BSP_panic(char *s) { printk("%s PANIC %s\n",_RTEMS_version, s); @@ -173,40 +163,7 @@ extern void bsp_postdriver_hook(void); /* see c/src/lib/libbsp/shared/bsppost.c extern void bsp_libc_init( void *, uint32_t, int ); -/* - * Function: bsp_pretasking_hook - * Created: 95/03/10 - * - * Description: - * BSP pretasking hook. Called just before drivers are initialized. - * Used to setup libc and install any BSP extensions. - * - * NOTES: - * Must not use libc (to do io) from here, since drivers are - * not yet initialized. - * - */ - -void bsp_pretasking_hook(void) -{ - uint32_t heap_start=heapStart(); - uint32_t heap_size,heap_sbrk_spared; - extern uint32_t _bsp_sbrk_init(uint32_t, uint32_t*); - - heap_size = (BSP_mem_size - heap_start) - BSP_Configuration.work_space_size; - - heap_sbrk_spared=_bsp_sbrk_init(heap_start, &heap_size); - -#ifdef SHOW_MORE_INIT_SETTINGS - printk(" HEAP start %x size %x (%x bytes spared for sbrk)\n", heap_start, heap_size, heap_sbrk_spared); -#endif - - bsp_libc_init((void *) 0, heap_size, heap_sbrk_spared); - -#ifdef RTEMS_DEBUG - rtems_debug_enable( RTEMS_DEBUG_ALL_MASK ); -#endif -} +extern void bsp_pretasking_hook(void); void zero_bss() { @@ -257,65 +214,12 @@ void save_boot_params(void *r3, void *r4, void* r5, char *cmdline_start, char *cmdline_end) { int i=cmdline_end-cmdline_start; -CmdLine future_heap=(CmdLine)heapStart(); - - /* get the string out of the stack area into the future heap region; - * assume there's enough memory... - */ - memmove(future_heap->buf,cmdline_start,i); - /* make sure there's an end of string marker */ - future_heap->buf[i++]=0; - future_heap->size=i; -} - - -/* Configure and enable the L3CR */ -void config_enable_L3CR(unsigned l3cr) -{ - unsigned x; - - /* By The Book (numbered steps from section 3.7.3.1 of MPC7450UM) */ - /* - * 1: Set all L3CR bits for final config except L3E, L3I, L3PE, and - * L3CLKEN. (also mask off reserved bits in case they were included - * in L3CR_CONFIG) - */ - l3cr &= ~(L3CR_L3E|L3CR_L3I|L3CR_LOCK_745x|L3CR_L3PE|L3CR_L3CLKEN|L3CR_RESERVED); - mtspr(L3CR, l3cr); - - /* 2: Set L3CR[5] (otherwise reserved bit) to 1 */ - l3cr |= 0x04000000; - mtspr(L3CR, l3cr); - - /* 3: Set L3CLKEN to 1*/ - l3cr |= L3CR_L3CLKEN; - mtspr(L3CR, l3cr); - - /* 4/5: Perform a global cache invalidate (ref section 3.7.3.6) */ - __asm __volatile("dssall;sync"); - /* L3 cache is already disabled, no need to clear L3E */ - mtspr(L3CR, l3cr|L3CR_L3I); - - do { - x = mfspr(L3CR); - } while (x & L3CR_L3I); - - /* 6: Clear L3CLKEN to 0 */ - l3cr &= ~L3CR_L3CLKEN; - mtspr(L3CR, l3cr); - - /* 7: Perform a 'sync' and wait at least 100 CPU cycles */ - __asm __volatile("sync"); - rtems_bsp_delay_in_bus_cycles(100); - - /* 8: Set L3E and L3CLKEN */ - l3cr |= (L3CR_L3E|L3CR_L3CLKEN); - mtspr(L3CR, l3cr); - - /* 9: Perform a 'sync' and wait at least 100 CPU cycles */ - __asm __volatile("sync"); - - rtems_bsp_delay_in_bus_cycles(100); + if ( i >= CMDLINE_BUF_SIZE ) + i = CMDLINE_BUF_SIZE-1; + else if ( i < 0 ) + i = 0; + memmove(cmdline_buf, cmdline_start, i); + cmdline_buf[i]=0; } /* @@ -346,6 +250,24 @@ void bsp_start( void ) ppc_cpu_id_t myCpu; ppc_cpu_revision_t myCpuRevision; Triv121PgTbl pt=0; + + /* Till Straumann: 4/2005 + * Need to map the system registers early, so we can printk... + * (otherwise we silently die) + */ + /* + * Kate Feng : PCI 0 domain memory space, want to leave room for the VME window + */ + setdbat(2, PCI0_MEM_BASE, PCI0_MEM_BASE, 0x10000000, IO_PAGE); + + /* Till Straumann: 2004 + * map the PCI 0, 1 Domain I/O space, GT64260B registers + * and the reserved area so that the size is the power of 2. + * + */ + setdbat(3,PCI0_IO_BASE, PCI0_IO_BASE, 0x2000000, IO_PAGE); + + /* * Get CPU identification dynamically. Note that the get_ppc_cpu_type() function * store the result in global variables so that it can be used latter... @@ -353,15 +275,6 @@ void bsp_start( void ) myCpu = get_ppc_cpu_type(); myCpuRevision = get_ppc_cpu_revision(); - /* - * enables L1 Cache. Note that the L1_caches_enables() codes checks for - * relevant CPU type so that the reason why there is no use of myCpu... - * - * MOTLoad default is good. Otherwise, one would have to disable L2, L3 - * first before settting L1. Then L1->L2->L3. - * - L1_caches_enables();*/ - #ifdef SHOW_LCR1_REGISTER l1cr = get_L1CR(); printk("Initial L1CR value = %x\n", l1cr); @@ -390,8 +303,8 @@ void bsp_start( void ) * This could be done latter (e.g in IRQ_INIT) but it helps to understand * some settings below... */ - intrStack = ((uint32_t) __rtems_end) + - INIT_STACK_SIZE + INTR_STACK_SIZE - PPC_MINIMUM_STACK_FRAME_SIZE; + BSP_heap_start = ((uint32_t) __rtems_end) + INIT_STACK_SIZE + INTR_STACK_SIZE; + intrStack = BSP_heap_start - PPC_MINIMUM_STACK_FRAME_SIZE; /* make sure it's properly aligned */ intrStack &= ~(CPU_STACK_ALIGNMENT-1); @@ -414,16 +327,6 @@ void bsp_start( void ) * access * More PCI1 memory mapping to be done after BSP_pgtbl_activate. */ - /* - * PCI 0 domain memory space, want to leave room for the VME window - */ - setdbat(2, PCI0_MEM_BASE, PCI0_MEM_BASE, 0x10000000, IO_PAGE); - - /* map the PCI 0, 1 Domain I/O space, GT64260B registers - * and the reserved area so that the size is the power of 2. - */ - setdbat(3,PCI0_IO_BASE, PCI0_IO_BASE, 0x2000000, IO_PAGE); - printk("-----------------------------------------\n"); printk("Welcome to %s on MVME5500-0163\n", _RTEMS_version ); printk("-----------------------------------------\n"); @@ -485,7 +388,7 @@ void bsp_start( void ) /* P94 : 7455 TB/DECR is clocked by the system bus clock frequency */ Cpu_table.clicks_per_usec = BSP_bus_frequency/(BSP_time_base_divisor * 1000); Cpu_table.exceptions_in_RAM = TRUE; - _CPU_Table = Cpu_table;/* for rtems_bsp_delay() */ + _CPU_Table = Cpu_table;/* S. Kate Feng , for rtems_bsp_delay() */ printk("BSP_Configuration.work_space_size = %x\n", BSP_Configuration.work_space_size); work_space_start = @@ -503,50 +406,10 @@ void bsp_start( void ) */ BSP_rtems_irq_mng_init(0); - /* - * Enable L2 Cache. Note that the set_L2CR(L2CR) codes checks for - * relevant CPU type (mpc750)... - * - * It also takes care of flushing the cache under certain conditions: - * current going to (E==enable, I==invalidate) - * E E | I -> __NOT_FLUSHED_, invalidated, stays E - * E I -> flush & disable, invalidate - * E E -> nothing, stays E - * 0 E | I -> not flushed, invalidated, enabled - * 0 | I -> not flushed, invalidated, stays off - * 0 E -> not flushed, _NO_INVALIDATE, enabled - * - * The first and the last combinations are potentially dangerous! - * - * NOTE: we assume the essential cache parameters (speed, size etc.) - * have been set correctly by the firmware! - * - */ #ifdef SHOW_LCR2_REGISTER l2cr = get_L2CR(); printk("Initial L2CR value = %x\n", l2cr); #endif -#if 0 - /* Again, MOTload setup seems to be fine. Otherwise, one would - * have to disable the L3 cahce, then R2 ->R3 - */ - if ( -1 != (int)l2cr ) { - /* -1 would mean that this machine doesn't support L2 */ - - l2cr &= ~( L2CR_LOCK_745x); /* clear 'data only' and 'instruction only' */ - l2cr |= L2CR_L3OH0; /* L3 output hold 0 should be set */ - if ( ! (l2cr & L2CR_L2E) ) { - /* we are going to enable the L2 - hence we - * MUST invalidate it first; however, if - * it was enabled already, we MUST NOT - * invalidate it!! - */ - l2cr |= L2CR_L2E | L2CR_L2I; - l2cr=set_L2CR(l2cr); - } - l2cr=set_L2CR(l2cr); - } -#endif #ifdef SHOW_LCR3_REGISTER /* L3CR needs DEC int. handler installed for bsp_delay()*/ @@ -554,22 +417,6 @@ void bsp_start( void ) printk("Initial L3CR value = %x\n", l3cr); #endif -#if 0 - /* Again, use the MOTLoad default for L3CR again */ - if ( -1 != (int)l3cr ) { - /* -1 would mean that this machine doesn't support L3 */ - /* BSD : %2 , SDRAM late wirte - l3cr |= L3SIZ_2M|L3CLK_20|L3RT_PIPELINE_LATE; */ - /* MOTLOad :0xDF826000-> %5, 4 clocks sample point,3 p-clocks SP */ - l3cr |= L3CR_L3PE| L3SIZ_2M|L3CLK_50|L3CKSP_4|L3PSP_3; - - /* TOCHECK MOTload had L2 cache enabled, try to set nothing first */ - if ( !(l3cr & L3CR_L3E)) { - l3cr |= L3CR_L3E | L3CR_L3I; - config_enable_L3CR(l3cr); - } - } -#endif /* Activate the page table mappings only after * initializing interrupts because the irq_mng_init() @@ -604,19 +451,6 @@ void bsp_start( void ) */ _BSP_clear_hostbridge_errors(0, 1 /*quiet*/); - /* - * Initialize VME bridge - needs working PCI - * and IRQ subsystems... - */ -#ifdef SHOW_MORE_INIT_SETTINGS - printk("Going to initialize VME bridge\n"); -#endif - /* VME initialization is in a separate file so apps which don't use - * VME or want a different configuration may link against a customized - * routine. - */ - BSP_vme_config(); - /* Read Configuration Vital Product Data (VPD) */ if ( I2Cread_eeprom(0xa8, 4,2, &ConfVPD_buff[0], 150)) printk("I2Cread_eeprom() error \n"); diff --git a/c/src/lib/libbsp/powerpc/mvme5500/startup/pgtbl_activate.c b/c/src/lib/libbsp/powerpc/mvme5500/startup/pgtbl_activate.c index 3d9d947a3b..8b14f9923e 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/startup/pgtbl_activate.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/startup/pgtbl_activate.c @@ -9,52 +9,8 @@ * default activation procedure. */ -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann , 4/2002, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ - -/* Kate Feng ported it to MVME5500, 4/2004 +/* Author: Till Straumann, , 4/2002 + * Kate Feng ported it to MVME5500, 4/2004 */ void diff --git a/c/src/lib/libbsp/powerpc/mvme5500/startup/reboot.c b/c/src/lib/libbsp/powerpc/mvme5500/startup/reboot.c index c885a5fcac..d6843a8e4e 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/startup/reboot.c +++ b/c/src/lib/libbsp/powerpc/mvme5500/startup/reboot.c @@ -7,10 +7,10 @@ void rtemsReboot() { - printk("\nPrinting a stack trace for your convenience :-)\n"); + printk("Printing a stack trace for your convenience :-)\n"); CPU_print_stack(); printk("RTEMS terminated; Rebooting ...\n"); - /* Mvme5500 board reset */ + /* Mvme5500 board reset : 2004 S. Kate Feng */ out_8((volatile unsigned char*) (GT64260_DEV1_BASE +2), 0x80); } -- cgit v1.2.3