]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/amd/pcnet/v2_0/src/if_pcnet.c
Initial revision
[karo-tx-redboot.git] / packages / devs / eth / amd / pcnet / v2_0 / src / if_pcnet.c
1 //==========================================================================
2 //
3 //      dev/if_pcnet.c
4 //
5 //      Ethernet device driver for AMD PCNET compatible controllers
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 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //####BSDCOPYRIGHTBEGIN####
41 //
42 // -------------------------------------------
43 //
44 // Portions of this software may have been derived from OpenBSD or other sources,
45 // and are covered by the appropriate copyright disclaimers included herein.
46 //
47 // -------------------------------------------
48 //
49 //####BSDCOPYRIGHTEND####
50 //==========================================================================
51 //#####DESCRIPTIONBEGIN####
52 //
53 // Author(s):    jskov, based on lan91cxx driver by hmt & jskov
54 // Contributors: gthomas, jskov, hmt
55 // Date:         2001-04-02
56 // Purpose:      
57 // Description:  hardware driver for AMD PCNet (and possibly Lance) ethernet
58 // Notes:        The controller is used in its 16bit mode. That means that
59 //               all addresses are 24bit only - and that all controller
60 //               accessed memory must be within the same 16MB region
61 //               (starting at 0 on older controllers).
62 //
63 //               The KEEP_STATISTICS code is not implemented yet. Look
64 //               for FIXME macro.
65 //
66 //####DESCRIPTIONEND####
67 //
68 //==========================================================================
69
70 #include <pkgconf/system.h>
71 #include <pkgconf/devs_eth_amd_pcnet.h>
72 #include <pkgconf/io_eth_drivers.h>
73
74 #include <cyg/infra/cyg_type.h>
75 #include <cyg/hal/hal_arch.h>
76 #include <cyg/hal/hal_intr.h>
77 #include <cyg/infra/cyg_ass.h>
78 #include <cyg/infra/diag.h>
79 #include <cyg/hal/drv_api.h>
80 #include <cyg/hal/hal_if.h>             // delays
81 #include <string.h>
82 #include <cyg/io/eth/netdev.h>
83 #include <cyg/io/eth/eth_drv.h>
84 #ifdef CYGPKG_NET
85 #include <pkgconf/net.h>
86 #include <cyg/kernel/kapi.h>
87 #include <net/if.h>  /* Needed for struct ifnet */
88 #include <pkgconf/io_eth_drivers.h>
89 #endif
90 #include CYGHWR_MEMORY_LAYOUT_H
91
92 #ifdef CYGPKG_IO_PCI
93 #include <cyg/io/pci.h>
94 #else
95 #error "Need PCI package here"
96 #endif
97
98 #define FIXME 0
99
100 #define _BUF_SIZE 1544
101
102 #ifdef CYGPKG_INFRA_DEBUG
103 // Then we log, OOI, the number of times we get a bad packet number
104 // from the tx done fifo.
105 int pcnet_txfifo_good = 0;
106 int pcnet_txfifo_bad = 0;
107 #endif
108
109 #include "amd_pcnet.h"
110 #define __WANT_DEVS
111 #include CYGDAT_DEVS_ETH_AMD_PCNET_INL
112 #undef  __WANT_DEVS
113
114 #if defined(CYGPKG_REDBOOT) && DEBUG
115
116 static void db_printf( char *fmt, ... )
117 {
118     extern int start_console(void);
119     extern void end_console(int);
120     va_list a;
121     int old_console;
122     va_start( a, fmt );
123     old_console = start_console();  
124     diag_vprintf( fmt, a );
125     end_console(old_console);
126     va_end( a );
127 }
128
129 #else
130
131 #define db_printf diag_printf
132
133 #endif
134
135 static void pcnet_poll(struct eth_drv_sc *sc);
136
137 // This ISR is called when the ethernet interrupt occurs
138 static cyg_uint32
139 pcnet_isr(cyg_vector_t vector, cyg_addrword_t data)
140 {
141     struct pcnet_priv_data *cpd = (struct pcnet_priv_data *)data;
142
143     DEBUG_FUNCTION();
144
145     INCR_STAT( interrupts );
146
147     cyg_drv_interrupt_mask(cpd->interrupt);
148     cyg_drv_interrupt_acknowledge(cpd->interrupt);
149     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
150 }
151
152 static void
153 pcnet_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
154 {
155     // This conditioning out is necessary because of explicit calls to this
156     // DSR - which would not ever be called in the case of a polled mode
157     // usage ie. in RedBoot.
158 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
159     struct pcnet_priv_data* cpd = (struct pcnet_priv_data *)data;
160     struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->ndp);
161     struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
162
163     // but here, it must be a *sc:
164     eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
165 #else
166 # ifndef CYGPKG_REDBOOT
167 #  error Empty PCnet ethernet DSR is compiled.  Is this what you want?
168 # endif
169 #endif
170 }
171
172
173 // The deliver function (ex-DSR)  handles the ethernet [logical] processing
174 static void
175 pcnet_deliver(struct eth_drv_sc *sc)
176 {
177     struct pcnet_priv_data *cpd =
178         (struct pcnet_priv_data *)sc->driver_private;
179
180     DEBUG_FUNCTION();
181
182     // Service the interrupt:
183     pcnet_poll(sc);
184     // Allow interrupts to happen again
185     cyg_drv_interrupt_unmask(cpd->interrupt);
186 }
187
188 static int
189 pcnet_int_vector(struct eth_drv_sc *sc)
190 {
191     struct pcnet_priv_data *cpd =
192         (struct pcnet_priv_data *)sc->driver_private;
193
194     return (cpd->interrupt);
195 }
196
197 // ------------------------------------------------------------------------
198 // Memory management
199 //
200 // Simply carve off from the front of the PCI mapped window into real memory
201 static cyg_uint32 pcnet_heap_size;
202 static cyg_uint8 *pcnet_heap_base;
203 static cyg_uint8 *pcnet_heap_free;
204
205 static void*
206 pciwindow_mem_alloc(int size)
207 {
208     void *p_memory;
209     int _size = size;
210
211     CYG_ASSERT(
212         (CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE <= (int)pcnet_heap_free)
213         &&
214         ((CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE + 
215           CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE) > (int)pcnet_heap_free)
216         &&
217         (0 < pcnet_heap_size)
218         &&
219         (CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE >= pcnet_heap_size)
220         &&
221         (CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE == (int)pcnet_heap_base),
222         "Heap variables corrupted" );
223
224     p_memory = (void *)0;
225     size = (size + 3) & ~3;
226     if ( (pcnet_heap_free+size) < (pcnet_heap_base+pcnet_heap_size) ) {
227         cyg_uint32 *p;
228         p_memory = (void *)pcnet_heap_free;
229         pcnet_heap_free += size;
230         for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )
231             *p++ = 0;
232     }
233
234 #if DEBUG & 9
235     db_printf("Allocated %d bytes at 0x%08x\n", size, p_memory);
236 #endif
237
238     return p_memory;
239 }
240
241 static cyg_pci_match_func find_pcnet_match_func;
242
243 static cyg_bool
244 find_pcnet_match_func( cyg_uint16 v, cyg_uint16 d, cyg_uint32 c, void *p )
245 {
246 #if DEBUG & 9
247     db_printf("PCI match vendor 0x%04x device 0x%04x\n", v, d);
248 #endif
249     return (0x1022 == v) && (0x2000 == d);
250 }
251
252 static int
253 pci_init_find_pcnet( void )
254 {
255     cyg_pci_device_id devid;
256     cyg_pci_device dev_info;
257     cyg_uint16 cmd;
258     int device_index;
259     int found_devices = 0;
260
261     DEBUG_FUNCTION();
262
263 #ifdef CYGARC_UNCACHED_ADDRESS
264     CYG_ASSERT( CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) ==
265                 CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE,
266       "PCI window configured does not match PCI memory section base" );
267 #else
268     CYG_ASSERT( (CYG_ADDRWORD)CYGMEM_SECTION_pci_window ==
269                 CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE,
270       "PCI window configured does not match PCI memory section base" );
271 #endif
272     CYG_ASSERT( CYGMEM_SECTION_pci_window_SIZE ==
273                 CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE,
274         "PCI window configured does not match PCI memory section size" );
275
276     if (
277 #ifdef CYGARC_UNCACHED_ADDRESS
278          CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) !=
279 #else
280          (CYG_ADDRWORD)CYGMEM_SECTION_pci_window !=
281 #endif
282          CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE
283          ||
284          CYGMEM_SECTION_pci_window_SIZE !=
285          CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE ) {
286 #if DEBUG & 8
287         db_printf("pci_init_find_pcnets(): PCI window misconfigured\n");
288 #endif
289         return 0;
290     }
291
292     // First initialize the heap in PCI window'd memory
293     pcnet_heap_size = CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE;
294     pcnet_heap_base = (cyg_uint8 *)CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE;
295     pcnet_heap_free = pcnet_heap_base;
296 #if DEBUG & 9
297     db_printf("pcimem : 0x%08x size: 0x%08x\n", pcnet_heap_base, pcnet_heap_size);
298 #endif
299
300     cyg_pci_init();
301 #if DEBUG & 8
302     db_printf("Finished cyg_pci_init();\n");
303 #endif
304
305     devid = CYG_PCI_NULL_DEVID;
306
307     for (device_index = 0; 
308          device_index < CYGNUM_DEVS_ETH_AMD_PCNET_DEV_COUNT;
309          device_index++) {
310         struct pcnet_priv_data* cpd = pcnet_priv_array[device_index];
311
312         cpd->index = device_index;
313
314         // See above for find_pcnet_match_func - it selects any of several
315         // variants.  This is necessary in case we have multiple mixed-type
316         // devices on one board in arbitrary orders.
317         if (cyg_pci_find_matching( &find_pcnet_match_func, NULL, &devid )) {
318 #if DEBUG & 8
319             db_printf("eth%d = pcnet\n", device_index);
320 #endif
321             cyg_pci_get_device_info(devid, &dev_info);
322
323             cpd->interrupt_handle = 0; // Flag not attached.
324             if (cyg_pci_translate_interrupt(&dev_info, &cpd->interrupt)) {
325 #if DEBUG & 8
326                 db_printf(" Wired to HAL vector %d\n", cpd->interrupt);
327 #endif
328                 cyg_drv_interrupt_create(
329                     cpd->interrupt,
330                     1,                  // Priority - unused
331                     (cyg_addrword_t)cpd,// Data item passed to ISR & DSR
332                     pcnet_isr,          // ISR
333                     pcnet_dsr,          // DSR
334                     &cpd->interrupt_handle, // handle to intr obj
335                     &cpd->interrupt_object ); // space for int obj
336
337                 cyg_drv_interrupt_attach(cpd->interrupt_handle);
338
339                 // Don't unmask the interrupt yet, that could get us into a
340                 // race.
341             }
342             else {
343                 cpd->interrupt = 0;
344 #if DEBUG & 8
345                 db_printf(" Does not generate interrupts.\n");
346 #endif
347             }
348
349             if (cyg_pci_configure_device(&dev_info)) {
350 #if DEBUG & 8
351                 int i;
352                 db_printf("Found device on bus %d, devfn 0x%02x:\n",
353                           CYG_PCI_DEV_GET_BUS(devid),
354                           CYG_PCI_DEV_GET_DEVFN(devid));
355
356                 if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) {
357                     db_printf(" Note that board is active. Probed"
358                               " sizes and CPU addresses invalid!\n");
359                 }
360                 db_printf(" Vendor    0x%04x", dev_info.vendor);
361                 db_printf("\n Device    0x%04x", dev_info.device);
362                 db_printf("\n Command   0x%04x, Status 0x%04x\n",
363                           dev_info.command, dev_info.status);
364                 
365                 db_printf(" Class/Rev 0x%08x", dev_info.class_rev);
366                 db_printf("\n Header 0x%02x\n", dev_info.header_type);
367
368                 db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n",
369                           dev_info.header.normal.sub_vendor, 
370                           dev_info.header.normal.sub_id);
371
372                 for(i = 0; i < CYG_PCI_MAX_BAR; i++) {
373                     db_printf(" BAR[%d]    0x%08x /", i, dev_info.base_address[i]);
374                     db_printf(" probed size 0x%08x / CPU addr 0x%08x\n",
375                               dev_info.base_size[i], dev_info.base_map[i]);
376                 }
377                 db_printf(" eth%d configured\n", device_index);
378 #endif
379                 found_devices++;
380                 cpd->found = 1;
381                 cpd->active = 0;
382                 cpd->devid = devid;
383                 cpd->base = (unsigned char*) dev_info.base_map[0];
384 #if DEBUG & 8
385                 db_printf(" I/O address = 0x%08x\n", cpd->base);
386 #endif
387
388                 // Don't use cyg_pci_set_device_info since it clears
389                 // some of the fields we want to print out below.
390                 cyg_pci_read_config_uint16(dev_info.devid,
391                                            CYG_PCI_CFG_COMMAND, &cmd);
392                 cmd |= (CYG_PCI_CFG_COMMAND_IO         // enable I/O space
393                         | CYG_PCI_CFG_COMMAND_MEMORY   // enable memory space
394                         | CYG_PCI_CFG_COMMAND_MASTER); // enable bus master
395                 cyg_pci_write_config_uint16(dev_info.devid,
396                                             CYG_PCI_CFG_COMMAND, cmd);
397
398                 // This is the indicator for "uses an interrupt"
399                 if (cpd->interrupt_handle != 0) {
400                     cyg_drv_interrupt_acknowledge(cpd->interrupt);
401                     cyg_drv_interrupt_unmask(cpd->interrupt);
402 #if DEBUG & 8
403                     db_printf(" Enabled interrupt %d\n", cpd->interrupt);
404 #endif
405                 }
406 #if DEBUG & 8
407                 db_printf(" **** Device enabled for I/O and Memory "
408                             "and Bus Master\n");
409 #endif
410             }
411             else {
412                 cpd->found = 0;
413                 cpd->active = 0;
414 #if DEBUG & 8
415                 db_printf("Failed to configure device %d\n", device_index);
416 #endif
417             }
418         }
419         else {
420             cpd->found = 0;
421             cpd->active = 0;
422 #if DEBUG & 8
423             db_printf("eth%d not found\n", device_index);
424 #endif
425         }
426     }
427
428     if (0 == found_devices)
429         return 0;
430
431     return 1;
432 }
433
434
435 static bool 
436 amd_pcnet_init(struct cyg_netdevtab_entry *tab)
437 {
438     static int initialized = 0; // only probe PCI et al *once*
439     struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
440     struct pcnet_priv_data *cpd =
441         (struct pcnet_priv_data *)sc->driver_private;
442     cyg_uint16 val;
443     cyg_uint32 b;
444     cyg_uint8* p;
445     cyg_uint8* d;
446     cyg_uint8* init_table;
447     int i;
448
449     DEBUG_FUNCTION();
450
451
452     if ( 0 == initialized++ ) {
453         // then this is the first time ever:
454         if ( ! pci_init_find_pcnet() ) {
455 #if DEBUG & 8
456             db_printf( "pci_init_find_pcnet failed" );
457 #endif
458             return false;
459         }
460     }
461
462     // If this device is not present, exit
463     if (0 == cpd->found)
464         return 0;
465
466     cpd->txbusy = 0;
467
468 #if DEBUG & 8
469     db_printf("PCNet at base 0x%08x, EEPROM key 0x%04x\n",
470                 cpd->base, _SU16(cpd->base, PCNET_IO_ID));
471 #endif
472
473 #if 0
474     // FIXME: Doesn't work with non-conforming EEPROMS
475     if (PCNET_IO_ID_KEY != _SU16(cpd->base, PCNET_IO_ID) ) {
476         db_printf("PCNet EPROM key not found\n");
477         return false;
478     }
479 #endif
480
481 #if DEBUG & 9
482     db_printf("pcimem : %08x size: %08x\n", pcnet_heap_base, pcnet_heap_size);
483 #endif
484
485     // Prepare ESA
486     if (!cpd->hardwired_esa) {
487         // Use the address from the serial EEPROM
488         p = cpd->base + PCNET_IO_EEPROM;
489         for (i = 0; i < 6; i++)
490             cpd->esa[i] = *p++;
491     }
492 #if DEBUG & 9
493     db_printf("PCNET - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
494                 (cpd->hardwired_esa) ? "static" : "eeprom",
495                 cpd->esa[0], cpd->esa[1], cpd->esa[2],
496                 cpd->esa[3], cpd->esa[4], cpd->esa[5] );
497 #endif
498
499 #ifdef CYGSEM_DEVS_ETH_AMD_PCNET_FORCE_10MBPS
500     if (get_reg(sc,PCNET_ANR_AAR) & PCNET_ANR_AAR_100) {
501         cyg_uint16 anr;
502         int loop;
503
504 #if DEBUG & 9
505         db_printf("%s: Forcing 10Mbps negotiation\n", __FUNCTION__);
506 #endif
507         // adjust speed/duplex auto-negotiation mask to clear 100Mbps bits
508         anr = get_reg(sc,PCNET_ANR_AAR);
509         anr &= ~PCNET_ANR_AAR_100;
510         put_reg(sc,PCNET_ANR_AAR,anr);
511         // renegotiate
512         anr = get_reg(sc,PCNET_ANR_PHYCTRL);
513         anr |= PCNET_ANR_PHYCTRL_RENEGOTIATE;
514         put_reg(sc,PCNET_ANR_PHYCTRL,anr);
515         loop = 100000;
516         while (loop>0 && !(get_reg(sc,PCNET_ANR_PHYSTAT) & PCNET_ANR_PHYSTAT_AUTONEG_COMP))
517                 loop--;
518 #if DEBUG & 9
519         db_printf("ANR0: %04x\n",get_reg(sc,PCNET_ANR_PHYCTRL));
520         db_printf("ANR1: %04x\n",get_reg(sc,PCNET_ANR_PHYSTAT));
521         db_printf("ANR4: %04x\n",get_reg(sc,PCNET_ANR_AAR));
522 #endif
523     }
524 #endif
525
526     // Prepare RX and TX rings
527     p = cpd->rx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->rx_ring_log_cnt)*PCNET_RD_SIZE));
528     memset(cpd->rx_ring,0,(1<<cpd->rx_ring_log_cnt)*PCNET_RD_SIZE);
529
530     d = cpd->rx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->rx_ring_cnt));
531     memset(cpd->rx_buffers,0,_BUF_SIZE*cpd->rx_ring_cnt);
532
533     for (i = 0; i < cpd->rx_ring_cnt; i++) {
534         HAL_PCI_CPU_TO_BUS(d, b);
535         _SU32(p, PCNET_RD_PTR) = (b & PCNET_RD_PTR_MASK) | PCNET_RD_PTR_OWN;
536         _SU16(p, PCNET_RD_BLEN) = (-_BUF_SIZE);
537         p += PCNET_RD_SIZE;
538         d += _BUF_SIZE;
539     }
540     cpd->rx_ring_next = 0;
541
542     p = cpd->tx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->tx_ring_log_cnt)*PCNET_TD_SIZE));
543     memset(cpd->tx_ring,0,(1<<cpd->tx_ring_log_cnt)*PCNET_TD_SIZE);
544
545     d = cpd->tx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->tx_ring_cnt));
546     for (i = 0; i < cpd->tx_ring_cnt; i++) {
547         HAL_PCI_CPU_TO_BUS(d, b);
548         _SU32(p, PCNET_RD_PTR) = b & PCNET_TD_PTR_MASK;
549         p += PCNET_TD_SIZE;
550         d += _BUF_SIZE;
551     }
552     cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
553
554     // Initialization table
555     init_table = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(PCNET_IB_SIZE));
556     _SU16(init_table, PCNET_IB_MODE) = 0x0000;
557     for (i = 0; i < 6; i++)
558         _SU8(init_table, PCNET_IB_PADR0+i) = cpd->esa[i];
559     for (i = 0; i < 8; i++)
560         _SU8(init_table, PCNET_IB_LADRF0+i) = 0;
561     
562     HAL_PCI_CPU_TO_BUS(cpd->rx_ring, b);
563     _SU32(init_table, PCNET_IB_RDRA) = ((b & PCNET_IB_RDRA_PTR_mask)
564                                         | (cpd->rx_ring_log_cnt << PCNET_IB_RDRA_CNT_shift));
565     HAL_PCI_CPU_TO_BUS(cpd->tx_ring, b);
566     _SU32(init_table, PCNET_IB_TDRA) = ((b & PCNET_IB_TDRA_PTR_mask)
567                                         | (cpd->tx_ring_log_cnt << PCNET_IB_TDRA_CNT_shift));
568
569 #if DEBUG & 9
570     db_printf("Loading up PCNet controller from table at 0x%08x\n", init_table);
571     db_printf(" Mode 0x%04x\n", _SU16(init_table, PCNET_IB_MODE));
572     db_printf(" PADR %02x:%02x:%02x:%02x:%02x:%02x ",
573                 _SU8(init_table, PCNET_IB_PADR0+0), _SU8(init_table, PCNET_IB_PADR0+1),
574                 _SU8(init_table, PCNET_IB_PADR0+2), _SU8(init_table, PCNET_IB_PADR0+3),
575                 _SU8(init_table, PCNET_IB_PADR0+4), _SU8(init_table, PCNET_IB_PADR0+5));
576     db_printf("LADR %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
577                 _SU8(init_table, PCNET_IB_LADRF0+0), _SU8(init_table, PCNET_IB_LADRF0+1),
578                 _SU8(init_table, PCNET_IB_LADRF0+2), _SU8(init_table, PCNET_IB_LADRF0+3),
579                 _SU8(init_table, PCNET_IB_LADRF0+4), _SU8(init_table, PCNET_IB_LADRF0+5),
580                 _SU8(init_table, PCNET_IB_LADRF0+5), _SU8(init_table, PCNET_IB_LADRF0+7));
581     db_printf(" RX 0x%08x (len %d) TX 0x%08x (len %d)\n",
582                 _SU32(init_table, PCNET_IB_RDRA) & 0x1fffffff,
583                 (_SU32(init_table, PCNET_IB_RDRA) >> PCNET_IB_RDRA_CNT_shift) & 7,
584                 _SU32(init_table, PCNET_IB_TDRA) & 0x1fffffff,
585                 (_SU32(init_table, PCNET_IB_TDRA) >> PCNET_IB_TDRA_CNT_shift) & 7);
586 #endif
587
588     // Reset chip
589     HAL_PCI_IO_READ_UINT16(cpd->base+PCNET_IO_RESET, val);
590
591     // Load up chip with buffers.
592     // Note: There is a 16M limit on the addresses used by the driver
593     // since the top 8 bits of the init_table address is appended to
594     // all other addresses used by the controller.
595     HAL_PCI_CPU_TO_BUS(init_table, b);
596     put_reg(sc, PCNET_CSR_IBA0, (b >>  0) & 0xffff);
597     put_reg(sc, PCNET_CSR_IBA1, (b >> 16) & 0xffff);
598     // Disable automatic TX polling (_send will force a poll), pad
599     // XT frames to legal length, mask status interrupts.
600     put_reg(sc, PCNET_CSR_TFC, (PCNET_CSR_TFC_TXDPOLL | PCNET_CSR_TFC_APAD_XMT
601                                 | PCNET_CSR_TFC_MFCOM | PCNET_CSR_TFC_RCVCCOM
602                                 | PCNET_CSR_TFC_TXSTRTM));
603     // Recover after TX FIFO underflow
604     put_reg(sc, PCNET_CSR_IM, PCNET_CSR_IM_DXSUFLO);
605     // Initialize controller - load up init_table
606     put_reg(sc, PCNET_CSR_CSCR, PCNET_CSR_CSCR_INIT);
607     while (0 == (get_reg(sc, PCNET_CSR_CSCR) & PCNET_CSR_CSCR_IDON));
608
609     // Stop controller
610     put_reg(sc, PCNET_CSR_CSCR, PCNET_CSR_CSCR_STOP);
611
612 #if DEBUG & 9
613     db_printf("PCNet controller state is now:\n");
614     db_printf(" Mode 0x%04x  TFC 0x%04x\n", _SU16(init_table, PCNET_IB_MODE), get_reg(sc, PCNET_CSR_TFC));
615     db_printf(" PADR %04x:%04x:%04x ",
616                 get_reg(sc, PCNET_CSR_PAR0),
617                 get_reg(sc, PCNET_CSR_PAR1),
618                 get_reg(sc, PCNET_CSR_PAR2));
619     db_printf("LADR %04x:%04x:%04x:%04x\n",
620                 get_reg(sc, PCNET_CSR_LAR0),
621                 get_reg(sc, PCNET_CSR_LAR1),
622                 get_reg(sc, PCNET_CSR_LAR2),
623                 get_reg(sc, PCNET_CSR_LAR3));
624     db_printf(" RX 0x%04x%04x (len 0x%04x) TX 0x%04x%04x (len 0x%04x)\n",
625                 get_reg(sc, PCNET_CSR_BARRU), get_reg(sc, PCNET_CSR_BARRL), 
626                 get_reg(sc, PCNET_CSR_RRLEN),
627                 get_reg(sc, PCNET_CSR_BATRU), get_reg(sc, PCNET_CSR_BATRL), 
628                 get_reg(sc, PCNET_CSR_TRLEN));
629
630     val = get_reg(sc, PCNET_CSR_ID_LO);
631     db_printf("PCnet ID 0x%04x (%s) ",
632                 val, 
633                 (0x5003 == val) ? "Am79C973" : (0x7003 == val) ? "Am79C975" : "Unknown");
634     val = get_reg(sc, PCNET_CSR_ID_HI);
635     db_printf("Part IDU 0x%03x Silicon rev %d\n",
636                 val & 0x0fff, (val >> 12) & 0xf);
637 #endif
638
639     // and record the net dev pointer
640     cpd->ndp = (void *)tab;
641
642     // Start controller, but put it in suspended mode
643     put_reg(sc, PCNET_CSR_CSCR, PCNET_CSR_CSCR_STOP);
644     put_reg(sc, PCNET_CSR_CSCR, (PCNET_CSR_CSCR_IENA | PCNET_CSR_CSCR_STRT));
645     i = 0;
646     while (0 == (PCNET_CSR_CSCR_STRT & get_reg(sc, PCNET_CSR_CSCR))) {
647         CYGACC_CALL_IF_DELAY_US(1000);
648         put_reg(sc, PCNET_CSR_CSCR, (PCNET_CSR_CSCR_IENA | PCNET_CSR_CSCR_STRT));
649         if (i++ == 1000) {
650 #if DEBUG & 9
651             db_printf("Failed to start the controller\n");
652 #endif
653             return false;
654         }
655     }
656
657     val = get_reg(sc, PCNET_CSR_ECI);
658     val |= PCNET_CSR_ECI_SPND;
659     put_reg(sc, PCNET_CSR_ECI, val);
660     // Wait for device to suspend
661     do {
662         val = get_reg(sc, PCNET_CSR_ECI);
663     } while (0 == (val & PCNET_CSR_ECI_SPND));
664     cpd->active = 0;
665
666     // Initialize upper level driver
667     (sc->funs->eth_drv->init)(sc, cpd->esa);
668
669 #if DEBUG & 9
670     db_printf("Done\n");
671 #endif
672     return true;
673 }
674
675 static void
676 pcnet_stop(struct eth_drv_sc *sc)
677 {
678     cyg_uint16 reg;
679     struct pcnet_priv_data *cpd =
680         (struct pcnet_priv_data *)sc->driver_private;
681
682     DEBUG_FUNCTION();
683     
684     reg = get_reg(sc, PCNET_CSR_ECI);
685     reg |= PCNET_CSR_ECI_SPND;
686     put_reg(sc, PCNET_CSR_ECI, reg);
687     // Wait for device to suspend
688     do {
689         reg = get_reg(sc, PCNET_CSR_ECI);
690     } while (0 == (reg & PCNET_CSR_ECI_SPND));
691     cpd->active = 0;
692 }
693
694 //
695 // This function is called to "start up" the interface.  It may be called
696 // multiple times, even when the hardware is already running.  It will be
697 // called whenever something "hardware oriented" changes and should leave
698 // the hardware ready to send/receive packets.
699 //
700 static void
701 pcnet_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
702 {
703     cyg_uint16 reg;
704     struct pcnet_priv_data *cpd =
705         (struct pcnet_priv_data *)sc->driver_private;
706 #ifdef CYGPKG_NET
707     struct ifnet *ifp = &sc->sc_arpcom.ac_if;
708 #endif
709     DEBUG_FUNCTION();
710
711     // If device is already active, suspend it
712     if (cpd->active) {
713         reg = get_reg(sc, PCNET_CSR_ECI);
714         reg |= PCNET_CSR_ECI_SPND;
715         put_reg(sc, PCNET_CSR_ECI, reg);
716         // Wait for device to suspend
717         do {
718             reg = get_reg(sc, PCNET_CSR_ECI);
719         } while (0 == (reg & PCNET_CSR_ECI_SPND));
720         cpd->active = 0;
721     }
722
723 #ifdef CYGPKG_NET
724     if (( 0
725 #ifdef ETH_DRV_FLAGS_PROMISC_MODE
726          != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
727 #endif
728         ) || (ifp->if_flags & IFF_PROMISC)
729         ) {
730         // Then we select promiscuous mode.
731         cyg_uint16 rcr;
732         rcr = get_reg(sc, PCNET_CSR_MODE );
733         rcr |= PCNET_CSR_MODE_PROM;
734         put_reg(sc, PCNET_CSR_MODE, rcr );
735     }
736 #endif
737
738     // Unsuspend the device
739     reg = get_reg(sc, PCNET_CSR_ECI);
740     reg &= ~PCNET_CSR_ECI_SPND;
741     put_reg(sc, PCNET_CSR_ECI, reg);
742     cpd->active = 1;
743 }
744
745 //
746 // This routine is called to perform special "control" opertions
747 //
748 static int
749 pcnet_control(struct eth_drv_sc *sc, unsigned long key,
750                void *data, int data_length)
751 {
752     cyg_uint8 *esa = (cyg_uint8 *)data;
753     int i, res;
754     cyg_uint16 reg;
755     struct pcnet_priv_data *cpd =
756         (struct pcnet_priv_data *)sc->driver_private;
757     cyg_bool was_active = cpd->active;
758
759     DEBUG_FUNCTION();
760
761     // If device is already active, suspend it
762     if (cpd->active) {
763         reg = get_reg(sc, PCNET_CSR_ECI);
764         reg |= PCNET_CSR_ECI_SPND;
765         put_reg(sc, PCNET_CSR_ECI, reg);
766         // Wait for device to suspend
767         do {
768             reg = get_reg(sc, PCNET_CSR_ECI);
769         } while (0 == (reg & PCNET_CSR_ECI_SPND));
770         cpd->active = 0;
771     }
772
773     res = 0;                            // expect success
774     switch (key) {
775     case ETH_DRV_SET_MAC_ADDRESS:
776 #if 9 & DEBUG
777         db_printf("PCNET - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
778                 esa[0], esa[1], esa[2], esa[3], esa[4], esa[5] );
779 #endif // DEBUG
780
781         for ( i = 0; i < sizeof(cpd->esa);  i++ )
782             cpd->esa[i] = esa[i];
783         for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
784             reg = cpd->esa[i] | (cpd->esa[i+1] << 8);
785             put_reg(sc, PCNET_CSR_PAR0+i/2, reg );
786         }
787         break;
788
789 #ifdef ETH_DRV_GET_MAC_ADDRESS
790     case ETH_DRV_GET_MAC_ADDRESS:
791         // Extract the MAC address that is in the chip, and tell the
792         // system about it.
793         for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
794             cyg_uint16 z = get_reg(sc, PCNET_CSR_PAR0+i/2 );
795             esa[i] =   (cyg_uint8)(0xff & z);
796             esa[i+1] = (cyg_uint8)(0xff & (z >> 8));
797         }
798         break;
799 #endif
800
801 #ifdef ETH_DRV_GET_IF_STATS_UD
802     case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
803 #endif
804         // drop through
805 #ifdef ETH_DRV_GET_IF_STATS
806     case ETH_DRV_GET_IF_STATS:
807 #endif
808
809 #if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
810     {
811         cyg_uint16 anr;
812         struct ether_drv_stats *p = (struct ether_drv_stats *)data;
813         // Chipset entry is no longer supported; RFC1573.
814         for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
815             p->snmp_chipset[i] = 0;
816
817         // This perhaps should be a config opt, so you can make up your own
818         // description, or supply it from the instantiation.
819         strcpy( p->description, "AMD PCNet" );
820         // CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
821
822         anr = get_reg(sc, PCNET_ANR_PHYSTAT);
823         if ((anr & PCNET_ANR_PHYSTAT_LINK) == 0) {
824             p->operational = 2;         // LINK DOWN
825             p->duplex = 1;              // UNKNOWN
826             p->speed = 0;
827         }
828         else {
829             p->operational = 3;         // LINK UP
830             anr = get_reg(sc, PCNET_ANR_PHYCTRL);
831
832             if (anr & PCNET_ANR_PHYCTRL_DUPLEX)
833                 p->duplex = 3;              // 3 = DUPLEX
834             else
835                 p->duplex = 2;              // 2 = SIMPLEX
836             p->speed = (anr & PCNET_ANR_PHYCTRL_100MBPS) ? 100 * 1000000 : 10 * 1000000;
837         }
838
839 #if FIXME
840 #ifdef KEEP_STATISTICS
841         {
842             struct amd_pcnet_stats *ps = &(cpd->stats);
843
844             // Admit to it...
845             p->supports_dot3        = true;
846
847             p->tx_good              = ps->tx_good             ;
848             p->tx_max_collisions    = ps->tx_max_collisions   ;
849             p->tx_late_collisions   = ps->tx_late_collisions  ;
850             p->tx_underrun          = ps->tx_underrun         ;
851             p->tx_carrier_loss      = ps->tx_carrier_loss     ;
852             p->tx_deferred          = ps->tx_deferred         ;
853             p->tx_sqetesterrors     = ps->tx_sqetesterrors    ;
854             p->tx_single_collisions = ps->tx_single_collisions;
855             p->tx_mult_collisions   = ps->tx_mult_collisions  ;
856             p->tx_total_collisions  = ps->tx_total_collisions ;
857             p->rx_good              = ps->rx_good             ;
858             p->rx_crc_errors        = ps->rx_crc_errors       ;
859             p->rx_align_errors      = ps->rx_align_errors     ;
860             p->rx_resource_errors   = ps->rx_resource_errors  ;
861             p->rx_overrun_errors    = ps->rx_overrun_errors   ;
862             p->rx_collisions        = ps->rx_collisions       ;
863             p->rx_short_frames      = ps->rx_short_frames     ;
864             p->rx_too_long_frames   = ps->rx_too_long_frames  ;
865             p->rx_symbol_errors     = ps->rx_symbol_errors    ;
866         
867             p->interrupts           = ps->interrupts          ;
868             p->rx_count             = ps->rx_count            ;
869             p->rx_deliver           = ps->rx_deliver          ;
870             p->rx_resource          = ps->rx_resource         ;
871             p->rx_restart           = ps->rx_restart          ;
872             p->tx_count             = ps->tx_count            ;
873             p->tx_complete          = ps->tx_complete         ;
874             p->tx_dropped           = ps->tx_dropped          ;
875         }
876 #endif // KEEP_STATISTICS
877 #endif // FIXME
878
879         p->tx_queue_len = 1;
880         break;
881     }
882 #endif
883     default:
884         res = 1;
885         break;
886     }
887
888     // Restore controller state
889     if (was_active) {
890         // Unsuspend the device
891         reg = get_reg(sc, PCNET_CSR_ECI);
892         reg &= ~PCNET_CSR_ECI_SPND;
893         put_reg(sc, PCNET_CSR_ECI, reg);
894     }
895
896     return res;
897 }
898
899 //
900 // This routine is called to see if it is possible to send another packet.
901 // It will return non-zero if a transmit is possible, zero otherwise.
902 //
903 static int
904 pcnet_can_send(struct eth_drv_sc *sc)
905 {
906     struct pcnet_priv_data *cpd =
907         (struct pcnet_priv_data *)sc->driver_private;
908     cyg_uint16 stat;
909
910     DEBUG_FUNCTION();
911
912     stat = get_reg(sc, PCNET_ANR_PHYSTAT);
913     if ((stat & PCNET_ANR_PHYSTAT_LINK) == 0) {
914         return 0;                       // Link not connected
915     }
916
917     return (0 == cpd->txbusy);
918 }
919
920 //
921 // This routine is called to send data to the hardware.
922 static void 
923 pcnet_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, 
924             int total_len, unsigned long key)
925 {
926     struct pcnet_priv_data *cpd = 
927         (struct pcnet_priv_data *)sc->driver_private;
928     int i, len, plen, ring_entry;
929
930     cyg_uint8* sdata = NULL;
931     cyg_uint8 *d, *buf, *txd;
932     cyg_uint16 ints;
933     cyg_uint32 b;
934
935     DEBUG_FUNCTION();
936
937     INCR_STAT( tx_count );
938
939     cpd->txbusy = 1;
940     cpd->txkey = key;
941
942     // Find packet length
943     plen = 0;
944     for (i = 0;  i < sg_len;  i++)
945         plen += sg_list[i].len;
946
947     CYG_ASSERT( plen == total_len, "sg data length mismatch" );
948     
949     // Get next TX descriptor
950     ring_entry = cpd->tx_ring_free;
951     do {
952         if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {
953             // Is this a dead end? Probably is.
954 #if DEBUG & 1
955             db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );
956 #endif
957             continue;
958         }
959
960         cpd->tx_ring_free++;
961         cpd->tx_ring_owned++;
962         if (cpd->tx_ring_free == cpd->tx_ring_cnt)
963             cpd->tx_ring_free = 0;
964     } while (0);
965
966     txd = cpd->tx_ring + ring_entry*PCNET_TD_SIZE;
967     buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;
968     CYG_ASSERT(0 == (_SU32(txd, PCNET_TD_PTR) & PCNET_TD_PTR_OWN),
969                "TX descriptor not free");
970
971 #if DEBUG & 4
972     db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",
973                 txd, buf);
974 #endif
975
976     // Put data into buffer
977     d = buf;
978     for (i = 0;  i < sg_len;  i++) {
979         sdata = (cyg_uint8 *)sg_list[i].buf;
980         len = sg_list[i].len;
981
982         CYG_ASSERT( sdata, "No sg data pointer here" );
983         while(len--)
984             *d++ = *sdata++;
985     }
986     CYG_ASSERT( sdata, "No sg data pointer outside" );
987
988 #if DEBUG & 1
989     db_printf("CSCR %04x\n", get_reg(sc, PCNET_CSR_CSCR));
990 #endif
991     _SU16(txd, PCNET_TD_LEN) = (-plen);
992     _SU16(txd, PCNET_TD_MISC) = 0;
993     HAL_PCI_CPU_TO_BUS(buf, b);
994     _SU32(txd, PCNET_TD_PTR) = ((b & PCNET_TD_PTR_MASK)
995                                 | PCNET_TD_PTR_OWN | PCNET_TD_PTR_STP | PCNET_TD_PTR_ENP);
996
997 #if DEBUG & 1
998     db_printf("Last TX: LEN %04x MISC %04x PTR %08x\n", 
999                 _SU16(txd, PCNET_TD_LEN),
1000                 _SU16(txd, PCNET_TD_MISC),
1001                 _SU32(txd, PCNET_TD_PTR));
1002 #endif
1003
1004     // This delay seems to be necessary on some platforms 
1005     // (Malta 5kc for example).
1006     // Why it is needed is not clear, but removing it or
1007     // reducing it cause transmission failures in RedBoot (at least).
1008     CYGACC_CALL_IF_DELAY_US(100);
1009     
1010
1011     // Set transmit demand
1012     ints = get_reg(sc, PCNET_CSR_CSCR);
1013     ints &= PCNET_CSR_CSCR_EV_MASK;
1014     ints |= PCNET_CSR_CSCR_TDMD;
1015     put_reg(sc, PCNET_CSR_CSCR, ints);
1016
1017 #if DEBUG & 1
1018     ints = get_reg(sc, PCNET_CSR_CSCR);
1019     db_printf("%s:END: ints at TX: 0x%04x\n", __FUNCTION__, ints);
1020 #endif
1021
1022     // This is another mystery delay like the one above. This one is
1023     // even stranger, since waiting here at the _end_ of the function
1024     // should have no effect.
1025     CYGACC_CALL_IF_DELAY_US(200);
1026 }
1027
1028 static void
1029 pcnet_TxEvent(struct eth_drv_sc *sc, int stat)
1030 {
1031      struct pcnet_priv_data *cpd =
1032         (struct pcnet_priv_data *)sc->driver_private;
1033     int success = 1;
1034     cyg_uint8 *txd;
1035     cyg_uint16 ints;
1036     cyg_uint32 pkt_stat;
1037
1038     DEBUG_FUNCTION();
1039
1040     if (0 == cpd->tx_ring_owned) {
1041 #if DEBUG & 1
1042         db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);
1043 #endif
1044         return;
1045     }
1046
1047     INCR_STAT( tx_complete );
1048
1049     txd = cpd->tx_ring + cpd->tx_ring_alloc*PCNET_TD_SIZE;
1050     pkt_stat = _SU32(txd, PCNET_TD_PTR);
1051     if (pkt_stat & PCNET_TD_PTR_OWN) {
1052 #if DEBUG & 1
1053         db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);
1054 #endif
1055         // first dirty ring entry not freed - wtf?
1056     }
1057
1058     if (pkt_stat & PCNET_TD_PTR_ERR) {
1059         // We had an error. Tell the stack.
1060         success = 0;
1061 #if DEBUG & 1
1062         db_printf("%s: TX failure, retrying...\n", __FUNCTION__);
1063 #endif
1064     }
1065
1066     cpd->tx_ring_alloc++;
1067     if (cpd->tx_ring_alloc == cpd->tx_ring_cnt)
1068         cpd->tx_ring_alloc = 0;
1069     cpd->tx_ring_owned--;
1070
1071 #if FIXME
1072 #ifdef KEEP_STATISTICS
1073     {
1074         cyg_uint16 reg;
1075
1076         reg = get_reg( sc, PCNET_CSR_CSCR );
1077         
1078         // Covering each bit in turn...
1079         if ( reg & PCNET_STATUS_TX_UNRN   ) INCR_STAT( tx_underrun );
1080         //if ( reg & PCNET_STATUS_LINK_OK ) INCR_STAT(  );
1081         //if ( reg & PCNET_STATUS_CTR_ROL ) INCR_STAT(  );
1082         //if ( reg & PCNET_STATUS_EXC_DEF ) INCR_STAT(  );
1083         if ( reg & PCNET_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );
1084         if ( reg & PCNET_STATUS_LATCOL    ) INCR_STAT( tx_late_collisions );
1085         //if ( reg & PCNET_STATUS_WAKEUP  ) INCR_STAT(  );
1086         if ( reg & PCNET_STATUS_TX_DEFR   ) INCR_STAT( tx_deferred );
1087         //if ( reg & PCNET_STATUS_LTX_BRD ) INCR_STAT(  );
1088         if ( reg & PCNET_STATUS_SQET      ) INCR_STAT( tx_sqetesterrors );
1089         if ( reg & PCNET_STATUS_16COL     ) INCR_STAT( tx_max_collisions );
1090         //if ( reg & PCNET_STATUS_LTX_MULT) INCR_STAT(  );
1091         if ( reg & PCNET_STATUS_MUL_COL   ) INCR_STAT( tx_mult_collisions );
1092         if ( reg & PCNET_STATUS_SNGL_COL  ) INCR_STAT( tx_single_collisions );
1093         if ( reg & PCNET_STATUS_TX_SUC    ) INCR_STAT( tx_good );
1094
1095         cpd->stats.tx_total_collisions = 
1096             cpd->stats.tx_late_collisions + 
1097             cpd->stats.tx_max_collisions + 
1098             cpd->stats.tx_mult_collisions + 
1099             cpd->stats.tx_single_collisions;
1100
1101         // We do not need to look in the Counter Register (PCNET_COUNTER)
1102         // because it just mimics the info we already have above.
1103     }
1104 #endif // KEEP_STATISTICS
1105 #endif // FIXME
1106
1107     // Ack the TX int which clears the packet from the TX completion
1108     // queue.
1109     ints = get_reg(sc, PCNET_CSR_CSCR);
1110     ints |= PCNET_CSR_CSCR_TINT;
1111     put_reg(sc, PCNET_CSR_CSCR, ints);
1112
1113 #if DEBUG & 4
1114     db_printf("#####Tx packet freed 0x%08x\n", txd );
1115 #endif
1116
1117     if ( cpd->txbusy ) {
1118         cpd->txbusy = 0;
1119         (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);
1120     }
1121 }
1122
1123
1124 //
1125 // This function is called when a packet has been received.  Its job is
1126 // to prepare to unload the packet from the hardware.  Once the length of
1127 // the packet is known, the upper layer of the driver can be told.  When
1128 // the upper layer is ready to unload the packet, the internal function
1129 // 'pcnet_recv' will be called to actually fetch it from the hardware.
1130 //
1131 static void
1132 pcnet_RxEvent(struct eth_drv_sc *sc)
1133 {
1134     struct pcnet_priv_data *cpd = 
1135         (struct pcnet_priv_data *)sc->driver_private;
1136     cyg_uint8 *rxd;
1137     cyg_uint32 rstat;
1138     cyg_uint16 ints, len;
1139
1140     DEBUG_FUNCTION();
1141
1142     ints = get_reg(sc, PCNET_CSR_CSCR);
1143 #if DEBUG & 1
1144     db_printf("RxEvent - CSR: 0x%04x\n", ints);
1145 #endif
1146
1147     while (1) {
1148         // Get state of next (supposedly) full ring entry
1149         cpd->rxpacket = cpd->rx_ring_next;
1150         rxd = cpd->rx_ring + cpd->rxpacket*PCNET_RD_SIZE;
1151         rstat = _SU32(rxd, PCNET_RD_PTR);
1152
1153         // Keep going until we hit an entry that is owned by the
1154         // controller.
1155         if (rstat & PCNET_RD_PTR_OWN) {
1156 #if DEBUG & 1
1157             int i;
1158             for (i = 0; i < cpd->rx_ring_cnt; i++) {
1159                 rxd = cpd->rx_ring + i*PCNET_RD_SIZE;
1160                 rstat = _SU32(rxd, PCNET_RD_PTR);
1161
1162                 if (!(rstat & PCNET_RD_PTR_OWN)) {
1163                     int i;
1164                     cyg_uint32 rstat;
1165                     cyg_uint16 mlen, blen;
1166                     cyg_uint8* rxd;
1167
1168                     db_printf("%s: Inconsistent RX state\n", __FUNCTION__);
1169                     for (i = 0; i < cpd->rx_ring_cnt; i++) {
1170                         rxd = cpd->rx_ring + i*PCNET_RD_SIZE;
1171                 
1172                         rstat = _SU32(rxd, PCNET_RD_PTR);
1173                         blen = _SU16(rxd, PCNET_RD_BLEN);
1174                         mlen = _SU16(rxd, PCNET_RD_MLEN);
1175                         db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
1176                     }
1177                 }
1178             }
1179 #endif
1180             break;
1181         }
1182
1183 #if DEBUG & 4
1184         db_printf("#####Rx packet at index %d\n", cpd->rxpacket);
1185 #endif
1186
1187         // Increment counts
1188         INCR_STAT( rx_count );
1189         cpd->rx_ring_next++;
1190         if (cpd->rx_ring_next == cpd->rx_ring_cnt) cpd->rx_ring_next = 0;
1191
1192         len = _SU16(rxd, PCNET_RD_MLEN);
1193
1194 #ifdef KEEP_STATISTICS
1195         //if ( rstat & PCNET_RD_PTR_FRAM ) INCR_STAT( rx_frame_errors );
1196         //if ( rstat & PCNET_RD_PTR_OFLO ) INCR_STAT(  );
1197         if ( rstat & PCNET_RD_PTR_CRC ) INCR_STAT( rx_crc_errors );
1198         //if ( rstat & PCNET_RD_PTR_BUFF ) INCR_STAT(  );
1199 #endif // KEEP_STATISTICS
1200
1201         if (0 == (rstat & PCNET_RD_PTR_ERR)) {
1202             // It's OK
1203             INCR_STAT( rx_good );
1204
1205 #if DEBUG & 1
1206             db_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);
1207 #endif
1208             // Check for bogusly short packets; can happen in promisc
1209             // mode: Asserted against and checked by upper layer
1210             // driver.
1211 #ifdef CYGPKG_NET
1212             if ( len > sizeof( struct ether_header ) )
1213                 // then it is acceptable; offer the data to the network stack
1214 #endif
1215                 (sc->funs->eth_drv->recv)(sc, len);
1216         } else {
1217             // Not OK for one reason or another...
1218 #if DEBUG & 1
1219             db_printf("RxEvent - No RX bit: stat: 0x%08x, len: 0x%04x\n",
1220                         rstat, len);
1221 #endif
1222         }
1223
1224         // Free packet (clear all status flags, and set OWN)
1225         _SU32(rxd, PCNET_RD_PTR) &= PCNET_RD_PTR_MASK;
1226         _SU32(rxd, PCNET_RD_PTR) |= PCNET_RD_PTR_OWN;
1227     }
1228
1229     // Ack RX interrupt set
1230     ints = get_reg(sc, PCNET_CSR_CSCR);
1231     ints &= PCNET_CSR_CSCR_EV_MASK;
1232     ints |= PCNET_CSR_CSCR_RINT;
1233     put_reg(sc, PCNET_CSR_CSCR, ints);
1234 }
1235
1236 //
1237 // This function is called as a result of the "eth_drv_recv()" call above.
1238 // Its job is to actually fetch data for a packet from the hardware once
1239 // memory buffers have been allocated for the packet.  Note that the buffers
1240 // may come in pieces, using a scatter-gather list.  This allows for more
1241 // efficient processing in the upper layers of the stack.
1242 //
1243 static void
1244 pcnet_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
1245 {
1246     struct pcnet_priv_data *cpd = 
1247         (struct pcnet_priv_data *)sc->driver_private;
1248     int i, mlen=0, plen;
1249     cyg_uint8 *data, *rxd, *buf;
1250
1251     DEBUG_FUNCTION();
1252
1253     rxd = cpd->rx_ring + cpd->rxpacket*PCNET_RD_SIZE;
1254     buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;
1255
1256     INCR_STAT( rx_deliver );
1257
1258     plen = _SU16(rxd, PCNET_RD_MLEN);
1259
1260     for (i = 0;  i < sg_len;  i++) {
1261         data = (cyg_uint8*)sg_list[i].buf;
1262         mlen = sg_list[i].len;
1263
1264 #if DEBUG & 1
1265         db_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);
1266 #endif
1267         if (data) {
1268             while (mlen > 0) {
1269                 *data++ = *buf++;
1270                 mlen--;
1271                 plen--;
1272             }
1273         }
1274     }
1275 }
1276
1277 static void
1278 pcnet_poll(struct eth_drv_sc *sc)
1279 {
1280     cyg_uint16 event;
1281
1282 //  DEBUG_FUNCTION();
1283
1284     while (1) {
1285         // Get the (unmasked) requests
1286         event = get_reg(sc, PCNET_CSR_CSCR);
1287         if (!((PCNET_CSR_CSCR_ERR|PCNET_CSR_CSCR_INTR) & event))
1288             break;
1289
1290         if (event & PCNET_CSR_CSCR_RINT) {
1291             pcnet_RxEvent(sc);
1292         }
1293         else if (event & PCNET_CSR_CSCR_TINT) {
1294             pcnet_TxEvent(sc, event);
1295         } 
1296         else if (event & PCNET_CSR_CSCR_MISS) {
1297 #if DEBUG & 1
1298             int i;
1299             cyg_uint32 rstat;
1300             cyg_uint16 mlen, blen;
1301             cyg_uint8* rxd;
1302             struct pcnet_priv_data *cpd = 
1303                 (struct pcnet_priv_data *)sc->driver_private;
1304
1305             db_printf("%s: Ran out of RX buffers (%04x)\n", __FUNCTION__, event);
1306             for (i = 0; i < cpd->rx_ring_cnt; i++) {
1307                 rxd = cpd->rx_ring + i*PCNET_TD_SIZE;
1308                 
1309                 rstat = _SU32(rxd, PCNET_RD_PTR);
1310                 blen = _SU16(rxd, PCNET_RD_BLEN);
1311                 mlen = _SU16(rxd, PCNET_RD_MLEN);
1312                 db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
1313             }
1314 #endif
1315             event &= PCNET_CSR_CSCR_EV_MASK;
1316             event |= PCNET_CSR_CSCR_MISS;
1317             put_reg(sc, PCNET_CSR_CSCR, event);
1318         }
1319         else {
1320 #if DEBUG & 1
1321             db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);
1322 #endif
1323             put_reg(sc, PCNET_CSR_CSCR, event);
1324         }
1325     }
1326 }
1327
1328 // EOF if_pcnet.c