]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/powerpc/quicc/v2_0/src/if_quicc.c
Initial revision
[karo-tx-redboot.git] / packages / devs / eth / powerpc / quicc / v2_0 / src / if_quicc.c
1 //==========================================================================
2 //
3 //      dev/if_quicc.c
4 //
5 //      Ethernet device driver for PowerPC QUICC (MPC8xx) 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 // Copyright (C) 2003 Nick Garnett <nickg@calivar.com>
14 //
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
18 //
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 // for more details.
23 //
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 //
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
34 //
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
37 //
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //####BSDCOPYRIGHTBEGIN####
43 //
44 // -------------------------------------------
45 //
46 // Portions of this software may have been derived from OpenBSD or other sources,
47 // and are covered by the appropriate copyright disclaimers included herein.
48 //
49 // -------------------------------------------
50 //
51 //####BSDCOPYRIGHTEND####
52 //==========================================================================
53 //#####DESCRIPTIONBEGIN####
54 //
55 // Author(s):    gthomas
56 // Contributors: gthomas, nickg
57 // Date:         2000-01-10
58 // Purpose:      
59 // Description:  hardware driver for MPC8xx QUICC
60 //              
61 //
62 //####DESCRIPTIONEND####
63 //
64 //==========================================================================
65
66 // Ethernet device driver for MPC8xx QUICC
67
68 #include <pkgconf/system.h>
69 #include <pkgconf/devs_eth_powerpc_quicc.h>
70 #include <pkgconf/io_eth_drivers.h>
71
72 #ifdef CYGPKG_NET
73 #include <pkgconf/net.h>
74 #endif
75
76 #include <cyg/infra/cyg_type.h>
77 #include <cyg/infra/diag.h>
78
79 #include <cyg/hal/hal_arch.h>
80 #include <cyg/hal/hal_cache.h>
81 #include <cyg/hal/hal_intr.h>
82 #include <cyg/hal/drv_api.h>
83
84 #include <cyg/io/eth/netdev.h>
85 #include <cyg/io/eth/eth_drv.h>
86
87 #include "quicc_eth.h"
88
89 static unsigned char quicc_eth_rxbufs[CYGNUM_DEVS_ETH_POWERPC_QUICC_RxNUM]
90                                      [CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
91 static unsigned char quicc_eth_txbufs[CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM]
92                                      [CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE]  __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
93
94 static struct quicc_eth_info quicc_eth0_info;
95 static unsigned char _default_enaddr[] = { 0x08, 0x00, 0x3E, 0x28, 0x79, 0xB8};
96 static unsigned char enaddr[6];
97 #ifdef CYGPKG_REDBOOT
98 #include <pkgconf/redboot.h>
99 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
100 #include <redboot.h>
101 #include <flash_config.h>
102 RedBoot_config_option("Network hardware address [MAC]",
103                       quicc_esa,
104                       ALWAYS_ENABLED, true,
105                       CONFIG_ESA, 0
106     );
107 #endif
108 #endif
109
110 // For fetching the ESA from RedBoot
111 #include <cyg/hal/hal_if.h>
112 #ifndef CONFIG_ESA
113 #define CONFIG_ESA 6
114 #endif
115
116 ETH_DRV_SC(quicc_eth0_sc,
117            &quicc_eth0_info,   // Driver specific data
118            "eth0",             // Name for this interface
119            quicc_eth_start,
120            quicc_eth_stop,
121            quicc_eth_control,
122            quicc_eth_can_send,
123            quicc_eth_send,
124            quicc_eth_recv,
125            quicc_eth_deliver,
126            quicc_eth_int,
127            quicc_eth_int_vector);
128
129 NETDEVTAB_ENTRY(quicc_netdev, 
130                 "quicc_eth", 
131                 quicc_eth_init, 
132                 &quicc_eth0_sc);
133
134 // LED activity [exclusive of hardware bits]
135 #ifndef _get_led
136 #define _get_led()  
137 #define _set_led(v) 
138 #endif
139 #ifndef LED_TxACTIVE
140 #define LED_TxACTIVE  7
141 #define LED_RxACTIVE  6
142 #define LED_IntACTIVE 5
143 #endif
144
145 static void
146 set_led(int bit)
147 {
148   _set_led(_get_led() | (1<<bit));
149 }
150
151 static void
152 clear_led(int bit)
153 {
154   _set_led(_get_led() & ~(1<<bit));
155 }
156
157 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
158 static cyg_interrupt quicc_eth_interrupt;
159 static cyg_handle_t  quicc_eth_interrupt_handle;
160 #endif
161 static void          quicc_eth_int(struct eth_drv_sc *data);
162 static void          quicc_eth_command(struct eth_drv_sc *sc, unsigned long cmd);
163
164 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
165 // This ISR is called when the ethernet interrupt occurs
166 static int
167 quicc_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
168 {
169     cyg_drv_interrupt_mask(QUICC_ETH_INT);
170     cyg_drv_interrupt_acknowledge(QUICC_ETH_INT);
171     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
172 }
173 #endif
174
175 // Deliver function (ex-DSR) handles the ethernet [logical] processing
176 static void
177 quicc_eth_deliver(struct eth_drv_sc * sc)
178 {
179     quicc_eth_int(sc);
180 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
181     // Allow interrupts to happen again
182     cyg_drv_interrupt_unmask(QUICC_ETH_INT);
183 #endif
184 }
185
186 //
187 // Initialize the interface - performed at system startup
188 // This function must set up the interface, including arranging to
189 // handle interrupts, etc, so that it may be "started" cheaply later.
190 //
191 static bool 
192 quicc_eth_init(struct cyg_netdevtab_entry *tab)
193 {
194     struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
195     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
196     volatile EPPC *eppc = (volatile EPPC *)eppc_base();
197     struct cp_bufdesc *rxbd, *txbd;
198     unsigned char *RxBUF, *TxBUF, *ep, *ap; 
199     volatile struct ethernet_pram *enet_pram;
200     volatile struct scc_regs *scc;
201     int TxBD, RxBD;
202     int cache_state;
203     int i;
204     bool esa_ok = false;
205
206 #ifdef QUICC_ETH_FETCH_ESA
207     QUICC_ETH_FETCH_ESA(esa_ok);
208 #endif
209
210     if (!esa_ok) {
211 #if defined(CYGPKG_REDBOOT) && \
212     defined(CYGSEM_REDBOOT_FLASH_CONFIG)
213         esa_ok = flash_get_config("quicc_esa", enaddr, CONFIG_ESA);
214 #else
215         esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,         
216                                              "quicc_esa", enaddr, CONFIG_ESA);
217 #endif
218         if (!esa_ok) {
219             // Can't figure out ESA
220             diag_printf("QUICC_ETH - Warning! ESA unknown\n");
221             memcpy(&enaddr, &_default_enaddr, sizeof(enaddr));
222         }
223     }
224
225     // Ensure consistent state between cache and what the QUICC sees
226     HAL_DCACHE_IS_ENABLED(cache_state);
227     if (cache_state) {
228         HAL_DCACHE_SYNC();
229         HAL_DCACHE_DISABLE();
230     }
231
232 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
233     // Set up to handle interrupts
234     cyg_drv_interrupt_create(QUICC_ETH_INT,
235                              CYGARC_SIU_PRIORITY_HIGH,
236                              (cyg_addrword_t)sc, //  Data item passed to interrupt handler
237                              (cyg_ISR_t *)quicc_eth_isr,
238                              (cyg_DSR_t *)eth_drv_dsr,
239                              &quicc_eth_interrupt_handle,
240                              &quicc_eth_interrupt);
241     cyg_drv_interrupt_attach(quicc_eth_interrupt_handle);
242     cyg_drv_interrupt_acknowledge(QUICC_ETH_INT);
243     cyg_drv_interrupt_unmask(QUICC_ETH_INT);
244 #endif
245
246     qi->pram = enet_pram = &eppc->pram[QUICC_ETH_SCC].enet_scc;
247     qi->ctl = scc = &eppc->scc_regs[QUICC_ETH_SCC];  // Use SCCx
248
249     // Shut down ethernet, in case it is already running
250     scc->scc_gsmr_l &= ~(QUICC_SCC_GSML_ENR | QUICC_SCC_GSML_ENT);
251
252     memset((void *)enet_pram, 0, sizeof(*enet_pram));
253
254     TxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM * sizeof(struct cp_bufdesc));
255     RxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_QUICC_RxNUM * sizeof(struct cp_bufdesc));
256
257     txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
258     rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
259     qi->tbase = txbd;
260     qi->txbd = txbd;    
261     qi->tnext = txbd;
262     qi->rbase = rxbd;
263     qi->rxbd = rxbd;
264     qi->rnext = rxbd;
265     qi->txactive = 0;
266
267     RxBUF = &quicc_eth_rxbufs[0][0];
268     TxBUF = &quicc_eth_txbufs[0][0];
269
270     // setup buffer descriptors
271     for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_QUICC_RxNUM;  i++) {
272         rxbd->length = 0;
273         rxbd->buffer = RxBUF;
274         rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
275         RxBUF += CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
276         rxbd++;
277     }
278     rxbd--;
279     rxbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
280     for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM;  i++) {
281         txbd->length = 0;
282         txbd->buffer = TxBUF;
283         txbd->ctrl   = 0;
284         TxBUF += CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
285         txbd++;
286     }
287     txbd--;
288     txbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
289
290     // Set up parallel ports for connection to ethernet tranceiver
291     eppc->pio_papar |= (QUICC_ETH_PA_RXD | QUICC_ETH_PA_TXD);
292     eppc->pio_padir &= ~(QUICC_ETH_PA_RXD | QUICC_ETH_PA_TXD);
293     eppc->pio_paodr &= ~QUICC_ETH_PA_TXD;
294
295     eppc->pio_pcpar &= ~(QUICC_ETH_PC_COLLISION | QUICC_ETH_PC_Rx_ENABLE);
296     eppc->pio_pcdir &= ~(QUICC_ETH_PC_COLLISION | QUICC_ETH_PC_Rx_ENABLE);
297     eppc->pio_pcso  |= (QUICC_ETH_PC_COLLISION | QUICC_ETH_PC_Rx_ENABLE);
298
299     eppc->pio_papar |= (QUICC_ETH_PA_Tx_CLOCK | QUICC_ETH_PA_Rx_CLOCK);
300     eppc->pio_padir &= ~(QUICC_ETH_PA_Tx_CLOCK | QUICC_ETH_PA_Rx_CLOCK);
301
302     // Set up clock routing
303     eppc->si_sicr &= ~QUICC_ETH_SICR_MASK;
304     eppc->si_sicr |= QUICC_ETH_SICR_ENET;
305     eppc->si_sicr &= ~QUICC_ETH_SICR_ENABLE;
306
307     // Set up DMA mode
308     eppc->dma_sdcr = 0x0001;
309
310     // Initialize shared PRAM
311     enet_pram->rbase = RxBD;
312     enet_pram->tbase = TxBD;
313
314     // Set Big Endian mode
315     enet_pram->rfcr = QUICC_SCC_FCR_BE;
316     enet_pram->tfcr = QUICC_SCC_FCR_BE;
317
318     // Size of receive buffers
319     enet_pram->mrblr = CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
320
321     // Initialize CRC calculations
322     enet_pram->c_pres = 0xFFFFFFFF;
323     enet_pram->c_mask = 0xDEBB20E3;  // Actual CRC formula
324     enet_pram->crcec = 0;
325     enet_pram->alec = 0;
326     enet_pram->disfc = 0;
327
328     // Frame padding
329     enet_pram->pads = 0x8888;
330     enet_pram->pads = 0x0000;
331
332     // Retries
333     enet_pram->ret_lim = 15;
334     enet_pram->ret_cnt = 0;
335
336     // Frame sizes
337     enet_pram->mflr = IEEE_8023_MAX_FRAME;
338     enet_pram->minflr = IEEE_8023_MIN_FRAME;
339     enet_pram->maxd1 = CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
340     enet_pram->maxd2 = CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
341
342     // Group address hash
343     enet_pram->gaddr1 = 0;
344     enet_pram->gaddr2 = 0;
345     enet_pram->gaddr3 = 0;
346     enet_pram->gaddr4 = 0;
347
348     // Device physical address
349     ep = &enaddr[sizeof(enaddr)];
350     ap = (unsigned char *)&enet_pram->paddr_h;
351     for (i = 0;  i < sizeof(enaddr);  i++) {
352         *ap++ = *--ep;
353     }
354
355     // Persistence counter
356     enet_pram->p_per = 0; 
357
358     // Individual address filter
359     enet_pram->iaddr1 = 0;
360     enet_pram->iaddr2 = 0;
361     enet_pram->iaddr3 = 0;
362     enet_pram->iaddr4 = 0;
363
364     // Temp address
365     enet_pram->taddr_h = 0;
366     enet_pram->taddr_m = 0;
367     enet_pram->taddr_l = 0;
368
369     // Initialize the CPM (set up buffer pointers, etc).
370     quicc_eth_command(sc, QUICC_CPM_CR_INIT_TXRX);
371
372     // Clear any pending interrupt/exceptions
373     scc->scc_scce = 0xFFFF;
374
375     // Enable interrupts
376     scc->scc_sccm = QUICC_SCCE_INTS | QUICC_SCCE_GRC | QUICC_SCCE_BSY;
377
378     // Set up SCCx to run in ethernet mode
379     scc->scc_gsmr_h = 0;
380     scc->scc_gsmr_l = QUICC_SCC_GSML_TCI | QUICC_SCC_GSML_TPL_48 |
381         QUICC_SCC_GSML_TPP_01 | QUICC_SCC_GSML_MODE_ENET;
382
383     // Sync delimiters
384     scc->scc_dsr = 0xD555;
385
386     // Protocol specifics (as if GSML wasn't enough)
387     scc->scc_psmr = QUICC_PMSR_ENET_CRC | QUICC_PMSR_SEARCH_AFTER_22 |
388         QUICC_PMSR_RCV_SHORT_FRAMES;
389
390 #ifdef QUICC_ETH_ENABLE
391     QUICC_ETH_ENABLE();
392 #endif
393
394 #ifdef QUICC_ETH_RESET_PHY
395     QUICC_ETH_RESET_PHY();
396 #endif
397
398     // Enable ethernet interface
399 #ifdef QUICC_ETH_PC_Tx_ENABLE
400     eppc->pio_pcpar |= QUICC_ETH_PC_Tx_ENABLE;
401     eppc->pio_pcdir &= ~QUICC_ETH_PC_Tx_ENABLE;
402 #else
403     eppc->pip_pbpar |= QUICC_ETH_PB_Tx_ENABLE;
404     eppc->pip_pbdir |= QUICC_ETH_PB_Tx_ENABLE;
405 #endif
406
407     if (cache_state)
408         HAL_DCACHE_ENABLE();
409
410     // Initialize upper level driver
411     (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr);
412
413     // Set LED state
414     clear_led(LED_TxACTIVE);
415     clear_led(LED_RxACTIVE);
416
417     return true;
418 }
419
420 //
421 // This function is called to shut down the interface.
422 //
423 static void
424 quicc_eth_stop(struct eth_drv_sc *sc)
425 {
426     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
427     volatile struct scc_regs *scc = qi->ctl;
428
429     // Disable the device!
430     scc->scc_gsmr_l &= ~(QUICC_SCC_GSML_ENR | QUICC_SCC_GSML_ENT);
431 }
432
433 //
434 // This function is called to "start up" the interface.  It may be called
435 // multiple times, even when the hardware is already running.  It will be
436 // called whenever something "hardware oriented" changes and should leave
437 // the hardware ready to send/receive packets.
438 //
439 static void
440 quicc_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
441 {
442     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
443     volatile struct scc_regs *scc = qi->ctl;
444
445     // Enable the device!
446     scc->scc_gsmr_l |= QUICC_SCC_GSML_ENR | QUICC_SCC_GSML_ENT;
447 }
448
449 //
450 // This function is called for low level "control" operations
451 //
452 static int
453 quicc_eth_control(struct eth_drv_sc *sc, unsigned long key,
454                   void *data, int length)
455 {
456     switch (key) {
457     case ETH_DRV_SET_MAC_ADDRESS:
458         return 0;
459         break;
460
461 #ifdef ETH_DRV_GET_IF_STATS
462     case ETH_DRV_GET_IF_STATS:
463     {
464         struct ether_drv_stats *p = (struct ether_drv_stats *)data;
465         struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
466
467         strcpy( p->description, "QUICC (MPC8xx) SCC Ethernet" );
468         CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
469
470         // Really need to determine the following values properly, for
471         // now just assume the link is up, full duplex, unknown speed.
472         
473         p->operational = 3;            // LINK UP
474         p->duplex = 1;
475         p->speed = 0;
476
477         {
478             p->supports_dot3        = false;
479
480             // Those commented out are not available on this chip.
481
482             p->tx_good              = qi->tx_good             ;
483             //p->tx_max_collisions    = qi->tx_max_collisions ;
484             p->tx_late_collisions   = qi->tx_late_collisions  ;
485             p->tx_underrun          = qi->tx_underrun         ;
486             p->tx_carrier_loss      = qi->tx_carrier_loss     ;
487             p->tx_deferred          = qi->tx_deferred         ;
488             //p->tx_sqetesterrors   = qi->tx_sqetesterrors    ;
489             //p->tx_single_collisions = qi->tx_single_collisions;
490             //p->tx_mult_collisions   = qi->tx_mult_collisions  ;
491             //p->tx_total_collisions  = qi->tx_total_collisions ;
492             p->rx_good              = qi->rx_good             ;
493             p->rx_crc_errors        = qi->rx_crc_errors       ;
494             p->rx_align_errors      = qi->rx_align_errors     ;
495             p->rx_resource_errors   = qi->rx_resource_errors  ;
496             p->rx_overrun_errors    = qi->rx_overrun_errors   ;
497             p->rx_collisions        = qi->rx_collisions       ;
498             p->rx_short_frames      = qi->rx_short_frames     ;
499             p->rx_too_long_frames   = qi->rx_long_frames      ;
500             //p->rx_symbol_errors   = qi->rx_symbol_errors    ;
501         
502             p->interrupts           = qi->interrupts          ;
503             p->rx_count             = qi->rx_count            ;
504             p->rx_deliver           = qi->rx_deliver          ;
505             p->rx_resource          = qi->rx_resource         ;
506             p->rx_restart           = qi->rx_restart          ;
507             p->tx_count             = qi->tx_count            ;
508             p->tx_complete          = qi->tx_complete         ;
509             p->tx_dropped           = qi->tx_dropped          ;
510         }
511
512         p->tx_queue_len = CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM;
513
514         return 0; // OK
515     }
516 #endif
517
518         
519     default:
520         return 1;
521         break;
522     }
523 }
524
525 //
526 // This function is called to see if another packet can be sent.
527 // It should return the number of packets which can be handled.
528 // Zero should be returned if the interface is busy and can not send any more.
529 //
530 static int
531 quicc_eth_can_send(struct eth_drv_sc *sc)
532 {
533     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
534
535     return (qi->txactive < CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM);
536 }
537
538 //
539 // This routine is called to send data to the hardware.
540 static void 
541 quicc_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, 
542                int total_len, unsigned long key)
543 {
544     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
545     volatile struct cp_bufdesc *txbd, *txfirst;
546     volatile char *bp;
547     int i, txindex, cache_state;
548     unsigned int ctrl;
549
550     qi->tx_count++;
551     
552     // Find a free buffer
553     txbd = txfirst = qi->txbd;
554     if ((txbd->ctrl & (QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int )))
555 #ifdef CYGPKG_NET
556             panic ("No free xmit buffers");
557 #else
558             diag_printf("QUICC Ethernet: No free xmit buffers\n");
559 #endif
560
561     // Remember the next buffer to try
562     if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
563         qi->txbd = qi->tbase;
564     } else {
565         qi->txbd = txbd+1;
566     }
567     txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
568     qi->txkey[txindex] = key;
569     // Set up buffer
570     txbd->length = total_len;
571     bp = txbd->buffer;
572     for (i = 0;  i < sg_len;  i++) {
573         memcpy((void *)bp, (void *)sg_list[i].buf, sg_list[i].len);
574         bp += sg_list[i].len;
575     }
576     // Note: the MPC8xx does not seem to snoop/invalidate the data cache properly!
577     HAL_DCACHE_IS_ENABLED(cache_state);
578     if (cache_state) {
579         HAL_DCACHE_FLUSH(txbd->buffer, txbd->length);  // Make sure no stale data
580     }
581     // Send it on it's way
582     ctrl = txbd->ctrl & ~QUICC_BD_TX_PAD;
583     if (txbd->length < IEEE_8023_MIN_FRAME) {
584         ctrl |= QUICC_BD_TX_PAD;
585     }
586     txbd->ctrl = ctrl | QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int | 
587         QUICC_BD_TX_LAST | QUICC_BD_TX_TC;
588     qi->txactive++;
589     set_led(LED_TxACTIVE);
590 }
591
592 //
593 // This function is called when a packet has been received.  It's job is
594 // to prepare to unload the packet from the hardware.  Once the length of
595 // the packet is known, the upper layer of the driver can be told.  When
596 // the upper layer is ready to unload the packet, the internal function
597 // 'quicc_eth_recv' will be called to actually fetch it from the hardware.
598 //
599 static void
600 quicc_eth_RxEvent(struct eth_drv_sc *sc)
601 {
602     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
603     volatile struct cp_bufdesc *rxbd;
604         
605
606     rxbd = qi->rnext;
607     while ((rxbd->ctrl & (QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
608
609         qi->rx_count++;
610         
611         if( rxbd->ctrl & QUICC_BD_RX_MISS )
612         {
613             qi->rx_miss++;
614         }
615         if( rxbd->ctrl & QUICC_BD_RX_LG )
616         {
617             qi->rx_long_frames++;
618         }
619         if( rxbd->ctrl & QUICC_BD_RX_NO )
620         {
621             qi->rx_align_errors++;
622         }
623         if( rxbd->ctrl & QUICC_BD_RX_SH )
624         {
625             qi->rx_short_frames++;
626         }
627         if( rxbd->ctrl & QUICC_BD_RX_CR )
628         {
629             qi->rx_crc_errors++;
630         }
631         if( rxbd->ctrl & QUICC_BD_RX_OV )
632         {
633             qi->rx_overrun_errors++;
634         }
635
636         if( rxbd->ctrl & QUICC_BD_RX_CL )
637         {
638             qi->rx_collisions++;
639         }
640
641         if( (rxbd->ctrl & QUICC_BD_RX_ERRORS) == 0 )
642         {
643             qi->rx_good++;
644                         
645             // OK frame - Prepare for callback
646             qi->rxbd = rxbd;  // Save for callback
647             set_led(LED_RxACTIVE);
648             // Remove the CRC from the end
649             (sc->funs->eth_drv->recv)(sc, rxbd->length - 4);
650                         
651             clear_led(LED_RxACTIVE);
652         }
653         
654       
655         // Clear flags and wrap if needed else step up BD pointer 
656         if (rxbd->ctrl & QUICC_BD_CTL_Wrap) 
657         {
658             rxbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int | QUICC_BD_CTL_Wrap;
659             rxbd = qi->rbase;
660         } 
661         else 
662         {
663             rxbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
664             rxbd++;
665         }
666         
667     }
668     // Remember where we left off
669     qi->rnext = (struct cp_bufdesc *)rxbd;
670 }
671
672 //
673 // This function is called as a result of the "eth_drv_recv()" call above.
674 // It's job is to actually fetch data for a packet from the hardware once
675 // memory buffers have been allocated for the packet.  Note that the buffers
676 // may come in pieces, using a scatter-gather list.  This allows for more
677 // efficient processing in the upper layers of the stack.
678 //
679 static void
680 quicc_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
681 {
682     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
683     unsigned char *bp;
684     int i, cache_state;
685     int sg_list_null_buffer = 0;
686     
687     bp = (unsigned char *)qi->rxbd->buffer;
688     // Note: the MPC8xx does not seem to snoop/invalidate the data cache properly!
689     HAL_DCACHE_IS_ENABLED(cache_state);
690     if (cache_state) {
691         HAL_DCACHE_INVALIDATE(qi->rxbd->buffer, qi->rxbd->length);  // Make sure no stale data
692     }
693     for (i = 0;  i < sg_len;  i++) {
694         if (sg_list[i].buf != 0) {
695             memcpy((void *)sg_list[i].buf, bp, sg_list[i].len);
696             bp += sg_list[i].len;
697         }
698         else
699             sg_list_null_buffer = 1;
700     }
701
702     // A NULL sg_list buffer usually means no mbufs, so we don't count
703     // it as a delivery, instead we count it as a resource error.
704     
705     if (!sg_list_null_buffer)
706         qi->rx_deliver++;
707     else
708         qi->rx_resource++;
709
710 }
711
712 static void
713 quicc_eth_command( struct eth_drv_sc *sc, unsigned long cmd)
714 {
715    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
716    
717    eppc->cp_cr = QUICC_CPM_SCCx | cmd | QUICC_CPM_CR_BUSY;
718    while (eppc->cp_cr & QUICC_CPM_CR_BUSY )
719        continue;
720 }
721
722 static void
723 quicc_eth_TxEvent(struct eth_drv_sc *sc, int stat)
724 {
725     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
726     volatile struct cp_bufdesc *txbd;
727     int txindex;
728     bool restart = false;
729
730     txbd = qi->tnext;
731     
732     while ((txbd->ctrl & (QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
733
734         txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
735
736         qi->tx_complete++;
737         
738         (sc->funs->eth_drv->tx_done)(sc, qi->txkey[txindex], 0);
739         txbd->ctrl &= ~QUICC_BD_CTL_Int;  // Reset int pending bit
740
741         if (txbd->ctrl & QUICC_BD_TX_LC )
742             qi->tx_late_collisions++, restart = true;
743         if (txbd->ctrl & QUICC_BD_TX_RL )
744             qi->tx_retransmit_error++, restart = true;
745         if (txbd->ctrl & QUICC_BD_TX_UN )
746             qi->tx_underrun++, restart = true;
747         if (txbd->ctrl & QUICC_BD_TX_CSL )
748             qi->tx_carrier_loss++;
749         if (txbd->ctrl & QUICC_BD_TX_HB )
750             qi->tx_heartbeat_loss++;        
751         if (txbd->ctrl & QUICC_BD_TX_DEF )
752             qi->tx_deferred++;        
753
754         if( (txbd->ctrl & QUICC_BD_TX_ERRORS) == 0 )
755             qi->tx_good++;
756
757         
758         if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
759             txbd->ctrl = QUICC_BD_CTL_Wrap;
760             txbd = qi->tbase;
761         } else {
762             txbd->ctrl = 0;            
763             txbd++;
764         }
765         qi->txactive--;
766     }
767
768     if (qi->txactive == 0) {
769         clear_led(LED_TxACTIVE);
770     }
771     
772     // Remember where we left off
773     qi->tnext = (struct cp_bufdesc *)txbd;
774
775     if (restart)
776     {
777         quicc_eth_command(sc,QUICC_CPM_CR_RESTART_TX);
778         qi->tx_restart++;        
779     }
780     
781 }
782
783 //
784 // Interrupt processing
785 //
786 static void          
787 quicc_eth_int(struct eth_drv_sc *sc)
788 {
789     struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
790     volatile struct scc_regs *scc = qi->ctl;
791     unsigned short scce;
792
793     qi->interrupts++;
794
795     while ( (scce = scc->scc_scce) != 0 )
796     {
797         scc->scc_scce = scce;
798         
799         if ( (scce & (QUICC_SCCE_TXE | QUICC_SCCE_TX)) != 0)
800         {
801             quicc_eth_TxEvent(sc, scce);
802         }
803         if ( (scce & ( QUICC_SCCE_RXF | QUICC_SCCE_RX )) != 0)
804         {
805             quicc_eth_RxEvent(sc);
806         }
807         if ( (scce & QUICC_SCCE_BSY) != 0)
808         {
809             qi->rx_resource_errors++;
810         }
811         if ( (scce & QUICC_SCCE_GRC) != 0 )
812         {
813             quicc_eth_command(sc, QUICC_CPM_CR_RESTART_TX);
814             qi->tx_restart++;
815             quicc_eth_command(sc, QUICC_CPM_CR_HUNT_MODE);
816             qi->rx_restart++;
817         }
818     }
819 }
820
821 //
822 // Interrupt vector
823 //
824 static int          
825 quicc_eth_int_vector(struct eth_drv_sc *sc)
826 {
827     return (QUICC_ETH_INT);
828 }