1 //==========================================================================
5 // Fast ethernet device driver for PowerPC MPC8xxT boards
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: gthomas
48 // Description: hardware driver for MPC8xxT FEC
51 //####DESCRIPTIONEND####
53 //==========================================================================
55 // Ethernet device driver for MPC8xx FEC
57 #include <pkgconf/system.h>
58 #include <pkgconf/devs_eth_powerpc_fec.h>
59 #include <pkgconf/io_eth_drivers.h>
60 #include CYGDAT_DEVS_FEC_ETH_INL
63 #include <pkgconf/net.h>
66 #include <cyg/infra/cyg_type.h>
67 #include <cyg/infra/diag.h>
69 #include <cyg/hal/hal_arch.h>
70 #include <cyg/hal/hal_cache.h>
71 #include <cyg/hal/hal_intr.h>
72 #include <cyg/hal/drv_api.h>
73 #include <cyg/hal/hal_if.h>
74 #include <cyg/hal/ppc_regs.h>
76 #include <cyg/io/eth/netdev.h>
77 #include <cyg/io/eth/eth_drv.h>
81 // Align buffers on a cache boundary
82 #define RxBUFSIZE CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM*CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE
83 #define TxBUFSIZE CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM*CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE
84 static unsigned char fec_eth_rxbufs[RxBUFSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
85 static unsigned char fec_eth_txbufs[TxBUFSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
87 static struct fec_eth_info fec_eth0_info;
88 static unsigned char _default_enaddr[] = { 0x08, 0x00, 0x3E, 0x28, 0x7A, 0xBA};
89 static unsigned char enaddr[6];
91 #include <pkgconf/redboot.h>
92 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
94 #include <flash_config.h>
95 RedBoot_config_option("Network hardware address [MAC]",
103 #define os_printf diag_printf
105 // For fetching the ESA from RedBoot
106 #include <cyg/hal/hal_if.h>
111 ETH_DRV_SC(fec_eth0_sc,
112 &fec_eth0_info, // Driver specific data
113 "eth0", // Name for this interface
124 NETDEVTAB_ENTRY(fec_netdev,
129 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
130 #define _FEC_USE_INTS
132 static cyg_interrupt fec_eth_interrupt;
133 static cyg_handle_t fec_eth_interrupt_handle;
135 #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
136 static char fec_fake_int_stack[STACK_SIZE];
137 static cyg_thread fec_fake_int_thread_data;
138 static cyg_handle_t fec_fake_int_thread_handle;
139 static void fec_fake_int(cyg_addrword_t);
140 #endif // _FEC_USE_INTS
141 #endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
142 static void fec_eth_int(struct eth_drv_sc *data);
145 #error FEC_ETH_INT must be defined
149 #error FEC_ETH_PHY must be defined
152 #ifndef FEC_ETH_RESET_PHY
153 #define FEC_ETH_RESET_PHY()
156 #ifndef FEC_EPPC_BD_OFFSET
157 #define FEC_EPPC_BD_OFFSET CYGNUM_DEVS_ETH_POWERPC_FEC_BD_OFFSET
160 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_STATUS_LEDS
161 // LED activity [exclusive of hardware bits]
167 #define LED_TxACTIVE 7
168 #define LED_RxACTIVE 6
169 #define LED_IntACTIVE 5
175 _set_led(_get_led() | (1<<bit));
181 _set_led(_get_led() & ~(1<<bit));
189 // This ISR is called when the ethernet interrupt occurs
191 fec_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
193 cyg_drv_interrupt_mask(FEC_ETH_INT);
194 return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR
198 // Deliver function (ex-DSR) handles the ethernet [logical] processing
200 fec_eth_deliver(struct eth_drv_sc * sc)
204 // Allow interrupts to happen again
205 cyg_drv_interrupt_acknowledge(FEC_ETH_INT);
206 cyg_drv_interrupt_unmask(FEC_ETH_INT);
210 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
212 // PHY unit access (via MII channel)
215 phy_write(int reg, int addr, unsigned short data)
217 volatile EPPC *eppc = (volatile EPPC *)eppc_base();
218 volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
219 int timeout = 0x100000;
221 fec->iEvent = iEvent_MII;
222 fec->MiiData = MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data;
223 while (!(fec->iEvent & iEvent_MII) && (--timeout > 0)) ;
227 phy_read(int reg, int addr, unsigned short *val)
229 volatile EPPC *eppc = (volatile EPPC *)eppc_base();
230 volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
231 int timeout = 0x100000;
233 fec->iEvent = iEvent_MII;
234 fec->MiiData = MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA;
235 while (!(fec->iEvent & iEvent_MII)) {
236 if (--timeout <= 0) {
240 *val = fec->MiiData & 0x0000FFFF;
243 #endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
246 // [re]Initialize the ethernet controller
247 // Done separately since shutting down the device requires a
248 // full reconfiguration when re-enabling.
251 fec_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
253 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
254 volatile EPPC *eppc = (volatile EPPC *)eppc_base();
255 volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
256 volatile struct fec_bd *rxbd, *txbd;
257 unsigned char *RxBUF, *TxBUF;
258 int cache_state, int_state;
262 // Ignore unless device is idle/stopped
263 if ((qi->fec->eControl & eControl_EN) != 0) {
267 // Make sure interrupts are off while we mess with the device
268 HAL_DISABLE_INTERRUPTS(int_state);
270 // Ensure consistent state between cache and what the FEC sees
271 HAL_DCACHE_IS_ENABLED(cache_state);
274 HAL_DCACHE_DISABLE();
277 // Shut down ethernet controller, in case it is already running
278 fec->eControl = eControl_RESET;
280 while ((fec->eControl & eControl_RESET) != 0) {
282 os_printf("FEC Ethernet does not reset\n");
285 HAL_RESTORE_INTERRUPTS(int_state);
290 fec->iMask = 0x0000000; // Disables all interrupts
291 fec->iEvent = 0xFFFFFFFF; // Clear all interrupts
292 fec->iVector = (1<<29); // Caution - must match FEC_ETH_INT above
294 TxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM * sizeof(struct cp_bufdesc));
295 RxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM * sizeof(struct cp_bufdesc));
296 txbd = (struct fec_bd *)(TxBD + (cyg_uint32)eppc);
297 rxbd = (struct fec_bd *)(RxBD + (cyg_uint32)eppc);
298 qi->tbase = qi->txbd = qi->tnext = txbd;
299 qi->rbase = qi->rxbd = qi->rnext = rxbd;
302 RxBUF = &fec_eth_rxbufs[0];
303 TxBUF = &fec_eth_txbufs[0];
305 // setup buffer descriptors
306 for (i = 0; i < CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM; i++) {
308 rxbd->buffer = RxBUF;
309 rxbd->ctrl = FEC_BD_Rx_Empty;
310 RxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
314 rxbd->ctrl |= FEC_BD_Rx_Wrap; // Last buffer
315 for (i = 0; i < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM; i++) {
317 txbd->buffer = TxBUF;
319 TxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
323 txbd->ctrl |= FEC_BD_Tx_Wrap; // Last buffer
326 fec->iMask = 0x00000000; // No interrupts enabled
327 fec->iEvent = 0xFFFFFFFF; // Clear all interrupts
329 // Initialize shared PRAM
330 fec->RxRing = qi->rbase;
331 fec->TxRing = qi->tbase;
333 // Size of receive buffers
334 fec->RxBufSize = CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
337 fec->RxControl = RxControl_MII | RxControl_DRT;
338 // fec->RxControl = RxControl_MII | RxControl_LOOP | RxControl_PROM;
339 fec->RxHash = IEEE_8023_MAX_FRAME; // Largest possible ethernet frame
342 fec->TxControl = 4+0;
344 // Use largest possible Tx FIFO
348 fec->FunCode = ((2<<29) | (2<<27) | (0<<24));
350 // MII speed control (50MHz)
351 fec->MiiSpeed = 0x14;
353 // Group address hash
357 // Device physical address
358 fec->addr[0] = *(unsigned long *)&enaddr[0];
359 fec->addr[1] = *(unsigned long *)&enaddr[4];
360 // os_printf("FEC ESA = %08x/%08x\n", fec->addr[0], fec->addr[1]);
363 fec->eControl = eControl_EN | eControl_MUX;
364 fec->RxUpdate = 0x0F0F0F0F; // Any write tells machine to look for work
367 // Set up for interrupts
368 fec->iMask = iEvent_TFINT | iEvent_TXB |
369 iEvent_RFINT | iEvent_RXB;
370 fec->iEvent = 0xFFFFFFFF; // Clear all interrupts
377 clear_led(LED_TxACTIVE);
378 clear_led(LED_RxACTIVE);
380 HAL_RESTORE_INTERRUPTS(int_state);
385 // Initialize the interface - performed at system startup
386 // This function must set up the interface, including arranging to
387 // handle interrupts, etc, so that it may be "started" cheaply later.
390 fec_eth_init(struct cyg_netdevtab_entry *tab)
392 struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
393 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
394 volatile EPPC *eppc = (volatile EPPC *)eppc_base();
395 volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
397 unsigned long proc_rev;
399 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
400 int phy_timeout = 5*1000; // Wait 5 seconds max for link to clear
402 unsigned short phy_state = 0;
405 // Ensure consistent state between cache and what the FEC sees
406 HAL_DCACHE_IS_ENABLED(cache_state);
409 HAL_DCACHE_DISABLE();
413 fec_eth_stop(sc); // Make sure it's not running yet
415 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
417 // Set up to handle interrupts
418 cyg_drv_interrupt_create(FEC_ETH_INT,
419 CYGARC_SIU_PRIORITY_HIGH,
420 (cyg_addrword_t)sc, // Data item passed to interrupt handler
421 (cyg_ISR_t *)fec_eth_isr,
422 (cyg_DSR_t *)eth_drv_dsr,
423 &fec_eth_interrupt_handle,
425 cyg_drv_interrupt_attach(fec_eth_interrupt_handle);
426 cyg_drv_interrupt_acknowledge(FEC_ETH_INT);
427 cyg_drv_interrupt_unmask(FEC_ETH_INT);
428 #else // _FEC_USE_INTS
429 // Hack - use a thread to simulate interrupts
430 cyg_thread_create(1, // Priority
431 fec_fake_int, // entry
432 (cyg_addrword_t)sc, // entry parameter
433 "CS8900 int", // Name
434 &fec_fake_int_stack[0], // Stack
436 &fec_fake_int_thread_handle, // Handle
437 &fec_fake_int_thread_data // Thread data structure
439 cyg_thread_resume(fec_fake_int_thread_handle); // Start it
443 // Set up parallel port for connection to ethernet tranceiver
444 eppc->pio_pdpar = 0x1FFF;
445 CYGARC_MFSPR( CYGARC_REG_PVR, proc_rev );
446 #define PROC_REVB 0x0020
447 if ((proc_rev & 0x0000FFFF) == PROC_REVB) {
448 eppc->pio_pddir = 0x1C58;
450 eppc->pio_pddir = 0x1FFF;
453 // Get physical device address
454 #ifdef CYGPKG_REDBOOT
455 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
456 esa_ok = flash_get_config("fec_esa", enaddr, CONFIG_ESA);
461 esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
462 "fec_esa", enaddr, CONFIG_ESA);
465 // Can't figure out ESA
466 os_printf("FEC_ETH - Warning! ESA unknown\n");
467 memcpy(&enaddr, &_default_enaddr, sizeof(enaddr));
470 // Configure the device
471 if (!fec_eth_reset(sc, enaddr, 0)) {
475 fec->iEvent = 0xFFFFFFFF; // Clear all interrupts
477 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
478 // Reset PHY (transceiver)
482 if (phy_read(PHY_BMSR, FEC_ETH_PHY, &phy_state)) {
483 if ((phy_state & PHY_BMSR_LINK) != PHY_BMSR_LINK) {
484 unsigned short reset_mode;
486 phy_write(PHY_BMCR, FEC_ETH_PHY, PHY_BMCR_RESET);
487 for (i = 0; i < 10; i++) {
488 phy_ok = phy_read(PHY_BMCR, FEC_ETH_PHY, &phy_state);
490 if (!(phy_state & PHY_BMCR_RESET)) break;
492 if (!phy_ok || (phy_state & PHY_BMCR_RESET)) {
493 os_printf("FEC: Can't get PHY unit to soft reset: %x\n", phy_state);
497 fec->iEvent = 0xFFFFFFFF; // Clear all interrupts
498 reset_mode = PHY_BMCR_RESTART;
499 #ifdef CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE_Auto
500 reset_mode |= PHY_BMCR_AUTO_NEG;
502 #ifdef CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE_100Mb
503 reset_mode |= PHY_BMCR_100MB;
505 phy_write(PHY_BMCR, FEC_ETH_PHY, reset_mode);
506 while (phy_timeout-- >= 0) {
507 int ev = fec->iEvent;
508 unsigned short state;
510 if (ev & iEvent_MII) {
511 phy_ok = phy_read(PHY_BMSR, FEC_ETH_PHY, &state);
512 if (phy_ok && (state & PHY_BMSR_LINK)) {
515 CYGACC_CALL_IF_DELAY_US(10000); // 10ms
519 if (phy_timeout <= 0) {
520 os_printf("** FEC Warning: PHY LINK UP failed\n");
524 os_printf("** FEC Info: PHY LINK already UP \n");
527 #endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
529 // Initialize upper level driver
530 (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr);
539 // This function is called to shut down the interface.
542 fec_eth_stop(struct eth_drv_sc *sc)
544 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
546 // Disable the device!
547 qi->fec->eControl &= ~eControl_EN;
551 // This function is called to "start up" the interface. It may be called
552 // multiple times, even when the hardware is already running. It will be
553 // called whenever something "hardware oriented" changes and should leave
554 // the hardware ready to send/receive packets.
557 fec_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
559 // Enable the device!
560 fec_eth_reset(sc, enaddr, flags);
564 // This function is called for low level "control" operations
567 fec_eth_control(struct eth_drv_sc *sc, unsigned long key,
568 void *data, int length)
570 #ifdef ETH_DRV_SET_MC_ALL
571 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
572 volatile struct fec *fec = qi->fec;
576 case ETH_DRV_SET_MAC_ADDRESS:
579 #ifdef ETH_DRV_SET_MC_ALL
580 case ETH_DRV_SET_MC_ALL:
581 case ETH_DRV_SET_MC_LIST:
582 fec->RxControl &= ~RxControl_PROM;
583 fec->hash[0] = 0xFFFFFFFF;
584 fec->hash[1] = 0xFFFFFFFF;
595 // This function is called to see if another packet can be sent.
596 // It should return the number of packets which can be handled.
597 // Zero should be returned if the interface is busy and can not send any more.
600 fec_eth_can_send(struct eth_drv_sc *sc)
602 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
604 return (qi->txactive < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM);
608 // This routine is called to send data to the hardware.
611 fec_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
612 int total_len, unsigned long key)
614 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
615 volatile struct fec_bd *txbd, *txfirst;
617 int i, txindex, cache_state;
619 // Find a free buffer
620 txbd = txfirst = qi->txbd;
621 while (txbd->ctrl & FEC_BD_Tx_Ready) {
622 // This buffer is busy, move to next one
623 if (txbd->ctrl & FEC_BD_Tx_Wrap) {
628 if (txbd == txfirst) {
630 panic ("No free xmit buffers");
632 os_printf("FEC Ethernet: No free xmit buffers\n");
638 for (i = 0; i < sg_len; i++) {
639 memcpy((void *)bp, (void *)sg_list[i].buf, sg_list[i].len);
640 bp += sg_list[i].len;
642 txbd->length = total_len;
643 txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
644 qi->txkey[txindex] = key;
645 // Note: the MPC8xx does not seem to snoop/invalidate the data cache properly!
646 HAL_DCACHE_IS_ENABLED(cache_state);
648 HAL_DCACHE_FLUSH(txbd->buffer, txbd->length); // Make sure no stale data
650 // Send it on it's way
651 txbd->ctrl |= FEC_BD_Tx_Ready | FEC_BD_Tx_Last | FEC_BD_Tx_TC;
653 qi->fec->TxUpdate = 0x01000000; // Any write tells machine to look for work
654 set_led(LED_TxACTIVE);
655 // Remember the next buffer to try
656 if (txbd->ctrl & FEC_BD_Tx_Wrap) {
657 qi->txbd = qi->tbase;
664 // This function is called when a packet has been received. It's job is
665 // to prepare to unload the packet from the hardware. Once the length of
666 // the packet is known, the upper layer of the driver can be told. When
667 // the upper layer is ready to unload the packet, the internal function
668 // 'fec_eth_recv' will be called to actually fetch it from the hardware.
671 fec_eth_RxEvent(struct eth_drv_sc *sc)
673 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
674 volatile struct fec_bd *rxbd, *rxfirst;
676 rxbd = rxfirst = qi->rnext;
678 if ((rxbd->ctrl & FEC_BD_Rx_Empty) == 0) {
679 qi->rxbd = rxbd; // Save for callback
680 set_led(LED_RxACTIVE); // Remove the CRC
681 (sc->funs->eth_drv->recv)(sc, rxbd->length - 4);
683 if (rxbd->ctrl & FEC_BD_Rx_Wrap) {
688 if (rxbd == rxfirst) {
692 // Remember where we left off
693 qi->rnext = (struct fec_bd *)rxbd;
694 qi->fec->RxUpdate = 0x0F0F0F0F; // Any write tells machine to look for work
698 // This function is called as a result of the "eth_drv_recv()" call above.
699 // It's job is to actually fetch data for a packet from the hardware once
700 // memory buffers have been allocated for the packet. Note that the buffers
701 // may come in pieces, using a scatter-gather list. This allows for more
702 // efficient processing in the upper layers of the stack.
705 fec_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
707 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
711 bp = (unsigned char *)qi->rxbd->buffer;
712 // Note: the MPC8xx does not seem to snoop/invalidate the data cache properly!
713 HAL_DCACHE_IS_ENABLED(cache_state);
715 HAL_DCACHE_INVALIDATE(qi->rxbd->buffer, qi->rxbd->length); // Make sure no stale data
717 for (i = 0; i < sg_len; i++) {
718 if (sg_list[i].buf != 0) {
719 memcpy((void *)sg_list[i].buf, bp, sg_list[i].len);
720 bp += sg_list[i].len;
723 qi->rxbd->ctrl |= FEC_BD_Rx_Empty;
724 clear_led(LED_RxACTIVE);
728 fec_eth_TxEvent(struct eth_drv_sc *sc)
730 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
731 volatile struct fec_bd *txbd;
735 // Note: TC field is used to indicate the buffer has/had data in it
736 while ((txbd->ctrl & (FEC_BD_Tx_Ready|FEC_BD_Tx_TC)) == FEC_BD_Tx_TC) {
737 txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
738 if ((key = qi->txkey[txindex]) != 0) {
739 qi->txkey[txindex] = 0;
740 (sc->funs->eth_drv->tx_done)(sc, key, 0);
742 if (--qi->txactive == 0) {
743 clear_led(LED_TxACTIVE);
745 txbd->ctrl &= ~FEC_BD_Tx_TC;
746 if (txbd->ctrl & FEC_BD_Tx_Wrap) {
752 // Remember where we left off
753 qi->tnext = (struct fec_bd *)txbd;
757 // Interrupt processing
760 fec_eth_int(struct eth_drv_sc *sc)
762 struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
765 while ((event = qi->fec->iEvent) != 0) {
766 qi->fec->iEvent = event; // Reset the bits we handled
767 if ((event & iEvent_TFINT) != 0) {
770 if ((event & iEvent_RFINT) != 0) {
780 fec_eth_int_vector(struct eth_drv_sc *sc)
782 return (FEC_ETH_INT);
785 #if defined(CYGINT_IO_ETH_INT_SUPPORT_REQUIRED) && ~defined(_FEC_USE_INTS)
787 fec_fake_int(cyg_addrword_t param)
789 struct eth_drv_sc *sc = (struct eth_drv_sc *) param;
793 cyg_thread_delay(1); // 10ms
794 HAL_DISABLE_INTERRUPTS(int_state);
796 HAL_RESTORE_INTERRUPTS(int_state);