Mercurial > ecos
diff packages/devs/eth/powerpc/fec/current/src/if_fec.c @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | f62680ef1804 |
| children | d2c90368aeef |
line wrap: on
line diff
--- a/packages/devs/eth/powerpc/fec/current/src/if_fec.c +++ b/packages/devs/eth/powerpc/fec/current/src/if_fec.c @@ -5,29 +5,38 @@ // Fast ethernet device driver for PowerPC MPC8xxT boards // //========================================================================== -//####COPYRIGHTBEGIN#### -// -// ------------------------------------------- -// The contents of this file are subject to the Red Hat eCos Public License -// Version 1.1 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://www.redhat.com/ -// -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -// License for the specific language governing rights and limitations under -// the License. -// -// The Original Code is eCos - Embedded Configurable Operating System, -// released September 30, 1998. -// -// The Initial Developer of the Original Code is Red Hat. -// Portions created by Red Hat are -// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. -// All Rights Reserved. -// ------------------------------------------- -// -//####COPYRIGHTEND#### +//####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#### // @@ -61,17 +70,22 @@ #include <cyg/hal/hal_if.h> #include <cyg/hal/ppc_regs.h> -#include <netdev.h> -#include <eth_drv.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 struct fec_bd fec_eth_rxring[CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM]; static unsigned char fec_eth_txbufs[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM+1] [CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE]; -static struct fec_bd fec_eth_txring[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM]; static struct fec_eth_info fec_eth0_info; static unsigned char _default_enaddr[] = { 0x08, 0x00, 0x3E, 0x28, 0x7A, 0xBA}; @@ -116,14 +130,49 @@ NETDEVTAB_ENTRY(fec_netdev, &fec_eth0_sc); #ifdef CYGPKG_NET +#define _FEC_USE_INTS +#ifdef _FEC_USE_INTS static cyg_interrupt fec_eth_interrupt; static cyg_handle_t fec_eth_interrupt_handle; -#endif +#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 // CYGPKG_NET static void fec_eth_int(struct eth_drv_sc *data); #define FEC_ETH_INT CYGNUM_HAL_INTERRUPT_SIU_LVL1 -#ifdef CYGPKG_NET +#ifdef CYGPKG_HAL_POWERPC_VIPER +extern int hal_viper_get_led(void); +extern void hal_viper_set_led(int); +#define _get_led() hal_viper_get_led() +#define _set_led(v) hal_viper_set_led(v) +#else +#define _get_led() +#define _set_led(v) +#endif + +#define LED_TxACTIVE 7 +#define LED_RxACTIVE 6 +#define LED_IntACTIVE 5 + +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) @@ -138,7 +187,7 @@ static void fec_eth_deliver(struct eth_drv_sc * sc) { fec_eth_int(sc); -#ifdef CYGPKG_NET +#ifdef _FEC_USE_INTS // Allow interrupts to happen again cyg_drv_interrupt_acknowledge(FEC_ETH_INT); cyg_drv_interrupt_unmask(FEC_ETH_INT); @@ -153,85 +202,89 @@ phy_write(int reg, int addr, unsigned sh { 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)) ; + while (!(fec->iEvent & iEvent_MII) && (--timeout > 0)) ; } -static unsigned short -phy_read(int reg, int addr) +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)) ; - return fec->MiiData & 0x0000FFFF; + while (!(fec->iEvent & iEvent_MII)) { + if (--timeout <= 0) { + return false; + } + } + *val = fec->MiiData & 0x0000FFFF; + 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) +// [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 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); struct fec_bd *rxbd, *txbd; unsigned char *RxBUF, *TxBUF; - unsigned short phy_state = 0; - int cache_state; + int cache_state, int_state; int i; - unsigned long proc_rev; - bool esa_ok; + + // 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); HAL_DCACHE_SYNC(); HAL_DCACHE_DISABLE(); - qi->fec = fec; - -#ifdef CYGPKG_NET - // 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); -#endif - - // Shut down ethernet, in case it is already running + // Shut down ethernet controller, in case it is already running fec->eControl = eControl_RESET; - eppc->pip_pbdat &= ~0x00004000; // Reset PHY chip - CYGACC_CALL_IF_DELAY_US(1000); // 1ms - eppc->pip_pbdat |= 0x00004000; // Enable PHY chip + 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 *)(0x2C00 + (cyg_uint32)eppc); + rxbd = &txbd[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM]; +#else txbd = fec_eth_txring; rxbd = fec_eth_rxring; - qi->tbase = txbd; - qi->txbd = txbd; - qi->tnext = txbd; - qi->rbase = rxbd; - qi->rxbd = rxbd; - qi->rnext = rxbd; +#endif + qi->tbase = qi->txbd = qi->tnext = txbd; + qi->rbase = qi->rxbd = qi->rnext = rxbd; + qi->txactive = 0; -#define ROUNDUP(b,s) (((unsigned long)(b) + (s-1)) & ~(s-1)) RxBUF = (unsigned char *)ROUNDUP(&fec_eth_rxbufs[0][0], 32); TxBUF = (unsigned char *)ROUNDUP(&fec_eth_txbufs[0][0], 32); @@ -255,23 +308,13 @@ fec_eth_init(struct cyg_netdevtab_entry txbd--; txbd->ctrl |= FEC_BD_Tx_Wrap; // Last buffer - // Set up parallel port for connection to ethernet tranceiver - eppc->pio_pdpar = 0x1FFF; - CYGARC_MFSPR( proc_rev, CYGARC_REG_PVR ); -#define PROC_REVB 0x0020 - if ((proc_rev & 0x0000FFFF) == PROC_REVB) { - eppc->pio_pddir = 0x1C58; - } else { - eppc->pio_pddir = 0x1FFF; - } - // Reset interrupts fec->iMask = 0x00000000; // No interrupts enabled fec->iEvent = 0xFFFFFFFF; // Clear all interrupts // Initialize shared PRAM - fec->RxRing = fec_eth_rxring; - fec->TxRing = fec_eth_txring; + fec->RxRing = qi->rbase; + fec->TxRing = qi->tbase; // Size of receive buffers fec->RxBufSize = CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE; @@ -282,7 +325,7 @@ fec_eth_init(struct cyg_netdevtab_entry fec->RxHash = IEEE_8023_MAX_FRAME; // Largest possible ethernet frame // Transmit control - fec->TxControl = 0; + fec->TxControl = 4+0; // Use largest possible Tx FIFO fec->TxWater = 3; @@ -298,6 +341,98 @@ fec_eth_init(struct cyg_netdevtab_entry 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); + unsigned short phy_state = 0; + int cache_state; + int i; + unsigned long proc_rev; + bool esa_ok, phy_ok; + int phy_timeout = 5*1000; // Wait 5 seconds max for link to clear + + // Ensure consistent state between cache and what the FEC sees + HAL_DCACHE_IS_ENABLED(cache_state); + HAL_DCACHE_SYNC(); + HAL_DCACHE_DISABLE(); + + qi->fec = fec; + fec_eth_stop(sc); // Make sure it's not running yet + +#ifdef CYGPKG_NET +#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 esa_ok = flash_get_config("fec_esa", enaddr, CONFIG_ESA); #else @@ -309,36 +444,50 @@ fec_eth_init(struct cyg_netdevtab_entry os_printf("FEC_ETH - Warning! ESA unknown\n"); memcpy(&enaddr, &_default_enaddr, sizeof(enaddr)); } - memcpy((void *)&fec->addr[0], &enaddr[0], sizeof(enaddr)); - // os_printf("FEC ESA = %08x/%08x\n", fec->addr[0], fec->addr[1]); - // Enable device - fec->eControl = eControl_EN | eControl_MUX; + // Configure the device + if (!fec_eth_reset(sc, enaddr, 0)) { + return false; + } + // Reset PHY (transceiver) + eppc->pip_pbdat &= ~0x00004000; // Reset PHY chip + CYGACC_CALL_IF_DELAY_US(10000); // 10ms + eppc->pip_pbdat |= 0x00004000; // Enable PHY chip // Enable transceiver (PHY) phy_write(PHY_BMCR, 0, PHY_BMCR_RESET); for (i = 0; i < 10; i++) { - phy_state = phy_read(PHY_BMCR, 0); + phy_ok = phy_read(PHY_BMCR, 0, &phy_state); + if (!phy_ok) break; if (!(phy_state & PHY_BMCR_RESET)) break; } - if (phy_state & PHY_BMCR_RESET) { + if (!phy_ok || (phy_state & PHY_BMCR_RESET)) { os_printf("FEC: Can't get PHY unit to reset: %x\n", phy_state); return false; } - phy_write(PHY_BMCR, 0, PHY_BMCR_AUTO_NEG); - // os_printf("MII: %x/%x\n", phy_state, phy_read(PHY_BMCR, 0)); - -#ifdef CYGPKG_NET - // Set up for interrupts - fec->iMask = iEvent_all & ~iEvent_MII; -#endif - - if (cache_state) - HAL_DCACHE_ENABLE(); + fec->iEvent = 0xFFFFFFFF; // Clear all interrupts + phy_write(PHY_BMCR, 0, PHY_BMCR_AUTO_NEG|PHY_BMCR_RESTART); + while (phy_timeout-- >= 0) { + int ev = fec->iEvent; + unsigned short state; + fec->iEvent = ev; + if (ev & iEvent_MII) { + phy_ok = phy_read(PHY_BMSR, 0, &state); + if (phy_ok && (state & PHY_BMSR_AUTO_NEG)) { +// os_printf("State: %x\n", state); + break; + } else { + CYGACC_CALL_IF_DELAY_US(1000); // 1ms + } + } + } + if (phy_timeout <= 0) { + os_printf("** FEC Warning: PHY auto-negotiation failed\n"); + } // Initialize upper level driver (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr); - + return true; } @@ -363,11 +512,8 @@ fec_eth_stop(struct eth_drv_sc *sc) static void fec_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) { - struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; - // Enable the device! - qi->fec->eControl |= eControl_EN; - qi->fec->RxUpdate = 0x0F0F0F0F; // Any write tells machine to look for work + fec_eth_reset(sc, enaddr, flags); } // @@ -377,10 +523,25 @@ static int fec_eth_control(struct eth_drv_sc *sc, unsigned long key, void *data, int length) { +#ifdef ETH_DRV_SET_MC_ALL + struct eth_drv_mc_list *mc_list; + 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; @@ -396,13 +557,13 @@ static int fec_eth_can_send(struct eth_drv_sc *sc) { struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; - volatile struct fec_bd *txbd = qi->txbd; - return ((txbd->ctrl & FEC_BD_Tx_Ready) == 0); + return (qi->txactive < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM); } // // This routine is called to send data to the hardware. +int _fec_eth_tx_count = 0; 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) @@ -429,32 +590,37 @@ fec_eth_send(struct eth_drv_sc *sc, stru #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 + _fec_eth_tx_count++; + 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; } - txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd); - qi->txkey[txindex] = key; - // Set up buffer - txbd->length = total_len; - 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; - } - // Note: the MBX860 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; - if (cache_state) { - HAL_DCACHE_FLUSH(fec_eth_txring, sizeof(fec_eth_txring)); // Make sure no stale data - } - qi->fec->TxUpdate = 0x0F0F0F0F; // Any write tells machine to look for work } // @@ -468,30 +634,39 @@ 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; + volatile struct fec_bd *rxbd, *rxfirst; int cache_state; - // Note: the MBX860 does not seem to snoop/invalidate the data cache properly! + // 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_FLUSH(fec_eth_rxring, sizeof(fec_eth_rxring)); // Make sure no stale data } - rxbd = qi->rnext; - while ((rxbd->ctrl & FEC_BD_Rx_Empty) == 0) { - qi->rxbd = rxbd; // Save for callback - (sc->funs->eth_drv->recv)(sc, rxbd->length); - rxbd->ctrl |= FEC_BD_Rx_Empty; +#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_FLUSH(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 } @@ -510,7 +685,7 @@ fec_eth_recv(struct eth_drv_sc *sc, stru int i, cache_state; bp = (unsigned char *)qi->rxbd->buffer; - // Note: the MBX860 does not seem to snoop/invalidate the data cache properly! + // 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 @@ -521,24 +696,34 @@ fec_eth_recv(struct eth_drv_sc *sc, stru 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, int stat) +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 txindex, cache_state; + 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); - (sc->funs->eth_drv->tx_done)(sc, qi->txkey[txindex], 0); + 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; @@ -548,9 +733,11 @@ fec_eth_TxEvent(struct eth_drv_sc *sc, i } // 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 } // @@ -564,7 +751,7 @@ fec_eth_int(struct eth_drv_sc *sc) while ((event = qi->fec->iEvent) != 0) { if ((event & iEvent_TFINT) != 0) { - fec_eth_TxEvent(sc, event); + fec_eth_TxEvent(sc); } if ((event & iEvent_RFINT) != 0) { fec_eth_RxEvent(sc); @@ -582,3 +769,18 @@ fec_eth_int_vector(struct eth_drv_sc *sc return (FEC_ETH_INT); } +#if defined(CYGPKG_NET) && ~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
