URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/ecos-2.0/packages/devs/eth/powerpc/fec/v2_0
- from Rev 1254 to Rev 1765
- ↔ Reverse comparison
Rev 1254 → Rev 1765
/cdl/fec_eth_drivers.cdl
0,0 → 1,142
# ==================================================================== |
# |
# fec_eth_drivers.cdl |
# |
# Ethernet drivers - platform dependent support for PowerPC MPC8xx |
# |
# ==================================================================== |
#####ECOSGPLCOPYRIGHTBEGIN#### |
## ------------------------------------------- |
## This file is part of eCos, the Embedded Configurable Operating System. |
## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
## Copyright (C) 2002, 2003 Gary Thomas |
## |
## eCos is free software; you can redistribute it and/or modify it under |
## the terms of the GNU General Public License as published by the Free |
## Software Foundation; either version 2 or (at your option) any later version. |
## |
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
## WARRANTY; without even the implied warranty of MERCHANTABILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## |
## You should have received a copy of the GNU General Public License along |
## with eCos; if not, write to the Free Software Foundation, Inc., |
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
## |
## As a special exception, if other files instantiate templates or use macros |
## or inline functions from this file, or you compile this file and link it |
## with other works to produce a work based on this file, this file does not |
## by itself cause the resulting work to be covered by the GNU General Public |
## License. However the source code for this file must still be made available |
## in accordance with section (3) of the GNU General Public License. |
## |
## This exception does not invalidate any other reasons why a work based on |
## this file might be covered by the GNU General Public License. |
## |
## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
## at http://sources.redhat.com/ecos/ecos-license/ |
## ------------------------------------------- |
#####ECOSGPLCOPYRIGHTEND#### |
# ==================================================================== |
######DESCRIPTIONBEGIN#### |
# |
# Author(s): gthomas |
# Original data: gthomas |
# Contributors: |
# Date: 2001-01-21 |
# |
#####DESCRIPTIONEND#### |
# |
# ==================================================================== |
|
cdl_package CYGPKG_DEVS_ETH_POWERPC_FEC { |
display "MPC8xx FEC ethernet driver" |
|
parent CYGPKG_IO_ETH_DRIVERS |
active_if CYGPKG_IO_ETH_DRIVERS |
active_if CYGPKG_HAL_POWERPC |
active_if CYGPKG_HAL_POWERPC_MPC8xx |
|
implements CYGHWR_NET_DRIVERS |
implements CYGHWR_NET_DRIVER_ETH0 |
implements CYGINT_IO_ETH_MULTICAST |
include_dir . |
include_files ; # none _exported_ whatsoever |
|
description "Fast ethernet driver for PowerPC MPC8xxT boards." |
compile -library=libextras.a if_fec.c |
|
cdl_option CYGNUM_DEVS_ETH_POWERPC_FEC_BD_OFFSET { |
display "Buffer descriptors offset in PRAM" |
flavor data |
default_value 0x2C00 |
description " |
This option specifies the address of the buffer descriptors |
used by the PowerPC FEC/ethernet device." |
} |
|
cdl_option CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE { |
display "Buffer size" |
flavor data |
default_value 1520 |
description " |
This option specifies the size of the internal buffers used |
for the PowerPC FEC/ethernet device." |
} |
|
cdl_option CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM { |
display "Number of output buffers" |
flavor data |
legal_values 2 to 64 |
default_value 16 |
description " |
This option specifies the number of output buffer packets |
to be used for the PowerPC FEC/ethernet device." |
} |
|
cdl_option CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM { |
display "Number of input buffers" |
flavor data |
legal_values 2 to 64 |
default_value 16 |
description " |
This option specifies the number of input buffer packets |
to be used for the PowerPC FEC/ethernet device." |
} |
|
cdl_component CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY { |
display "Reset and reconfigure PHY" |
flavor bool |
default_value { CYG_HAL_STARTUP != "RAM" } |
description " |
This option allows control over the physical transceiver" |
|
cdl_option CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE { |
display "Initial link mode" |
flavor data |
legal_values { "10Mb" "100Mb" "Auto" } |
default_value { "Auto" } |
description " |
This option specifies initial mode for the physical |
link. The PHY will be reset and then set to this mode." |
} |
} |
|
cdl_component CYGPKG_DEVS_ETH_POWERPC_FEC_OPTIONS { |
display "MPC8xx FEC ethernet driver build options" |
flavor none |
no_define |
|
cdl_option CYGPKG_DEVS_ETH_POWERPC_FEC_CFLAGS_ADD { |
display "Additional compiler flags" |
flavor data |
no_define |
default_value { "-D_KERNEL -D__ECOS" } |
description " |
This option modifies the set of compiler flags for |
building the MPC8xx FEC ethernet driver package. These flags are used in addition |
to the set of global flags." |
} |
} |
} |
/ChangeLog
0,0 → 1,188
2003-01-20 Gary Thomas <gary@mlbassoc.com> |
|
* cdl/fec_eth_drivers.cdl: Increase number of allowed buffers. |
|
2002-11-14 Gary Thomas <gthomas@ecoscentric.com> |
|
* cdl/fec_eth_drivers.cdl: Increase default number of buffers (to a |
more reasonable amount). |
|
2002-10-18 Gary Thomas <gthomas@ecoscentric.com> |
|
* src/if_fec.c: Reduce warnings when PHY code is not used. |
|
2002-10-11 Gary Thomas <gthomas@ecoscentric.com> [inspired by] |
2002-10-11 Wolfgang Heppner <hep@iis.fhg.de> |
|
* src/if_fec.c: |
* cdl/fec_eth_drivers.cdl: Make buffer descriptor use configurable. |
Also, fix some issues where cache state wasn't being honored. |
|
2002-10-11 Gary Thomas <gary@mlbassoc.com> |
|
* src/if_fec.c: |
* cdl/fec_eth_drivers.cdl: Add control over PHY - when to reset |
and how to configure the link. |
|
2002-09-19 Gary Thomas <gary@mlbassoc.com> |
|
* src/if_fec.c (fec_eth_init): Check for availability of RedBoot |
FLASH support. |
|
2002-09-03 Gary Thomas <gary@mlbassoc.com> |
|
* src/if_fec.c: Make driver more generic - platform specifics are |
now contained in an include file CYGDAT_DEVS_FEC_ETH_INL. |
|
2002-08-15 Gary Thomas <gthomas@ecoscentric.com> |
|
* src/if_fec.c (fec_eth_send): |
Clean up: remove unused variable _fec_eth_tx_count. |
|
2002-08-08 Gary Thomas <gthomas@ecoscentric.com> |
|
* src/if_fec.c (fec_eth_RxEvent): Cache needs to be invalidated |
to avoid any possible corruption. |
|
2002-06-14 Gary Thomas <gary@chez-thomas.org> |
|
* src/if_fec.c: |
Need to include <pkgconf/io_eth_drivers.h> for proper configuration |
of stand-alone (polled) vs. system (interrupt driven) mode. |
|
2002-05-30 Jonathan Larmour <jlarmour@redhat.com> |
|
* src/if_fec.c: Use CYGINT_IO_ETH_INT_SUPPORT_REQUIRED where |
appropriate. |
|
2002-05-30 Jesper Skov <jskov@redhat.com> |
|
* src/if_fec.c: Initialized a variable and removed an unused |
variable. Also made one volatile. All to remove warnings. |
* src/fec.h: Made more pointers volatile to avoid compiler |
warnings. |
|
2002-04-30 Nick Garnett <nickg@redhat.com> |
|
* src/if_fec.c: Changed order of initialization and made code more |
robust against hangups. Changed initialization of ESA from memcpy |
to 32 bit assignments, since 855 seems fussy about this where 860 |
is not. |
|
2002-04-22 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c (fec_eth_control): Fix compile error (multicast). |
|
2002-04-19 Gary Thomas <gthomas@redhat.com> |
|
* cdl/fec_eth_drivers.cdl: Add [minimal] multicast support. |
|
* src/if_fec.c: Cleaned out debug code. |
|
2002-04-18 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c: Finally working! Problem was that resetting the |
interface is much more involved than simply set/reset the "enable". |
|
2002-04-17 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c: |
* src/fec.h: Add code to poll PHY for link status on startup. |
Still trying to get reliable results in general operation. |
|
2002-04-12 Gary Thomas <gthomas@redhat.com> |
|
* src/fec.h: |
* src/if_fec.c: Lots of tinkering since this driver is somewhat |
unreliable with the generic eCos stack (the RedBoot code seems |
to work oddly enough). |
|
2002-02-19 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c (fec_eth_init): Args were backwards(!) getting |
processor revision. |
|
2001-08-22 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c: |
printf() is no longer a part of RedBoot. Thus all programs |
must use diag_printf() and related functions instead. |
|
2001-06-26 Jonathan Larmour <jlarmour@redhat.com> |
|
* src/if_fec.c (fec_eth_init): Use correct version register. |
|
2001-05-07 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c (fec_eth_init): Use RedBoot/fconfig data for ethernet |
station address (ESA). |
|
2001-05-04 Gary Thomas <gthomas@redhat.com> |
|
* src/fec.h (iEvent_all): |
* src/if_fec.c (fec_eth_init): Enable interrupts. |
|
2001-05-01 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c (fec_eth_init): Force buffers to 32 byte boundary. |
|
2001-02-21 Gary Thomas <gthomas@redhat.com> |
|
* src/if_fec.c: Finally working! Lots of little changes |
to get the setup just right. |
(fec_eth_init): Need to set Tx high water mark high for proper |
operation when code is run from FLASH. Also misc cleanups, removing |
old debug code, etc. |
(fec_eth_recv): |
(fec_eth_TxEvent): |
(fec_eth_RxEvent): |
(fec_eth_send): Need to flush data cache - not snooped? |
|
* src/fec.h: Add new defines for rev D of chip. |
|
* cdl/fec_eth_drivers.cdl: Remove CDL for chip revision, |
now handled automatically by driver. |
|
2001-01-22 Gary Thomas <gthomas@redhat.com> |
|
* src/fec.h: |
* src/if_fec.c: |
* cdl/fec_eth_drivers.cdl: New package/file(s). |
|
//=========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//=========================================================================== |
|
|
|
/src/fec.h
0,0 → 1,189
//========================================================================== |
// |
// fec.h |
// |
// PowerPC MPC8xxT fast ethernet (FEC) |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2001-01-21 |
// Purpose: |
// Description: |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
// PowerPC FEC (MPC8xxT) Fast Ethernet |
|
// Buffer descriptor |
struct fec_bd { |
unsigned short ctrl; |
unsigned short length; |
unsigned char *buffer; |
}; |
|
// control flags differ for Rx and Tx buffers |
#define FEC_BD_Rx_Empty 0x8000 // Buffer is empty [FEC can fill it] |
#define FEC_BD_Rx_Wrap 0x2000 // Last buffer in ring [wrap] |
#define FEC_BD_Rx_Last 0x0800 // Last buffer in frame |
#define FEC_BD_Rx_Miss 0x0100 // |
#define FEC_BD_Rx_BC 0x0080 |
#define FEC_BD_Rx_MC 0x0040 |
#define FEC_BD_Rx_LG 0x0020 |
#define FEC_BD_Rx_NO 0x0010 |
#define FEC_BD_Rx_SH 0x0008 // Short frame |
#define FEC_BD_Rx_CR 0x0004 // CRC error |
#define FEC_BD_Rx_OV 0x0002 // Overrun |
#define FEC_BD_Rx_TR 0x0001 // Frame truncated |
|
#define FEC_BD_Tx_Ready 0x8000 // Frame ready |
#define FEC_BD_Tx_Wrap 0x2000 // Last buffer in ring |
#define FEC_BD_Tx_Intr 0x1000 // Generate interrupt |
#define FEC_BD_Tx_Last 0x0800 // Last buffer in frame |
#define FEC_BD_Tx_TC 0x0400 // Send CRC after data |
#define FEC_BD_Tx_DEF 0x0200 |
#define FEC_BD_Tx_HB 0x0100 |
#define FEC_BD_Tx_LC 0x0080 |
#define FEC_BD_Tx_RL 0x0040 |
#define FEC_BD_Tx_RC 0x003C |
#define FEC_BD_Tx_UN 0x0002 // Underrun |
#define FEC_BD_Tx_CSL 0x0001 // Carrier sense lost |
|
#define FEC_BD_Tx_STATS 0x03FF // Status mask |
|
struct fec_eth_info { |
volatile struct fec *fec; |
volatile struct fec_bd *txbd, *rxbd; // Next Tx,Rx descriptor to use |
volatile struct fec_bd *tbase, *rbase; // First Tx,Rx descriptor |
volatile struct fec_bd *tnext, *rnext; // Next descriptor to check for interrupt |
int txsize, rxsize; // Length of individual buffers |
int txactive; // Count of active Tx buffers |
unsigned long txkey[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM]; |
}; |
|
// Fast Ethernet Controller [in PPC8xxT parameter RAM space] |
|
struct fec { |
unsigned long addr[2]; // ESA |
unsigned long hash[2]; // Address hash mask |
volatile struct fec_bd *RxRing; |
volatile struct fec_bd *TxRing; |
unsigned long RxBufSize; |
unsigned char _fill0[0x40-0x1C]; |
unsigned long eControl; // Master control register |
unsigned long iEvent; // Interrupt event |
unsigned long iMask; // Interrupt mask |
unsigned long iVector; // Interrupt vector |
unsigned long RxUpdate; // RxRing updated |
unsigned long TxUpdate; // TxRing updated |
unsigned char _fill1[0x80-0x58]; |
unsigned long MiiData; |
unsigned long MiiSpeed; |
unsigned char _fill2[0xCC-0x88]; |
unsigned long RxBound; // End of FIFO RAM |
unsigned long RxStart; // Start of FIFO RAM |
unsigned char _fill3[0xE4-0xD4]; |
unsigned long TxWater; // Transmit watermark |
unsigned char _fill4[0xEC-0xE8]; |
unsigned long TxStart; // Start of Tx FIFO |
unsigned char _fill5[0x134-0xF0]; |
unsigned long FunCode; // DMA function codes |
unsigned char _fill6[0x144-0x138]; |
unsigned long RxControl; // Receiver control |
unsigned long RxHash; // Receive hash |
unsigned char _fill7[0x184-0x14C]; |
unsigned long TxControl; // Transmitter control |
}; |
|
#define FEC_OFFSET 0x0E00 // Offset in 8xx parameter RAM |
|
// Master control register (eControl) |
#define eControl_MUX 0x0004 // Select proper pin MUX functions |
#define eControl_EN 0x0002 // Enable ethernet controller |
#define eControl_RESET 0x0001 // Reset controller |
|
// Receiver control register (RxControl) |
#define RxControl_BC_REJ 0x0010 // Reject broadcast frames |
#define RxControl_PROM 0x0008 // Promiscuous mode |
#define RxControl_MII 0x0004 // MII (1) or 7 wire (0) mode |
#define RxControl_DRT 0x0002 // Disable receive on transmit |
#define RxControl_LOOP 0x0001 // Internal loopback |
|
// Interrupt events |
#define iEvent_HBERR 0x80000000 // No heartbeat error |
#define iEvent_BABR 0x40000000 // Babling receiver |
#define iEvent_BABT 0x20000000 // Babling transmitter |
#define iEvent_GRA 0x10000000 // Graceful shutdown |
#define iEvent_TFINT 0x08000000 // Transmit frame interrupt |
#define iEvent_TXB 0x04000000 // Transmit buffer |
#define iEvent_RFINT 0x02000000 // Receive frame |
#define iEvent_RXB 0x01000000 // Receive buffer |
#define iEvent_MII 0x00800000 // MII complete |
#define iEvent_EBERR 0x00400000 // Ethernet BUS error |
#define iEvent_all 0xFFC00000 // Any interrupt |
|
// MII interface |
#define MII_Start 0x40000000 |
#define MII_Read 0x20000000 |
#define MII_Write 0x10000000 |
#define MII_Phy(phy) (phy << 23) |
#define MII_Reg(reg) (reg << 18) |
#define MII_TA 0x00020000 |
|
// Transceiver mode |
#define PHY_BMCR 0x00 // Register number |
#define PHY_BMCR_RESET 0x8000 |
#define PHY_BMCR_LOOPBACK 0x4000 |
#define PHY_BMCR_100MB 0x2000 |
#define PHY_BMCR_AUTO_NEG 0x1000 |
#define PHY_BMCR_POWER_DOWN 0x0800 |
#define PHY_BMCR_ISOLATE 0x0400 |
#define PHY_BMCR_RESTART 0x0200 |
#define PHY_BMCR_FULL_DUPLEX 0x0100 |
#define PHY_BMCR_COLL_TEST 0x0080 |
|
#define PHY_BMSR 0x01 // Status register |
#define PHY_BMSR_AUTO_NEG 0x0020 |
#define PHY_BMSR_LINK 0x0004 |
|
#define IEEE_8023_MAX_FRAME 1518 // Largest possible ethernet frame |
#define IEEE_8023_MIN_FRAME 60 // Smallest possible ethernet frame |
|
/src/if_fec.c
0,0 → 1,830
//========================================================================== |
// |
// dev/if_fec.c |
// |
// Fast ethernet device driver for PowerPC MPC8xxT boards |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// Copyright (C) 2002 Gary Thomas |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas |
// Date: 2001-01-21 |
// Purpose: |
// Description: hardware driver for MPC8xxT FEC |
// |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
// Ethernet device driver for MPC8xx FEC |
|
#include <pkgconf/system.h> |
#include <pkgconf/devs_eth_powerpc_fec.h> |
#include <pkgconf/io_eth_drivers.h> |
#include CYGDAT_DEVS_FEC_ETH_INL |
|
#ifdef CYGPKG_NET |
#include <pkgconf/net.h> |
#endif |
|
#include <cyg/infra/cyg_type.h> |
#include <cyg/infra/diag.h> |
|
#include <cyg/hal/hal_arch.h> |
#include <cyg/hal/hal_cache.h> |
#include <cyg/hal/hal_intr.h> |
#include <cyg/hal/drv_api.h> |
#include <cyg/hal/hal_if.h> |
#include <cyg/hal/ppc_regs.h> |
|
#include <cyg/io/eth/netdev.h> |
#include <cyg/io/eth/eth_drv.h> |
|
#include "fec.h" |
|
// Define this to force the buffer descriptors into the EPPC memory |
#define FEC_USE_EPPC_BD |
|
#ifndef FEC_USE_EPPC_BD |
static struct fec_bd fec_eth_rxring[CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM]; |
static struct fec_bd fec_eth_txring[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM]; |
#endif |
static unsigned char fec_eth_rxbufs[CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM+1] |
[CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE]; |
static unsigned char fec_eth_txbufs[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM+1] |
[CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE]; |
|
static struct fec_eth_info fec_eth0_info; |
static unsigned char _default_enaddr[] = { 0x08, 0x00, 0x3E, 0x28, 0x7A, 0xBA}; |
static unsigned char enaddr[6]; |
#ifdef CYGPKG_REDBOOT |
#include <pkgconf/redboot.h> |
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG |
#include <redboot.h> |
#include <flash_config.h> |
RedBoot_config_option("Network hardware address [MAC]", |
fec_esa, |
ALWAYS_ENABLED, true, |
CONFIG_ESA, 0 |
); |
#endif |
#endif |
|
#define os_printf diag_printf |
|
// For fetching the ESA from RedBoot |
#include <cyg/hal/hal_if.h> |
#ifndef CONFIG_ESA |
#define CONFIG_ESA 6 |
#endif |
|
ETH_DRV_SC(fec_eth0_sc, |
&fec_eth0_info, // Driver specific data |
"eth0", // Name for this interface |
fec_eth_start, |
fec_eth_stop, |
fec_eth_control, |
fec_eth_can_send, |
fec_eth_send, |
fec_eth_recv, |
fec_eth_deliver, |
fec_eth_int, |
fec_eth_int_vector); |
|
NETDEVTAB_ENTRY(fec_netdev, |
"fec_eth", |
fec_eth_init, |
&fec_eth0_sc); |
|
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED |
#define _FEC_USE_INTS |
#ifdef _FEC_USE_INTS |
static cyg_interrupt fec_eth_interrupt; |
static cyg_handle_t fec_eth_interrupt_handle; |
#else |
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM |
static char fec_fake_int_stack[STACK_SIZE]; |
static cyg_thread fec_fake_int_thread_data; |
static cyg_handle_t fec_fake_int_thread_handle; |
static void fec_fake_int(cyg_addrword_t); |
#endif // _FEC_USE_INTS |
#endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED |
static void fec_eth_int(struct eth_drv_sc *data); |
|
#ifndef FEC_ETH_INT |
#error FEC_ETH_INT must be defined |
#endif |
|
#ifndef FEC_ETH_PHY |
#error FEC_ETH_PHY must be defined |
#endif |
|
#ifndef FEC_ETH_RESET_PHY |
#define FEC_ETH_RESET_PHY() |
#endif |
|
#ifndef FEC_EPPC_BD_OFFSET |
#define FEC_EPPC_BD_OFFSET CYGNUM_DEVS_ETH_POWERPC_FEC_BD_OFFSET |
#endif |
|
// LED activity [exclusive of hardware bits] |
#ifndef _get_led |
#define _get_led() |
#define _set_led(v) |
#endif |
#ifndef LED_TxACTIVE |
#define LED_TxACTIVE 7 |
#define LED_RxACTIVE 6 |
#define LED_IntACTIVE 5 |
#endif |
|
static void |
set_led(int bit) |
{ |
_set_led(_get_led() | (1<<bit)); |
} |
|
static void |
clear_led(int bit) |
{ |
_set_led(_get_led() & ~(1<<bit)); |
} |
|
#ifdef _FEC_USE_INTS |
// This ISR is called when the ethernet interrupt occurs |
static int |
fec_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs) |
{ |
cyg_drv_interrupt_mask(FEC_ETH_INT); |
return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR |
} |
#endif |
|
// Deliver function (ex-DSR) handles the ethernet [logical] processing |
static void |
fec_eth_deliver(struct eth_drv_sc * sc) |
{ |
fec_eth_int(sc); |
#ifdef _FEC_USE_INTS |
// Allow interrupts to happen again |
cyg_drv_interrupt_acknowledge(FEC_ETH_INT); |
cyg_drv_interrupt_unmask(FEC_ETH_INT); |
#endif |
} |
|
#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY |
// |
// PHY unit access (via MII channel) |
// |
static void |
phy_write(int reg, int addr, unsigned short data) |
{ |
volatile EPPC *eppc = (volatile EPPC *)eppc_base(); |
volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET); |
int timeout = 0x100000; |
|
fec->iEvent = iEvent_MII; |
fec->MiiData = MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data; |
while (!(fec->iEvent & iEvent_MII) && (--timeout > 0)) ; |
} |
|
static bool |
phy_read(int reg, int addr, unsigned short *val) |
{ |
volatile EPPC *eppc = (volatile EPPC *)eppc_base(); |
volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET); |
int timeout = 0x100000; |
|
fec->iEvent = iEvent_MII; |
fec->MiiData = MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA; |
while (!(fec->iEvent & iEvent_MII)) { |
if (--timeout <= 0) { |
return false; |
} |
} |
*val = fec->MiiData & 0x0000FFFF; |
return true; |
} |
#endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY |
|
// |
// [re]Initialize the ethernet controller |
// Done separately since shutting down the device requires a |
// full reconfiguration when re-enabling. |
// when |
static bool |
fec_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
volatile EPPC *eppc = (volatile EPPC *)eppc_base(); |
volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET); |
volatile struct fec_bd *rxbd, *txbd; |
unsigned char *RxBUF, *TxBUF; |
int cache_state, int_state; |
int i; |
|
// Ignore unless device is idle/stopped |
if ((qi->fec->eControl & eControl_EN) != 0) { |
return true; |
} |
|
// Make sure interrupts are off while we mess with the device |
HAL_DISABLE_INTERRUPTS(int_state); |
|
// Ensure consistent state between cache and what the FEC sees |
HAL_DCACHE_IS_ENABLED(cache_state); |
if (cache_state) |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
|
// Shut down ethernet controller, in case it is already running |
fec->eControl = eControl_RESET; |
i = 0; |
while ((fec->eControl & eControl_RESET) != 0) { |
if (++i >= 500000) { |
os_printf("FEC Ethernet does not reset\n"); |
if (cache_state) |
HAL_DCACHE_ENABLE(); |
HAL_RESTORE_INTERRUPTS(int_state); |
return false; |
} |
} |
|
fec->iMask = 0x0000000; // Disables all interrupts |
fec->iEvent = 0xFFFFFFFF; // Clear all interrupts |
fec->iVector = (1<<29); // Caution - must match FEC_ETH_INT above |
|
#define ROUNDUP(b,s) (((unsigned long)(b) + (s-1)) & ~(s-1)) |
#ifdef FEC_USE_EPPC_BD |
txbd = (struct fec_bd *)(FEC_EPPC_BD_OFFSET + (cyg_uint32)eppc); |
rxbd = &txbd[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM]; |
#else |
txbd = fec_eth_txring; |
rxbd = fec_eth_rxring; |
#endif |
qi->tbase = qi->txbd = qi->tnext = txbd; |
qi->rbase = qi->rxbd = qi->rnext = rxbd; |
qi->txactive = 0; |
|
RxBUF = (unsigned char *)ROUNDUP(&fec_eth_rxbufs[0][0], 32); |
TxBUF = (unsigned char *)ROUNDUP(&fec_eth_txbufs[0][0], 32); |
|
// setup buffer descriptors |
for (i = 0; i < CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM; i++) { |
rxbd->length = 0; |
rxbd->buffer = RxBUF; |
rxbd->ctrl = FEC_BD_Rx_Empty; |
RxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE; |
rxbd++; |
} |
rxbd--; |
rxbd->ctrl |= FEC_BD_Rx_Wrap; // Last buffer |
for (i = 0; i < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM; i++) { |
txbd->length = 0; |
txbd->buffer = TxBUF; |
txbd->ctrl = 0; |
TxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE; |
txbd++; |
} |
txbd--; |
txbd->ctrl |= FEC_BD_Tx_Wrap; // Last buffer |
|
// Reset interrupts |
fec->iMask = 0x00000000; // No interrupts enabled |
fec->iEvent = 0xFFFFFFFF; // Clear all interrupts |
|
// Initialize shared PRAM |
fec->RxRing = qi->rbase; |
fec->TxRing = qi->tbase; |
|
// Size of receive buffers |
fec->RxBufSize = CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE; |
|
// Receiver control |
fec->RxControl = RxControl_MII | RxControl_DRT; |
// fec->RxControl = RxControl_MII | RxControl_LOOP | RxControl_PROM; |
fec->RxHash = IEEE_8023_MAX_FRAME; // Largest possible ethernet frame |
|
// Transmit control |
fec->TxControl = 4+0; |
|
// Use largest possible Tx FIFO |
fec->TxWater = 3; |
|
// DMA control |
fec->FunCode = ((2<<29) | (2<<27) | (0<<24)); |
|
// MII speed control (50MHz) |
fec->MiiSpeed = 0x14; |
|
// Group address hash |
fec->hash[0] = 0; |
fec->hash[1] = 0; |
|
// Device physical address |
fec->addr[0] = *(unsigned long *)&enaddr[0]; |
fec->addr[1] = *(unsigned long *)&enaddr[4]; |
// os_printf("FEC ESA = %08x/%08x\n", fec->addr[0], fec->addr[1]); |
|
// Enable device |
fec->eControl = eControl_EN | eControl_MUX; |
fec->RxUpdate = 0x0F0F0F0F; // Any write tells machine to look for work |
|
#ifdef _FEC_USE_INTS |
// Set up for interrupts |
fec->iMask = iEvent_TFINT | iEvent_TXB | |
iEvent_RFINT | iEvent_RXB; |
fec->iEvent = 0xFFFFFFFF; // Clear all interrupts |
#endif |
|
if (cache_state) |
HAL_DCACHE_ENABLE(); |
|
// Set LED state |
clear_led(LED_TxACTIVE); |
clear_led(LED_RxACTIVE); |
|
HAL_RESTORE_INTERRUPTS(int_state); |
return true; |
} |
|
// |
// Initialize the interface - performed at system startup |
// This function must set up the interface, including arranging to |
// handle interrupts, etc, so that it may be "started" cheaply later. |
// |
static bool |
fec_eth_init(struct cyg_netdevtab_entry *tab) |
{ |
struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance; |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
volatile EPPC *eppc = (volatile EPPC *)eppc_base(); |
volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET); |
int cache_state; |
unsigned long proc_rev; |
bool esa_ok; |
#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY |
int phy_timeout = 5*1000; // Wait 5 seconds max for link to clear |
bool phy_ok; |
unsigned short phy_state = 0; |
#endif |
|
// Ensure consistent state between cache and what the FEC sees |
HAL_DCACHE_IS_ENABLED(cache_state); |
if (cache_state) |
HAL_DCACHE_SYNC(); |
HAL_DCACHE_DISABLE(); |
|
qi->fec = fec; |
fec_eth_stop(sc); // Make sure it's not running yet |
|
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED |
#ifdef _FEC_USE_INTS |
// Set up to handle interrupts |
cyg_drv_interrupt_create(FEC_ETH_INT, |
CYGARC_SIU_PRIORITY_HIGH, |
(cyg_addrword_t)sc, // Data item passed to interrupt handler |
(cyg_ISR_t *)fec_eth_isr, |
(cyg_DSR_t *)eth_drv_dsr, |
&fec_eth_interrupt_handle, |
&fec_eth_interrupt); |
cyg_drv_interrupt_attach(fec_eth_interrupt_handle); |
cyg_drv_interrupt_acknowledge(FEC_ETH_INT); |
cyg_drv_interrupt_unmask(FEC_ETH_INT); |
#else // _FEC_USE_INTS |
// Hack - use a thread to simulate interrupts |
cyg_thread_create(1, // Priority |
fec_fake_int, // entry |
(cyg_addrword_t)sc, // entry parameter |
"CS8900 int", // Name |
&fec_fake_int_stack[0], // Stack |
STACK_SIZE, // Size |
&fec_fake_int_thread_handle, // Handle |
&fec_fake_int_thread_data // Thread data structure |
); |
cyg_thread_resume(fec_fake_int_thread_handle); // Start it |
#endif |
#endif |
|
// Set up parallel port for connection to ethernet tranceiver |
eppc->pio_pdpar = 0x1FFF; |
CYGARC_MFSPR( CYGARC_REG_PVR, proc_rev ); |
#define PROC_REVB 0x0020 |
if ((proc_rev & 0x0000FFFF) == PROC_REVB) { |
eppc->pio_pddir = 0x1C58; |
} else { |
eppc->pio_pddir = 0x1FFF; |
} |
|
// Get physical device address |
#ifdef CYGPKG_REDBOOT |
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG |
esa_ok = flash_get_config("fec_esa", enaddr, CONFIG_ESA); |
#else |
esa_ok = false; |
#endif |
#else |
esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, |
"fec_esa", enaddr, CONFIG_ESA); |
#endif |
if (!esa_ok) { |
// Can't figure out ESA |
os_printf("FEC_ETH - Warning! ESA unknown\n"); |
memcpy(&enaddr, &_default_enaddr, sizeof(enaddr)); |
} |
|
// Configure the device |
if (!fec_eth_reset(sc, enaddr, 0)) { |
return false; |
} |
|
fec->iEvent = 0xFFFFFFFF; // Clear all interrupts |
|
#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY |
// Reset PHY (transceiver) |
FEC_ETH_RESET_PHY(); |
|
phy_ok = 0; |
if (phy_read(PHY_BMSR, FEC_ETH_PHY, &phy_state)) { |
if ((phy_state & PHY_BMSR_LINK) != PHY_BMSR_LINK) { |
unsigned short reset_mode; |
int i; |
phy_write(PHY_BMCR, FEC_ETH_PHY, PHY_BMCR_RESET); |
for (i = 0; i < 10; i++) { |
phy_ok = phy_read(PHY_BMCR, FEC_ETH_PHY, &phy_state); |
if (!phy_ok) break; |
if (!(phy_state & PHY_BMCR_RESET)) break; |
} |
if (!phy_ok || (phy_state & PHY_BMCR_RESET)) { |
os_printf("FEC: Can't get PHY unit to soft reset: %x\n", phy_state); |
return false; |
} |
|
fec->iEvent = 0xFFFFFFFF; // Clear all interrupts |
reset_mode = PHY_BMCR_RESTART; |
#ifdef CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE_Auto |
reset_mode |= PHY_BMCR_AUTO_NEG; |
#endif |
#ifdef CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE_100Mb |
reset_mode |= PHY_BMCR_100MB; |
#endif |
phy_write(PHY_BMCR, FEC_ETH_PHY, reset_mode); |
while (phy_timeout-- >= 0) { |
int ev = fec->iEvent; |
unsigned short state; |
fec->iEvent = ev; |
if (ev & iEvent_MII) { |
phy_ok = phy_read(PHY_BMSR, FEC_ETH_PHY, &state); |
if (phy_ok && (state & PHY_BMSR_LINK)) { |
break; |
} else { |
CYGACC_CALL_IF_DELAY_US(10000); // 10ms |
} |
} |
} |
if (phy_timeout <= 0) { |
os_printf("** FEC Warning: PHY LINK UP failed\n"); |
} |
} |
else { |
os_printf("** FEC Info: PHY LINK already UP \n"); |
} |
} |
#endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY |
|
// Initialize upper level driver |
(sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr); |
|
if (cache_state) |
HAL_DCACHE_ENABLE(); |
|
return true; |
} |
|
// |
// This function is called to shut down the interface. |
// |
static void |
fec_eth_stop(struct eth_drv_sc *sc) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
|
// Disable the device! |
qi->fec->eControl &= ~eControl_EN; |
} |
|
// |
// This function is called to "start up" the interface. It may be called |
// multiple times, even when the hardware is already running. It will be |
// called whenever something "hardware oriented" changes and should leave |
// the hardware ready to send/receive packets. |
// |
static void |
fec_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) |
{ |
// Enable the device! |
fec_eth_reset(sc, enaddr, flags); |
} |
|
// |
// This function is called for low level "control" operations |
// |
static int |
fec_eth_control(struct eth_drv_sc *sc, unsigned long key, |
void *data, int length) |
{ |
#ifdef ETH_DRV_SET_MC_ALL |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
volatile struct fec *fec = qi->fec; |
#endif |
|
switch (key) { |
case ETH_DRV_SET_MAC_ADDRESS: |
return 0; |
break; |
#ifdef ETH_DRV_SET_MC_ALL |
case ETH_DRV_SET_MC_ALL: |
case ETH_DRV_SET_MC_LIST: |
fec->RxControl &= ~RxControl_PROM; |
fec->hash[0] = 0xFFFFFFFF; |
fec->hash[1] = 0xFFFFFFFF; |
return 0; |
break; |
#endif |
default: |
return 1; |
break; |
} |
} |
|
// |
// This function is called to see if another packet can be sent. |
// It should return the number of packets which can be handled. |
// Zero should be returned if the interface is busy and can not send any more. |
// |
static int |
fec_eth_can_send(struct eth_drv_sc *sc) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
|
return (qi->txactive < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM); |
} |
|
// |
// This routine is called to send data to the hardware. |
|
static void |
fec_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, |
int total_len, unsigned long key) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
volatile struct fec_bd *txbd, *txfirst; |
volatile char *bp; |
int i, txindex, cache_state; |
|
// Find a free buffer |
txbd = txfirst = qi->txbd; |
while (txbd->ctrl & FEC_BD_Tx_Ready) { |
// This buffer is busy, move to next one |
if (txbd->ctrl & FEC_BD_Tx_Wrap) { |
txbd = qi->tbase; |
} else { |
txbd++; |
} |
if (txbd == txfirst) { |
#ifdef CYGPKG_NET |
panic ("No free xmit buffers"); |
#else |
os_printf("FEC Ethernet: No free xmit buffers\n"); |
#endif |
} |
} |
// Set up buffer |
bp = txbd->buffer; |
for (i = 0; i < sg_len; i++) { |
memcpy((void *)bp, (void *)sg_list[i].buf, sg_list[i].len); |
bp += sg_list[i].len; |
} |
txbd->length = total_len; |
txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd); |
qi->txkey[txindex] = key; |
// Note: the MPC860 does not seem to snoop/invalidate the data cache properly! |
HAL_DCACHE_IS_ENABLED(cache_state); |
if (cache_state) { |
HAL_DCACHE_FLUSH(txbd->buffer, txbd->length); // Make sure no stale data |
} |
// Send it on it's way |
txbd->ctrl |= FEC_BD_Tx_Ready | FEC_BD_Tx_Last | FEC_BD_Tx_TC; |
#ifndef FEC_USE_EPPC_BD |
if (cache_state) { |
HAL_DCACHE_FLUSH(fec_eth_txring, sizeof(fec_eth_txring)); // Make sure no stale data |
} |
#endif |
qi->txactive++; |
qi->fec->TxUpdate = 0x01000000; // Any write tells machine to look for work |
set_led(LED_TxACTIVE); |
// Remember the next buffer to try |
if (txbd->ctrl & FEC_BD_Tx_Wrap) { |
qi->txbd = qi->tbase; |
} else { |
qi->txbd = txbd+1; |
} |
} |
|
// |
// This function is called when a packet has been received. It's job is |
// to prepare to unload the packet from the hardware. Once the length of |
// the packet is known, the upper layer of the driver can be told. When |
// the upper layer is ready to unload the packet, the internal function |
// 'fec_eth_recv' will be called to actually fetch it from the hardware. |
// |
static void |
fec_eth_RxEvent(struct eth_drv_sc *sc) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
volatile struct fec_bd *rxbd, *rxfirst; |
int cache_state; |
|
// Note: the MPC860 does not seem to snoop/invalidate the data cache properly! |
HAL_DCACHE_IS_ENABLED(cache_state); |
#ifndef FEC_USE_EPPC_BD |
if (cache_state) { |
HAL_DCACHE_INVALIDATE(fec_eth_rxring, sizeof(fec_eth_rxring)); // Make sure no stale data |
} |
#endif |
rxbd = rxfirst = qi->rnext; |
while (true) { |
if ((rxbd->ctrl & FEC_BD_Rx_Empty) == 0) { |
qi->rxbd = rxbd; // Save for callback |
set_led(LED_RxACTIVE); |
(sc->funs->eth_drv->recv)(sc, rxbd->length); |
} |
if (rxbd->ctrl & FEC_BD_Rx_Wrap) { |
rxbd = qi->rbase; |
} else { |
rxbd++; |
} |
if (rxbd == rxfirst) { |
break; |
} |
} |
// Remember where we left off |
qi->rnext = (struct fec_bd *)rxbd; |
#ifndef FEC_USE_EPPC_BD |
if (cache_state) { |
HAL_DCACHE_INVALIDATE(fec_eth_rxring, sizeof(fec_eth_rxring)); // Make sure no stale data |
} |
#endif |
qi->fec->RxUpdate = 0x0F0F0F0F; // Any write tells machine to look for work |
} |
|
// |
// This function is called as a result of the "eth_drv_recv()" call above. |
// It's job is to actually fetch data for a packet from the hardware once |
// memory buffers have been allocated for the packet. Note that the buffers |
// may come in pieces, using a scatter-gather list. This allows for more |
// efficient processing in the upper layers of the stack. |
// |
static void |
fec_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
unsigned char *bp; |
int i, cache_state; |
|
bp = (unsigned char *)qi->rxbd->buffer; |
// Note: the MPC860 does not seem to snoop/invalidate the data cache properly! |
HAL_DCACHE_IS_ENABLED(cache_state); |
if (cache_state) { |
HAL_DCACHE_INVALIDATE(qi->rxbd->buffer, qi->rxbd->length); // Make sure no stale data |
} |
for (i = 0; i < sg_len; i++) { |
if (sg_list[i].buf != 0) { |
memcpy((void *)sg_list[i].buf, bp, sg_list[i].len); |
bp += sg_list[i].len; |
} |
} |
qi->rxbd->ctrl |= FEC_BD_Rx_Empty; |
clear_led(LED_RxACTIVE); |
} |
|
static void |
fec_eth_TxEvent(struct eth_drv_sc *sc) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
volatile struct fec_bd *txbd; |
int key, txindex, cache_state; |
|
HAL_DCACHE_IS_ENABLED(cache_state); |
#ifndef FEC_USE_EPPC_BD |
if (cache_state) { |
HAL_DCACHE_FLUSH(fec_eth_txring, sizeof(fec_eth_txring)); // Make sure no stale data |
} |
#endif |
txbd = qi->tnext; |
// Note: TC field is used to indicate the buffer has/had data in it |
while ((txbd->ctrl & (FEC_BD_Tx_Ready|FEC_BD_Tx_TC)) == FEC_BD_Tx_TC) { |
txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd); |
if ((key = qi->txkey[txindex]) != 0) { |
qi->txkey[txindex] = 0; |
(sc->funs->eth_drv->tx_done)(sc, key, 0); |
} |
if (--qi->txactive == 0) { |
clear_led(LED_TxACTIVE); |
} |
txbd->ctrl &= ~FEC_BD_Tx_TC; |
if (txbd->ctrl & FEC_BD_Tx_Wrap) { |
txbd = qi->tbase; |
} else { |
txbd++; |
} |
} |
// Remember where we left off |
qi->tnext = (struct fec_bd *)txbd; |
#ifndef FEC_USE_EPPC_BD |
if (cache_state) { |
HAL_DCACHE_FLUSH(fec_eth_txring, sizeof(fec_eth_txring)); // Make sure no stale data |
} |
#endif |
} |
|
// |
// Interrupt processing |
// |
static void |
fec_eth_int(struct eth_drv_sc *sc) |
{ |
struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; |
unsigned long event; |
|
while ((event = qi->fec->iEvent) != 0) { |
if ((event & iEvent_TFINT) != 0) { |
fec_eth_TxEvent(sc); |
} |
if ((event & iEvent_RFINT) != 0) { |
fec_eth_RxEvent(sc); |
} |
qi->fec->iEvent = event; // Reset the bits we handled |
} |
} |
|
// |
// Interrupt vector |
// |
static int |
fec_eth_int_vector(struct eth_drv_sc *sc) |
{ |
return (FEC_ETH_INT); |
} |
|
#if defined(CYGINT_IO_ETH_INT_SUPPORT_REQUIRED) && ~defined(_FEC_USE_INTS) |
void |
fec_fake_int(cyg_addrword_t param) |
{ |
struct eth_drv_sc *sc = (struct eth_drv_sc *) param; |
int int_state; |
|
while (true) { |
cyg_thread_delay(1); // 10ms |
HAL_DISABLE_INTERRUPTS(int_state); |
fec_eth_int(sc); |
HAL_RESTORE_INTERRUPTS(int_state); |
} |
} |
#endif |