]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/powerpc/fec/v2_0/src/if_fec.c
Initial revision
[karo-tx-redboot.git] / packages / devs / eth / powerpc / fec / v2_0 / src / if_fec.c
1 //==========================================================================
2 //
3 //      dev/if_fec.c
4 //
5 //      Fast ethernet device driver for PowerPC MPC8xxT boards
6 //
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
13 //
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.
17 //
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
21 // for more details.
22 //
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.
26 //
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.
33 //
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.
36 //
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####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2001-01-21
47 // Purpose:      
48 // Description:  hardware driver for MPC8xxT FEC
49 //              
50 //
51 //####DESCRIPTIONEND####
52 //
53 //==========================================================================
54
55 // Ethernet device driver for MPC8xx FEC
56
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
61
62 #ifdef CYGPKG_NET
63 #include <pkgconf/net.h>
64 #endif
65
66 #include <cyg/infra/cyg_type.h>
67 #include <cyg/infra/diag.h>
68
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>
75
76 #include <cyg/io/eth/netdev.h>
77 #include <cyg/io/eth/eth_drv.h>
78
79 #include "fec.h"
80
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)));
86
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];
90 #ifdef CYGPKG_REDBOOT
91 #include <pkgconf/redboot.h>
92 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
93 #include <redboot.h>
94 #include <flash_config.h>
95 RedBoot_config_option("Network hardware address [MAC]",
96                       fec_esa,
97                       ALWAYS_ENABLED, true,
98                       CONFIG_ESA, 0
99     );
100 #endif
101 #endif
102
103 #define os_printf diag_printf
104
105 // For fetching the ESA from RedBoot
106 #include <cyg/hal/hal_if.h>
107 #ifndef CONFIG_ESA
108 #define CONFIG_ESA 6
109 #endif
110
111 ETH_DRV_SC(fec_eth0_sc,
112            &fec_eth0_info,   // Driver specific data
113            "eth0",             // Name for this interface
114            fec_eth_start,
115            fec_eth_stop,
116            fec_eth_control,
117            fec_eth_can_send,
118            fec_eth_send,
119            fec_eth_recv,
120            fec_eth_deliver,
121            fec_eth_int,
122            fec_eth_int_vector);
123
124 NETDEVTAB_ENTRY(fec_netdev, 
125                 "fec_eth", 
126                 fec_eth_init, 
127                 &fec_eth0_sc);
128
129 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
130 #define _FEC_USE_INTS
131 #ifdef _FEC_USE_INTS
132 static cyg_interrupt fec_eth_interrupt;
133 static cyg_handle_t  fec_eth_interrupt_handle;
134 #else
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);
143
144 #ifndef FEC_ETH_INT
145 #error  FEC_ETH_INT must be defined
146 #endif
147
148 #ifndef FEC_ETH_PHY
149 #error  FEC_ETH_PHY must be defined
150 #endif
151
152 #ifndef FEC_ETH_RESET_PHY
153 #define FEC_ETH_RESET_PHY()
154 #endif
155
156 #ifndef FEC_EPPC_BD_OFFSET
157 #define FEC_EPPC_BD_OFFSET CYGNUM_DEVS_ETH_POWERPC_FEC_BD_OFFSET
158 #endif
159
160 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_STATUS_LEDS
161 // LED activity [exclusive of hardware bits]
162 #ifndef _get_led
163 #define _get_led()  
164 #define _set_led(v) 
165 #endif
166 #ifndef LED_TxACTIVE
167 #define LED_TxACTIVE  7
168 #define LED_RxACTIVE  6
169 #define LED_IntACTIVE 5
170 #endif
171
172 static void
173 set_led(int bit)
174 {
175   _set_led(_get_led() | (1<<bit));
176 }
177
178 static void
179 clear_led(int bit)
180 {
181   _set_led(_get_led() & ~(1<<bit));
182 }
183 #else
184 #define set_led(b)
185 #define clear_led(b)
186 #endif
187
188 #ifdef _FEC_USE_INTS
189 // This ISR is called when the ethernet interrupt occurs
190 static int
191 fec_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
192 {
193     cyg_drv_interrupt_mask(FEC_ETH_INT);
194     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
195 }
196 #endif
197
198 // Deliver function (ex-DSR) handles the ethernet [logical] processing
199 static void
200 fec_eth_deliver(struct eth_drv_sc * sc)
201 {
202     fec_eth_int(sc);
203 #ifdef _FEC_USE_INTS
204     // Allow interrupts to happen again
205     cyg_drv_interrupt_acknowledge(FEC_ETH_INT);
206     cyg_drv_interrupt_unmask(FEC_ETH_INT);
207 #endif
208 }
209
210 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
211 //
212 // PHY unit access (via MII channel)
213 //
214 static void
215 phy_write(int reg, int addr, unsigned short data)
216 {
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;
220
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)) ;
224 }
225
226 static bool
227 phy_read(int reg, int addr, unsigned short *val)
228 {
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;
232
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) {
237             return false;
238         }
239     }
240     *val = fec->MiiData & 0x0000FFFF;
241     return true;
242 }
243 #endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
244
245 //
246 // [re]Initialize the ethernet controller
247 //   Done separately since shutting down the device requires a 
248 //   full reconfiguration when re-enabling.
249 //   when 
250 static bool
251 fec_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
252 {
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;
259     int i;
260     int TxBD, RxBD;
261
262     // Ignore unless device is idle/stopped
263     if ((qi->fec->eControl & eControl_EN) != 0) {
264         return true;
265     }
266
267     // Make sure interrupts are off while we mess with the device
268     HAL_DISABLE_INTERRUPTS(int_state);
269
270     // Ensure consistent state between cache and what the FEC sees
271     HAL_DCACHE_IS_ENABLED(cache_state);
272     if (cache_state) {
273       HAL_DCACHE_SYNC();
274       HAL_DCACHE_DISABLE();
275     }
276
277     // Shut down ethernet controller, in case it is already running
278     fec->eControl = eControl_RESET;
279     i = 0;
280     while ((fec->eControl & eControl_RESET) != 0) {
281       if (++i >= 500000) {
282         os_printf("FEC Ethernet does not reset\n");
283         if (cache_state)
284           HAL_DCACHE_ENABLE();
285         HAL_RESTORE_INTERRUPTS(int_state);
286         return false;
287       }
288     }
289
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
293
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;
300     qi->txactive = 0;
301
302     RxBUF = &fec_eth_rxbufs[0];
303     TxBUF = &fec_eth_txbufs[0];
304
305     // setup buffer descriptors
306     for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM;  i++) {
307         rxbd->length = 0;
308         rxbd->buffer = RxBUF;
309         rxbd->ctrl   = FEC_BD_Rx_Empty;
310         RxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
311         rxbd++;
312     }
313     rxbd--;
314     rxbd->ctrl |= FEC_BD_Rx_Wrap;  // Last buffer
315     for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM;  i++) {
316         txbd->length = 0;
317         txbd->buffer = TxBUF;
318         txbd->ctrl   = 0;
319         TxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
320         txbd++;
321     }
322     txbd--;
323     txbd->ctrl |= FEC_BD_Tx_Wrap;  // Last buffer
324
325     // Reset interrupts
326     fec->iMask  = 0x00000000;  // No interrupts enabled
327     fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
328
329     // Initialize shared PRAM
330     fec->RxRing = qi->rbase;
331     fec->TxRing = qi->tbase;
332
333     // Size of receive buffers
334     fec->RxBufSize = CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
335
336     // Receiver control
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
340
341     // Transmit control
342     fec->TxControl = 4+0;
343
344     // Use largest possible Tx FIFO
345     fec->TxWater = 3;
346
347     // DMA control
348     fec->FunCode = ((2<<29) | (2<<27) | (0<<24));
349
350     // MII speed control (50MHz)
351     fec->MiiSpeed = 0x14;
352
353     // Group address hash
354     fec->hash[0] = 0;
355     fec->hash[1] = 0;
356
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]);
361
362     // Enable device
363     fec->eControl = eControl_EN | eControl_MUX;
364     fec->RxUpdate = 0x0F0F0F0F;  // Any write tells machine to look for work
365
366 #ifdef _FEC_USE_INTS
367     // Set up for interrupts
368     fec->iMask = iEvent_TFINT | iEvent_TXB |
369                  iEvent_RFINT | iEvent_RXB;
370     fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
371 #endif
372
373     if (cache_state)
374         HAL_DCACHE_ENABLE();
375
376     // Set LED state
377     clear_led(LED_TxACTIVE);
378     clear_led(LED_RxACTIVE);
379
380     HAL_RESTORE_INTERRUPTS(int_state);
381     return true;
382 }
383
384 //
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.
388 //
389 static bool 
390 fec_eth_init(struct cyg_netdevtab_entry *tab)
391 {
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);
396     int cache_state;
397     unsigned long proc_rev;
398     bool esa_ok;
399 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
400     int phy_timeout = 5*1000;  // Wait 5 seconds max for link to clear
401     bool phy_ok;
402     unsigned short phy_state = 0;
403 #endif
404
405     // Ensure consistent state between cache and what the FEC sees
406     HAL_DCACHE_IS_ENABLED(cache_state);
407     if (cache_state) {
408       HAL_DCACHE_SYNC();
409       HAL_DCACHE_DISABLE();
410     }
411
412     qi->fec = fec;
413     fec_eth_stop(sc);  // Make sure it's not running yet
414
415 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
416 #ifdef _FEC_USE_INTS
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,
424                              &fec_eth_interrupt);
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
435                       STACK_SIZE,        // Size
436                       &fec_fake_int_thread_handle,    // Handle
437                       &fec_fake_int_thread_data       // Thread data structure
438             );
439     cyg_thread_resume(fec_fake_int_thread_handle);  // Start it
440 #endif
441 #endif
442
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;
449     } else {
450         eppc->pio_pddir = 0x1FFF;
451     }
452
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);
457 #else
458     esa_ok = false;
459 #endif
460 #else
461     esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,         
462                                          "fec_esa", enaddr, CONFIG_ESA);
463 #endif
464     if (!esa_ok) {
465         // Can't figure out ESA
466         os_printf("FEC_ETH - Warning! ESA unknown\n");
467         memcpy(&enaddr, &_default_enaddr, sizeof(enaddr));
468     }
469
470     // Configure the device
471     if (!fec_eth_reset(sc, enaddr, 0)) {
472         return false;
473     }
474
475     fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
476
477 #ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
478     // Reset PHY (transceiver)
479     FEC_ETH_RESET_PHY();
480
481     phy_ok = 0;
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;
485             int i;
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);
489                 if (!phy_ok) break;
490                 if (!(phy_state & PHY_BMCR_RESET)) break;
491             }
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);
494                 return false;
495             }
496
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;
501 #endif
502 #ifdef CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE_100Mb
503             reset_mode |= PHY_BMCR_100MB;
504 #endif
505             phy_write(PHY_BMCR, FEC_ETH_PHY, reset_mode);
506             while (phy_timeout-- >= 0) {
507                 int ev = fec->iEvent;
508                 unsigned short state;
509                 fec->iEvent = ev;
510                 if (ev & iEvent_MII) {
511                     phy_ok = phy_read(PHY_BMSR, FEC_ETH_PHY, &state);
512                     if (phy_ok && (state & PHY_BMSR_LINK)) {
513                         break;
514                     } else {
515                         CYGACC_CALL_IF_DELAY_US(10000);   // 10ms
516                     }
517                 }
518             }
519             if (phy_timeout <= 0) {
520                 os_printf("** FEC Warning: PHY LINK UP failed\n");
521             }
522         }
523         else {
524             os_printf("** FEC Info: PHY LINK already UP \n");
525         }
526     }
527 #endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
528
529     // Initialize upper level driver
530     (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr);
531     
532     if (cache_state)
533       HAL_DCACHE_ENABLE();
534
535     return true;
536 }
537  
538 //
539 // This function is called to shut down the interface.
540 //
541 static void
542 fec_eth_stop(struct eth_drv_sc *sc)
543 {
544     struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
545
546     // Disable the device!
547     qi->fec->eControl &= ~eControl_EN;
548 }
549
550 //
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.
555 //
556 static void
557 fec_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
558 {
559     // Enable the device!
560     fec_eth_reset(sc, enaddr, flags);
561 }
562
563 //
564 // This function is called for low level "control" operations
565 //
566 static int
567 fec_eth_control(struct eth_drv_sc *sc, unsigned long key,
568                   void *data, int length)
569 {
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;
573 #endif
574
575     switch (key) {
576     case ETH_DRV_SET_MAC_ADDRESS:
577         return 0;
578         break;
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;
585         return 0;
586         break;
587 #endif
588     default:
589         return 1;
590         break;
591     }
592 }
593
594 //
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.
598 //
599 static int
600 fec_eth_can_send(struct eth_drv_sc *sc)
601 {
602     struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
603
604     return (qi->txactive < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM);
605 }
606
607 //
608 // This routine is called to send data to the hardware.
609
610 static void 
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)
613 {
614     struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
615     volatile struct fec_bd *txbd, *txfirst;
616     volatile char *bp;
617     int i, txindex, cache_state;
618
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) {
624             txbd = qi->tbase;
625         } else {
626             txbd++;
627         }
628         if (txbd == txfirst) {
629 #ifdef CYGPKG_NET
630             panic ("No free xmit buffers");
631 #else
632             os_printf("FEC Ethernet: No free xmit buffers\n");
633 #endif
634         }
635     }
636     // Set up buffer
637     bp = txbd->buffer;
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;
641     } 
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);
647     if (cache_state) {
648         HAL_DCACHE_FLUSH(txbd->buffer, txbd->length);  // Make sure no stale data
649     }
650     // Send it on it's way
651     txbd->ctrl |= FEC_BD_Tx_Ready | FEC_BD_Tx_Last | FEC_BD_Tx_TC;
652     qi->txactive++;
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;
658     } else {
659         qi->txbd = txbd+1;
660     }
661 }
662
663 //
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.
669 //
670 static void
671 fec_eth_RxEvent(struct eth_drv_sc *sc)
672 {
673     struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
674     volatile struct fec_bd *rxbd, *rxfirst;
675
676     rxbd = rxfirst = qi->rnext;
677     while (true) {
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);
682         }
683         if (rxbd->ctrl & FEC_BD_Rx_Wrap) {
684             rxbd = qi->rbase;
685         } else {
686             rxbd++;
687         }
688         if (rxbd == rxfirst) {
689             break;
690         }
691     }
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
695 }
696
697 //
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.
703 //
704 static void
705 fec_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
706 {
707     struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
708     unsigned char *bp;
709     int i, cache_state;
710
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);
714     if (cache_state) {
715         HAL_DCACHE_INVALIDATE(qi->rxbd->buffer, qi->rxbd->length);  // Make sure no stale data
716     }
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;
721         }
722     }
723     qi->rxbd->ctrl |= FEC_BD_Rx_Empty;
724     clear_led(LED_RxACTIVE);
725 }
726
727 static void
728 fec_eth_TxEvent(struct eth_drv_sc *sc)
729 {
730     struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
731     volatile struct fec_bd *txbd;
732     int key, txindex;
733
734     txbd = qi->tnext;
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);
741         }
742         if (--qi->txactive == 0) {
743           clear_led(LED_TxACTIVE);
744         }
745         txbd->ctrl &= ~FEC_BD_Tx_TC;
746         if (txbd->ctrl & FEC_BD_Tx_Wrap) {
747             txbd = qi->tbase;
748         } else {
749             txbd++;
750         }
751     }
752     // Remember where we left off
753     qi->tnext = (struct fec_bd *)txbd;
754 }
755
756 //
757 // Interrupt processing
758 //
759 static void          
760 fec_eth_int(struct eth_drv_sc *sc)
761 {
762     struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
763     unsigned long event;
764
765     while ((event = qi->fec->iEvent) != 0) {
766         qi->fec->iEvent = event;  // Reset the bits we handled
767         if ((event & iEvent_TFINT) != 0) {
768             fec_eth_TxEvent(sc);
769         }
770         if ((event & iEvent_RFINT) != 0) {
771             fec_eth_RxEvent(sc);
772         }
773     }
774 }
775
776 //
777 // Interrupt vector
778 //
779 static int          
780 fec_eth_int_vector(struct eth_drv_sc *sc)
781 {
782     return (FEC_ETH_INT);
783 }
784
785 #if defined(CYGINT_IO_ETH_INT_SUPPORT_REQUIRED) && ~defined(_FEC_USE_INTS)
786 void
787 fec_fake_int(cyg_addrword_t param)
788 {
789     struct eth_drv_sc *sc = (struct eth_drv_sc *) param;
790     int int_state;
791
792     while (true) {
793       cyg_thread_delay(1);  // 10ms
794       HAL_DISABLE_INTERRUPTS(int_state);
795       fec_eth_int(sc);
796       HAL_RESTORE_INTERRUPTS(int_state);
797     }
798 }
799 #endif