1 //==========================================================================
5 // Ethernet device driver for AMD PCI Lance (for instance vmWare VLANCE)
6 // compatible controllers
8 //==========================================================================
9 //####ECOSGPLCOPYRIGHTBEGIN####
10 // -------------------------------------------
11 // This file is part of eCos, the Embedded Configurable Operating System.
12 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //####BSDCOPYRIGHTBEGIN####
43 // -------------------------------------------
45 // Portions of this software may have been derived from OpenBSD or other sources,
46 // and are covered by the appropriate copyright disclaimers included herein.
48 // -------------------------------------------
50 //####BSDCOPYRIGHTEND####
51 //==========================================================================
52 //#####DESCRIPTIONBEGIN####
54 // Author(s): jskov, based on lan91cxx driver by hmt & jskov, iz
55 // Contributors: gthomas, jskov, hmt, iz
56 // Date: 2002-07-17, 2003-01-26
58 // Description: hardware driver for AMD Lance PCI (and possibly PCnet)
59 // and wmWare VLANCE ethernet
60 // Notes: The controller is used in its 16bit mode. That means that
61 // all addresses are 24bit only - and that all controller
62 // accessed memory must be within the same 16MB region
63 // (starting at 0 on older controllers).
65 // The KEEP_STATISTICS code is not implemented yet. Look
68 //####DESCRIPTIONEND####
70 //==========================================================================
71 //#####VMWAREDESCRIPTIONBEGIN####
73 // Notes: The vmWare VLACNCE virtual controller does not seem to do
74 // anything about SUSPEND and seems it must be reinitialized after
75 // every STOP. In addition it lacks some registers.
77 // Sometimes, the driver must wait to let Vmware get a tick, to
78 // process the chip initialization and control functions!!!
80 // That's the reason for not patching the PCnet driver
81 // but cloning a special one from it.
84 //####VMWAREDESCRIPTIONEND####
85 //==========================================================================
87 #include <pkgconf/system.h>
88 #include <pkgconf/devs_eth_amd_lancepci.h>
89 #include <pkgconf/io_eth_drivers.h>
91 #include <cyg/infra/cyg_type.h>
92 #include <cyg/hal/hal_arch.h>
93 #include <cyg/hal/hal_intr.h>
94 #include <cyg/infra/cyg_ass.h>
95 #include <cyg/infra/diag.h>
96 #include <cyg/hal/drv_api.h>
97 #include <cyg/hal/hal_if.h> // delays
99 #include <cyg/io/eth/netdev.h>
100 #include <cyg/io/eth/eth_drv.h>
102 #include <pkgconf/net.h>
103 #include <cyg/kernel/kapi.h>
104 #include <net/if.h> // Needed for struct ifnet
105 #include <pkgconf/io_eth_drivers.h>
107 #include CYGHWR_MEMORY_LAYOUT_H
110 #include <cyg/io/pci.h>
112 #error "Need PCI package here"
117 #define _BUF_SIZE 1544
119 #ifdef CYGPKG_INFRA_DEBUG
120 // Then we log, OOI, the number of times we get a bad packet number
121 // from the tx done fifo.
122 int lancepci_txfifo_good = 0;
123 int lancepci_txfifo_bad = 0;
126 #include "amd_lance.h"
128 #include CYGDAT_DEVS_ETH_AMD_LANCEPCI_INL
133 #if defined(CYGPKG_REDBOOT)
135 static void db_printf( char *fmt, ... )
137 extern int start_console(void);
138 extern void end_console(int);
142 old_console = start_console();
143 diag_vprintf( fmt, a );
144 end_console(old_console);
150 #define db_printf diag_printf
155 static struct eth_drv_sc *oursc; //a dummy sc pointer
157 static void lancepci_poll(struct eth_drv_sc *sc);
160 // This ISR is called when the ethernet interrupt occurs
162 lancepci_isr(cyg_vector_t vector, cyg_addrword_t data)
164 struct lancepci_priv_data *cpd = (struct lancepci_priv_data *)data;
168 INCR_STAT( interrupts );
169 cpd->event = get_reg(oursc, LANCE_CSR_CSCR);
170 if (cpd->event & LANCE_CSR_CSCR_TINT)
171 cpd->txbusyh=0; // take care of HW txbusy flag
172 cyg_drv_interrupt_mask(cpd->interrupt);
173 cyg_drv_interrupt_acknowledge(cpd->interrupt);
174 return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR
178 lancepci_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
180 // This conditioning out is necessary because of explicit calls to this
181 // DSR - which would not ever be called in the case of a polled mode
182 // usage ie. in RedBoot.
183 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
184 struct lancepci_priv_data* cpd = (struct lancepci_priv_data *)data;
185 struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->ndp);
186 struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
188 // but here, it must be a *sc:
189 eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
191 # ifndef CYGPKG_REDBOOT
192 # error Empty lancepci ethernet DSR is compiled. Is this what you want?
198 // The deliver function (ex-DSR) handles the ethernet [logical] processing
200 lancepci_deliver(struct eth_drv_sc *sc)
202 struct lancepci_priv_data *cpd =
203 (struct lancepci_priv_data *)sc->driver_private;
207 // Service the interrupt:
209 // Allow interrupts to happen again
210 cyg_drv_interrupt_unmask(cpd->interrupt);
214 lancepci_int_vector(struct eth_drv_sc *sc)
216 struct lancepci_priv_data *cpd =
217 (struct lancepci_priv_data *)sc->driver_private;
219 return (cpd->interrupt);
222 // ------------------------------------------------------------------------
225 // Simply carve off from the front of the PCI mapped window into real memory
226 static cyg_uint32 lancepci_heap_size;
227 static cyg_uint8 *lancepci_heap_base;
228 static cyg_uint8 *lancepci_heap_free;
231 pciwindow_mem_alloc(int size)
237 (CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE <= (int)lancepci_heap_free)
239 ((CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE +
240 CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE) > (int)lancepci_heap_free)
242 (0 < lancepci_heap_size)
244 (CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE >= lancepci_heap_size)
246 (CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE == (int)lancepci_heap_base),
247 "Heap variables corrupted" );
249 p_memory = (void *)0;
250 size = (size + 3) & ~3;
251 if ( (lancepci_heap_free+size) < (lancepci_heap_base+lancepci_heap_size) ) {
253 p_memory = (void *)lancepci_heap_free;
254 lancepci_heap_free += size;
255 for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )
260 db_printf("Allocated %d bytes at 0x%08x\n", size, p_memory);
266 static cyg_pci_match_func find_lancepci_match_func;
269 find_lancepci_match_func( cyg_uint16 v, cyg_uint16 d, cyg_uint32 c, void *p )
272 db_printf("PCI match vendor 0x%04x device 0x%04x\n", v, d);
274 return (0x1022 == v) && (0x2000 == d);
278 pci_init_find_lancepci( void )
280 cyg_pci_device_id devid;
281 cyg_pci_device dev_info;
284 int found_devices = 0;
288 #ifdef CYGARC_UNCACHED_ADDRESS
289 CYG_ASSERT( CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) ==
290 CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE,
291 "PCI window configured does not match PCI memory section base" );
293 CYG_ASSERT( (CYG_ADDRWORD)CYGMEM_SECTION_pci_window ==
294 CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE,
295 "PCI window configured does not match PCI memory section base" );
297 CYG_ASSERT( CYGMEM_SECTION_pci_window_SIZE ==
298 CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE,
299 "PCI window configured does not match PCI memory section size" );
302 #ifdef CYGARC_UNCACHED_ADDRESS
303 CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) !=
305 (CYG_ADDRWORD)CYGMEM_SECTION_pci_window !=
307 (CYG_ADDRWORD)CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE
309 CYGMEM_SECTION_pci_window_SIZE !=
310 CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE ) {
312 db_printf("pci_init_find_lancepci(): PCI window misconfigured\n");
317 // First initialize the heap in PCI window'd memory
318 lancepci_heap_size = CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE;
319 lancepci_heap_base = (cyg_uint8 *)CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE;
320 lancepci_heap_free = lancepci_heap_base;
322 db_printf("pcimem : 0x%08x size: 0x%08x\n", lancepci_heap_base, lancepci_heap_size);
327 db_printf("Finished cyg_pci_init();\n");
330 devid = CYG_PCI_NULL_DEVID;
332 for (device_index = 0;
333 device_index < CYGNUM_DEVS_ETH_AMD_LANCEPCI_DEV_COUNT;
335 struct lancepci_priv_data* cpd = lancepci_priv_array[device_index];
337 cpd->index = device_index;
339 // See above for find_lancepci_match_func - it selects any of several
340 // variants. This is necessary in case we have multiple mixed-type
341 // devices on one board in arbitrary orders.
342 if (cyg_pci_find_matching( &find_lancepci_match_func, NULL, &devid )) {
344 db_printf("eth%d = lancepci\n", device_index);
346 cyg_pci_get_device_info(devid, &dev_info);
348 cpd->interrupt_handle = 0; // Flag not attached.
349 if (cyg_pci_translate_interrupt(&dev_info, &cpd->interrupt)) {
351 db_printf(" Wired to HAL vector %d\n", cpd->interrupt);
353 cyg_drv_interrupt_create(
355 1, // Priority - unused
356 (cyg_addrword_t)cpd,// Data item passed to ISR & DSR
359 &cpd->interrupt_handle, // handle to intr obj
360 &cpd->interrupt_object ); // space for int obj
362 cyg_drv_interrupt_attach(cpd->interrupt_handle);
364 // Don't unmask the interrupt yet, that could get us into a
370 db_printf(" Does not generate interrupts.\n");
374 if (cyg_pci_configure_device(&dev_info)) {
377 db_printf("Found device on bus %d, devfn 0x%02x:\n",
378 CYG_PCI_DEV_GET_BUS(devid),
379 CYG_PCI_DEV_GET_DEVFN(devid));
381 if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) {
382 db_printf(" Note that board is active. Probed"
383 " sizes and CPU addresses invalid!\n");
385 db_printf(" Vendor 0x%04x", dev_info.vendor);
386 db_printf("\n Device 0x%04x", dev_info.device);
387 db_printf("\n Command 0x%04x, Status 0x%04x\n",
388 dev_info.command, dev_info.status);
390 db_printf(" Class/Rev 0x%08x", dev_info.class_rev);
391 db_printf("\n Header 0x%02x\n", dev_info.header_type);
393 db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n",
394 dev_info.header.normal.sub_vendor,
395 dev_info.header.normal.sub_id);
397 for(i = 0; i < CYG_PCI_MAX_BAR; i++) {
398 db_printf(" BAR[%d] 0x%08x /", i, dev_info.base_address[i]);
399 db_printf(" probed size 0x%08x / CPU addr 0x%08x\n",
400 dev_info.base_size[i], dev_info.base_map[i]);
402 db_printf(" eth%d configured\n", device_index);
408 cpd->base = (unsigned char*) dev_info.base_map[0];
410 db_printf(" I/O address = 0x%08x\n", cpd->base);
413 // Don't use cyg_pci_set_device_info since it clears
414 // some of the fields we want to print out below.
415 cyg_pci_read_config_uint16(dev_info.devid,
416 CYG_PCI_CFG_COMMAND, &cmd);
417 cmd |= (CYG_PCI_CFG_COMMAND_IO // enable I/O space
418 | CYG_PCI_CFG_COMMAND_MEMORY // enable memory space
419 | CYG_PCI_CFG_COMMAND_MASTER); // enable bus master
420 cyg_pci_write_config_uint16(dev_info.devid,
421 CYG_PCI_CFG_COMMAND, cmd);
423 // This is the indicator for "uses an interrupt"
424 if (cpd->interrupt_handle != 0) {
425 cyg_drv_interrupt_acknowledge(cpd->interrupt);
426 cyg_drv_interrupt_unmask(cpd->interrupt);
428 db_printf(" Enabled interrupt %d\n", cpd->interrupt);
432 db_printf(" **** Device enabled for I/O and Memory "
440 db_printf("Failed to configure device %d\n", device_index);
448 db_printf("eth%d not found\n", device_index);
453 if (0 == found_devices)
461 amd_lancepci_init(struct cyg_netdevtab_entry *tab)
463 static int initialized = 0; // only probe PCI et al *once*
464 struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
465 struct lancepci_priv_data *cpd =
466 (struct lancepci_priv_data *)sc->driver_private;
475 if ( 0 == initialized++ ) {
476 // then this is the first time ever:
477 if ( ! pci_init_find_lancepci() ) {
479 db_printf( "pci_init_find_lancepci failed" );
485 // If this device is not present, exit
490 db_printf("lancepci at base 0x%08x, EEPROM key 0x%04x\n",
491 cpd->base, _SU16(cpd->base, LANCE_IO_ID));
495 // FIXME: Doesn't work with non-conforming EEPROMS
496 if (LANCE_IO_ID_KEY != _SU16(cpd->base, LANCE_IO_ID) ) {
497 db_printf("Lance EPROM key not found\n");
503 db_printf("pcimem : %08x size: %08x\n", lancepci_heap_base, lancepci_heap_size);
507 if (!cpd->hardwired_esa) {
508 // Don't use the address from the EEPROM for VMware
509 // Use the address that VMware prepares in CSR_PAR registers
510 // if You want to be able to use NAT networking. (iz@elsis.si Feb 27 04)
512 // p = cpd->base + LANCE_IO_EEPROM;
513 // for (i = 0; i < 6; i++)
514 // cpd->esa[i] = *p++;
515 put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
516 for (i = 0; i < sizeof(cpd->esa); i += 2) {
517 cyg_uint16 z = get_reg(sc, LANCE_CSR_PAR0+i/2 );
518 cpd->esa[i] = (cyg_uint8)(0xff & z);
519 cpd->esa[i+1] = (cyg_uint8)(0xff & (z >> 8));
524 db_printf("Lance - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
525 (cpd->hardwired_esa) ? "static" : "eeprom",
526 cpd->esa[0], cpd->esa[1], cpd->esa[2],
527 cpd->esa[3], cpd->esa[4], cpd->esa[5] );
531 // Prepare RX and TX rings
532 p = cpd->rx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->rx_ring_log_cnt)*LANCE_RD_SIZE));
533 memset(cpd->rx_ring,0,(1<<cpd->rx_ring_log_cnt)*LANCE_RD_SIZE);
535 d = cpd->rx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->rx_ring_cnt));
536 memset(cpd->rx_buffers,0,_BUF_SIZE*cpd->rx_ring_cnt);
538 for (i = 0; i < cpd->rx_ring_cnt; i++) {
539 HAL_PCI_CPU_TO_BUS(d, (cyg_uint8 *)b);
540 _SU32(p, LANCE_RD_PTR) = (b & LANCE_RD_PTR_MASK) | LANCE_RD_PTR_OWN;
541 _SU16(p, LANCE_RD_BLEN) = (-_BUF_SIZE);
545 cpd->rx_ring_next = 0;
547 p = cpd->tx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->tx_ring_log_cnt)*LANCE_TD_SIZE));
548 memset(cpd->tx_ring,0,(1<<cpd->tx_ring_log_cnt)*LANCE_TD_SIZE);
550 d = cpd->tx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->tx_ring_cnt));
551 for (i = 0; i < cpd->tx_ring_cnt; i++) {
552 HAL_PCI_CPU_TO_BUS(d, (cyg_uint8 *)b);
553 _SU32(p, LANCE_RD_PTR) = b & LANCE_TD_PTR_MASK;
557 cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
559 // Initialization table
560 cpd->init_table = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(LANCE_IB_SIZE));
561 _SU16(cpd->init_table, LANCE_IB_MODE) = 0x0000;
562 for (i = 0; i < 6; i++)
563 _SU8(cpd->init_table, LANCE_IB_PADR0+i) = cpd->esa[i];
564 for (i = 0; i < 8; i++)
565 _SU8(cpd->init_table, LANCE_IB_LADRF0+i) = 0;
567 HAL_PCI_CPU_TO_BUS(cpd->rx_ring, (cyg_uint8 *)b);
568 _SU32(cpd->init_table, LANCE_IB_RDRA) = ((b & LANCE_IB_RDRA_PTR_mask)
569 | (cpd->rx_ring_log_cnt << LANCE_IB_RDRA_CNT_shift));
570 HAL_PCI_CPU_TO_BUS(cpd->tx_ring, (cyg_uint8 *)b);
571 _SU32(cpd->init_table, LANCE_IB_TDRA) = ((b & LANCE_IB_TDRA_PTR_mask)
572 | (cpd->tx_ring_log_cnt << LANCE_IB_TDRA_CNT_shift));
575 db_printf("Loading up lance controller from table at 0x%08x\n", cpd->init_table);
576 db_printf(" Mode 0x%04x\n", _SU16(cpd->init_table, LANCE_IB_MODE));
577 db_printf(" PADR %02x:%02x:%02x:%02x:%02x:%02x ",
578 _SU8(cpd->init_table, LANCE_IB_PADR0+0), _SU8(cpd->init_table, LANCE_IB_PADR0+1),
579 _SU8(cpd->init_table, LANCE_IB_PADR0+2), _SU8(cpd->init_table, LANCE_IB_PADR0+3),
580 _SU8(cpd->init_table, LANCE_IB_PADR0+4), _SU8(cpd->init_table, LANCE_IB_PADR0+5));
581 db_printf("LADR %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
582 _SU8(cpd->init_table, LANCE_IB_LADRF0+0), _SU8(cpd->init_table, LANCE_IB_LADRF0+1),
583 _SU8(cpd->init_table, LANCE_IB_LADRF0+2), _SU8(cpd->init_table, LANCE_IB_LADRF0+3),
584 _SU8(cpd->init_table, LANCE_IB_LADRF0+4), _SU8(cpd->init_table, LANCE_IB_LADRF0+5),
585 _SU8(cpd->init_table, LANCE_IB_LADRF0+5), _SU8(cpd->init_table, LANCE_IB_LADRF0+7));
586 db_printf(" RX 0x%08x (len %d) TX 0x%08x (len %d)\n",
587 _SU32(cpd->init_table, LANCE_IB_RDRA) & 0x1fffffff,
588 (_SU32(cpd->init_table, LANCE_IB_RDRA) >> LANCE_IB_RDRA_CNT_shift) & 7,
589 _SU32(cpd->init_table, LANCE_IB_TDRA) & 0x1fffffff,
590 (_SU32(cpd->init_table, LANCE_IB_TDRA) >> LANCE_IB_TDRA_CNT_shift) & 7);
594 HAL_PCI_IO_READ_UINT16(cpd->base+LANCE_IO_RESET, val);
596 // Load up chip with buffers.
597 // Note: There is a 16M limit on the addresses used by the driver
598 // since the top 8 bits of the init_table address is appended to
599 // all other addresses used by the controller.
600 HAL_PCI_CPU_TO_BUS(cpd->init_table, (cyg_uint8 *)b);
601 put_reg(sc, LANCE_CSR_IBA0, (b >> 0) & 0xffff);
602 put_reg(sc, LANCE_CSR_IBA1, (b >> 16) & 0xffff);
603 // Disable automatic TX polling (_send will force a poll), pad
604 // XT frames to legal length, mask status interrupts.
605 put_reg(sc, LANCE_CSR_TFC, (LANCE_CSR_TFC_TXDPOLL | LANCE_CSR_TFC_APAD_XMT
606 | LANCE_CSR_TFC_MFCOM | LANCE_CSR_TFC_RCVCCOM
607 | LANCE_CSR_TFC_TXSTRTM));
608 // Recover after TX FIFO underflow
609 put_reg(sc, LANCE_CSR_IM, LANCE_CSR_IM_DXSUFLO);
610 // Initialize controller - load up init_table
611 put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_INIT);
612 while (0 == (get_reg(sc, LANCE_CSR_CSCR) & LANCE_CSR_CSCR_IDON));
615 put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
618 db_printf("lancepci controller state is now:\n");
619 db_printf(" Mode 0x%04x TFC 0x%04x\n", _SU16(cpd->init_table, LANCE_IB_MODE), get_reg(sc, LANCE_CSR_TFC));
620 db_printf(" PADR %04x:%04x:%04x ",
621 get_reg(sc, LANCE_CSR_PAR0),
622 get_reg(sc, LANCE_CSR_PAR1),
623 get_reg(sc, LANCE_CSR_PAR2));
624 db_printf("LADR %04x:%04x:%04x:%04x\n",
625 get_reg(sc, LANCE_CSR_LAR0),
626 get_reg(sc, LANCE_CSR_LAR1),
627 get_reg(sc, LANCE_CSR_LAR2),
628 get_reg(sc, LANCE_CSR_LAR3));
629 db_printf(" RX 0x%04x%04x (len 0x%04x) TX 0x%04x%04x (len 0x%04x)\n",
630 get_reg(sc, LANCE_CSR_BARRU), get_reg(sc, LANCE_CSR_BARRL),
631 get_reg(sc, LANCE_CSR_RRLEN),
632 get_reg(sc, LANCE_CSR_BATRU), get_reg(sc, LANCE_CSR_BATRL),
633 get_reg(sc, LANCE_CSR_TRLEN));
635 val = get_reg(sc, LANCE_CSR_ID_LO);
636 db_printf("lancepci ID 0x%04x (%s) ",
638 (0x5003 == val) ? "Am79C973" : (0x7003 == val) ? "Am79C975" :
639 (0x1003 == val) ? "Am79C900 or wmWare VLANCE" : "Unknown");
640 val = get_reg(sc, LANCE_CSR_ID_HI);
641 db_printf("Part IDU 0x%03x Silicon rev %d\n",
642 val & 0x0fff, (val >> 12) & 0xf);
644 // and record the net dev pointer
645 cpd->ndp = (void *)tab;
649 // Initialize upper level driver
650 (sc->funs->eth_drv->init)(sc, cpd->esa);
651 cpd->txbusyh=cpd->txbusy=0;
653 db_printf("Lancepci driver loaded and Init Done\n");
658 lancepci_stop(struct eth_drv_sc *sc)
661 struct lancepci_priv_data *cpd =
662 (struct lancepci_priv_data *)sc->driver_private;
669 db_printf("Lancepci-stop:waiting for tx empty\n");
672 while (cpd->txbusyh && b) {
673 CYGACC_CALL_IF_DELAY_US(200);
677 put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
680 db_printf("Lancepci-stop:done\n");
685 // This function is called to "start up" the interface. It may be called
686 // multiple times, even when the hardware is already running. It will be
687 // called whenever something "hardware oriented" changes and should leave
688 // the hardware ready to send/receive packets.
691 lancepci_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
695 struct lancepci_priv_data *cpd =
696 (struct lancepci_priv_data *)sc->driver_private;
698 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
702 // If device is already active, stop it
704 db_printf("Lancepci-start:entered\n");
710 db_printf("Lancepci-start:waiting for tx empty\n");
713 while (cpd->txbusyh && b) {
714 CYGACC_CALL_IF_DELAY_US(200);
718 put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
721 db_printf("Lancepci-start:stopped\n");
724 CYGACC_CALL_IF_DELAY_US(200);
728 #ifdef ETH_DRV_FLAGS_PROMISC_MODE
729 != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
731 ) || (ifp->if_flags & IFF_PROMISC)
733 // Then we select promiscuous mode.
734 _SU16(cpd->init_table, LANCE_IB_MODE) = 0x0000|LANCE_CSR_MODE_PROM;
736 db_printf("Promisc MODE!");
739 else _SU16(cpd->init_table, LANCE_IB_MODE) = 0x0000;
741 cpd->rx_ring_next = 0;
742 cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
743 // Init the chip again
744 HAL_PCI_CPU_TO_BUS(cpd->init_table, (cyg_uint8 *)b);
745 put_reg(sc, LANCE_CSR_IBA0, (b >> 0) & 0xffff);
746 put_reg(sc, LANCE_CSR_IBA1, (b >> 16) & 0xffff);
747 // Disable automatic TX polling (_send will force a poll), pad
748 // XT frames to legal length, mask status interrupts.
749 put_reg(sc, LANCE_CSR_TFC, (LANCE_CSR_TFC_TXDPOLL | LANCE_CSR_TFC_APAD_XMT
750 | LANCE_CSR_TFC_MFCOM | LANCE_CSR_TFC_RCVCCOM
751 | LANCE_CSR_TFC_TXSTRTM));
752 // Recover after TX FIFO underflow
753 put_reg(sc, LANCE_CSR_IM, LANCE_CSR_IM_DXSUFLO);
754 // Initialize controller - load up init_table
755 put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_INIT);
756 while (0 == (get_reg(sc, LANCE_CSR_CSCR) & LANCE_CSR_CSCR_IDON));
757 reg=get_reg(sc,LANCE_CSR_CSCR);
758 put_reg(sc, LANCE_CSR_CSCR, (reg|(LANCE_CSR_CSCR_IENA | LANCE_CSR_CSCR_STRT))&~LANCE_CSR_CSCR_INIT);
760 reg=get_reg(sc,LANCE_CSR_CSCR);
761 db_printf("CSR after start = %4x\n",reg);
763 cpd->active = 1; cpd->txbusy=0; cpd->txbusyh=0;
764 // delay is necessary for Vmware to get a tick !!!
765 CYGACC_CALL_IF_DELAY_US(50000);
769 // This routine is called to perform special "control" opertions
772 lancepci_control(struct eth_drv_sc *sc, unsigned long key,
773 void *data, int data_length)
775 cyg_uint8 *esa = (cyg_uint8 *)data;
778 struct lancepci_priv_data *cpd =
779 (struct lancepci_priv_data *)sc->driver_private;
784 db_printf("Lancepci-control:entered\n");
786 res = 0; // expect success
788 case ETH_DRV_SET_MAC_ADDRESS:
790 db_printf("PCNET - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
791 esa[0], esa[1], esa[2], esa[3], esa[4], esa[5] );
793 for ( i = 0; i < sizeof(cpd->esa); i++ )
794 cpd->esa[i] = esa[i];
795 for (i = 0; i < sizeof(cpd->esa); i += 2) {
796 reg = cpd->esa[i] | (cpd->esa[i+1] << 8);
797 put_reg(sc, LANCE_CSR_PAR0+i/2, reg );
799 for (i = 0; i < 6; i++) // in case of later restart
800 _SU8(cpd->init_table, LANCE_IB_PADR0+i) = cpd->esa[i];
802 #ifdef ETH_DRV_GET_MAC_ADDRESS
803 case ETH_DRV_GET_MAC_ADDRESS:
804 // Extract the MAC address that is in the chip, and tell the
806 for (i = 0; i < sizeof(cpd->esa); i += 2) {
807 cyg_uint16 z = get_reg(sc, LANCE_CSR_PAR0+i/2 );
808 esa[i] = (cyg_uint8)(0xff & z);
809 esa[i+1] = (cyg_uint8)(0xff & (z >> 8));
813 #ifdef ETH_DRV_GET_IF_STATS_UD
814 case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
817 #ifdef ETH_DRV_GET_IF_STATS
818 case ETH_DRV_GET_IF_STATS:
821 #if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
823 struct ether_drv_stats *p = (struct ether_drv_stats *)data;
824 // Chipset entry is no longer supported; RFC1573.
825 for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
826 p->snmp_chipset[i] = 0;
828 // This perhaps should be a config opt, so you can make up your own
829 // description, or supply it from the instantiation.
830 strcpy( p->description, "AMD LancePCI" );
831 // CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
833 p->operational = 3; // LINK UP
834 p->duplex = 2; // 2 = SIMPLEX
835 p->speed = 10 * 1000000;
838 #ifdef KEEP_STATISTICS
840 struct amd_lancepci_stats *ps = &(cpd->stats);
843 p->supports_dot3 = true;
845 p->tx_good = ps->tx_good ;
846 p->tx_max_collisions = ps->tx_max_collisions ;
847 p->tx_late_collisions = ps->tx_late_collisions ;
848 p->tx_underrun = ps->tx_underrun ;
849 p->tx_carrier_loss = ps->tx_carrier_loss ;
850 p->tx_deferred = ps->tx_deferred ;
851 p->tx_sqetesterrors = ps->tx_sqetesterrors ;
852 p->tx_single_collisions = ps->tx_single_collisions;
853 p->tx_mult_collisions = ps->tx_mult_collisions ;
854 p->tx_total_collisions = ps->tx_total_collisions ;
855 p->rx_good = ps->rx_good ;
856 p->rx_crc_errors = ps->rx_crc_errors ;
857 p->rx_align_errors = ps->rx_align_errors ;
858 p->rx_resource_errors = ps->rx_resource_errors ;
859 p->rx_overrun_errors = ps->rx_overrun_errors ;
860 p->rx_collisions = ps->rx_collisions ;
861 p->rx_short_frames = ps->rx_short_frames ;
862 p->rx_too_long_frames = ps->rx_too_long_frames ;
863 p->rx_symbol_errors = ps->rx_symbol_errors ;
865 p->interrupts = ps->interrupts ;
866 p->rx_count = ps->rx_count ;
867 p->rx_deliver = ps->rx_deliver ;
868 p->rx_resource = ps->rx_resource ;
869 p->rx_restart = ps->rx_restart ;
870 p->tx_count = ps->tx_count ;
871 p->tx_complete = ps->tx_complete ;
872 p->tx_dropped = ps->tx_dropped ;
874 #endif // KEEP_STATISTICS
886 db_printf("Lancepci-control:done\n");
888 CYGACC_CALL_IF_DELAY_US(50000); // let VMware get a tick
893 // This routine is called to see if it is possible to send another packet.
894 // It will return non-zero if a transmit is possible, zero otherwise.
897 lancepci_can_send(struct eth_drv_sc *sc)
899 struct lancepci_priv_data *cpd =
900 (struct lancepci_priv_data *)sc->driver_private;
904 return (0 == cpd->txbusy);
908 // This routine is called to send data to the hardware.
910 lancepci_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
911 int total_len, unsigned long key)
913 struct lancepci_priv_data *cpd =
914 (struct lancepci_priv_data *)sc->driver_private;
915 int i, len, plen, ring_entry;
917 cyg_uint8* sdata = NULL;
918 cyg_uint8 *d, *buf, *txd;
924 INCR_STAT( tx_count );
926 cpd->txbusy = 1; cpd->txbusyh=1;
929 // Find packet length
931 for (i = 0; i < sg_len; i++)
932 plen += sg_list[i].len;
934 CYG_ASSERT( plen == total_len, "sg data length mismatch" );
936 // Get next TX descriptor
937 ring_entry = cpd->tx_ring_free;
939 if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {
940 // Is this a dead end? Probably is.
942 db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );
948 cpd->tx_ring_owned++;
949 if (cpd->tx_ring_free == cpd->tx_ring_cnt)
950 cpd->tx_ring_free = 0;
953 txd = cpd->tx_ring + ring_entry*LANCE_TD_SIZE;
954 buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;
955 CYG_ASSERT(0 == (_SU32(txd, LANCE_TD_PTR) & LANCE_TD_PTR_OWN),
956 "TX descriptor not free");
959 db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",
963 // Put data into buffer
965 for (i = 0; i < sg_len; i++) {
966 sdata = (cyg_uint8 *)sg_list[i].buf;
967 len = sg_list[i].len;
969 CYG_ASSERT( sdata, "No sg data pointer here" );
973 CYG_ASSERT( sdata, "No sg data pointer outside" );
976 db_printf("CSCR %04x\n", get_reg(sc, LANCE_CSR_CSCR));
978 _SU16(txd, LANCE_TD_LEN) = (-plen);
979 _SU16(txd, LANCE_TD_MISC) = 0;
980 HAL_PCI_CPU_TO_BUS(buf, (cyg_uint8 *)b);
981 _SU32(txd, LANCE_TD_PTR) = ((b & LANCE_TD_PTR_MASK)
982 | LANCE_TD_PTR_OWN | LANCE_TD_PTR_STP | LANCE_TD_PTR_ENP);
985 db_printf("Last TX: LEN %04x MISC %04x PTR %08x\n",
986 _SU16(txd, LANCE_TD_LEN),
987 _SU16(txd, LANCE_TD_MISC),
988 _SU32(txd, LANCE_TD_PTR));
991 // This delay seems to be necessary on some platforms
992 // (Malta 5kc for example).
993 // Why it is needed is not clear, but removing it or
994 // reducing it cause transmission failures in RedBoot (at least).
995 CYGACC_CALL_IF_DELAY_US(100);
998 // Set transmit demand
999 ints = get_reg(sc, LANCE_CSR_CSCR);
1000 ints &= LANCE_CSR_CSCR_EV_MASK;
1001 ints |= LANCE_CSR_CSCR_TDMD;
1002 put_reg(sc, LANCE_CSR_CSCR, ints);
1005 ints = get_reg(sc, LANCE_CSR_CSCR);
1006 db_printf("%s:END: ints at TX: 0x%04x\n", __FUNCTION__, ints);
1009 // This is another mystery delay like the one above. This one is
1010 // even stranger, since waiting here at the _end_ of the function
1011 // should have no effect.
1012 CYGACC_CALL_IF_DELAY_US(200);
1016 lancepci_TxEvent(struct eth_drv_sc *sc, int stat)
1018 struct lancepci_priv_data *cpd =
1019 (struct lancepci_priv_data *)sc->driver_private;
1023 cyg_uint32 pkt_stat;
1027 if (0 == cpd->tx_ring_owned) {
1029 db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);
1034 INCR_STAT( tx_complete );
1036 txd = cpd->tx_ring + cpd->tx_ring_alloc*LANCE_TD_SIZE;
1037 pkt_stat = _SU32(txd, LANCE_TD_PTR);
1038 if (pkt_stat & LANCE_TD_PTR_OWN) {
1040 db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);
1042 // first dirty ring entry not freed - wtf?
1045 if (pkt_stat & LANCE_TD_PTR_ERR) {
1046 // We had an error. Tell the stack.
1049 db_printf("%s: TX failure, retrying...\n", __FUNCTION__);
1053 cpd->tx_ring_alloc++;
1054 if (cpd->tx_ring_alloc == cpd->tx_ring_cnt)
1055 cpd->tx_ring_alloc = 0;
1056 cpd->tx_ring_owned--;
1059 #ifdef KEEP_STATISTICS
1063 reg = get_reg( sc, LANCE_CSR_CSCR );
1065 // Covering each bit in turn...
1066 if ( reg & LANCE_STATUS_TX_UNRN ) INCR_STAT( tx_underrun );
1067 //if ( reg & LANCE_STATUS_LINK_OK ) INCR_STAT( );
1068 //if ( reg & LANCE_STATUS_CTR_ROL ) INCR_STAT( );
1069 //if ( reg & LANCE_STATUS_EXC_DEF ) INCR_STAT( );
1070 if ( reg & LANCE_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );
1071 if ( reg & LANCE_STATUS_LATCOL ) INCR_STAT( tx_late_collisions );
1072 //if ( reg & LANCE_STATUS_WAKEUP ) INCR_STAT( );
1073 if ( reg & LANCE_STATUS_TX_DEFR ) INCR_STAT( tx_deferred );
1074 //if ( reg & LANCE_STATUS_LTX_BRD ) INCR_STAT( );
1075 if ( reg & LANCE_STATUS_SQET ) INCR_STAT( tx_sqetesterrors );
1076 if ( reg & LANCE_STATUS_16COL ) INCR_STAT( tx_max_collisions );
1077 //if ( reg & LANCE_STATUS_LTX_MULT) INCR_STAT( );
1078 if ( reg & LANCE_STATUS_MUL_COL ) INCR_STAT( tx_mult_collisions );
1079 if ( reg & LANCE_STATUS_SNGL_COL ) INCR_STAT( tx_single_collisions );
1080 if ( reg & LANCE_STATUS_TX_SUC ) INCR_STAT( tx_good );
1082 cpd->stats.tx_total_collisions =
1083 cpd->stats.tx_late_collisions +
1084 cpd->stats.tx_max_collisions +
1085 cpd->stats.tx_mult_collisions +
1086 cpd->stats.tx_single_collisions;
1088 // We do not need to look in the Counter Register (LANCE_COUNTER)
1089 // because it just mimics the info we already have above.
1091 #endif // KEEP_STATISTICS
1094 // Ack the TX int which clears the packet from the TX completion
1096 ints = get_reg(sc, LANCE_CSR_CSCR);
1097 ints |= LANCE_CSR_CSCR_TINT;
1098 put_reg(sc, LANCE_CSR_CSCR, ints);
1101 db_printf("#####Tx packet freed 0x%08x\n", txd );
1104 if ( cpd->txbusy ) {
1106 (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);
1112 // This function is called when a packet has been received. Its job is
1113 // to prepare to unload the packet from the hardware. Once the length of
1114 // the packet is known, the upper layer of the driver can be told. When
1115 // the upper layer is ready to unload the packet, the internal function
1116 // 'lancepci_recv' will be called to actually fetch it from the hardware.
1119 lancepci_RxEvent(struct eth_drv_sc *sc)
1121 struct lancepci_priv_data *cpd =
1122 (struct lancepci_priv_data *)sc->driver_private;
1125 cyg_uint16 ints, len;
1129 ints = get_reg(sc, LANCE_CSR_CSCR);
1131 db_printf("RxEvent - CSR: 0x%04x\n", ints);
1135 // Get state of next (supposedly) full ring entry
1136 cpd->rxpacket = cpd->rx_ring_next;
1137 rxd = cpd->rx_ring + cpd->rxpacket*LANCE_RD_SIZE;
1138 rstat = _SU32(rxd, LANCE_RD_PTR);
1140 // Keep going until we hit an entry that is owned by the
1142 if (rstat & LANCE_RD_PTR_OWN) {
1145 for (i = 0; i < cpd->rx_ring_cnt; i++) {
1146 rxd = cpd->rx_ring + i*LANCE_RD_SIZE;
1147 rstat = _SU32(rxd, LANCE_RD_PTR);
1149 if (!(rstat & LANCE_RD_PTR_OWN)) {
1152 cyg_uint16 mlen, blen;
1155 db_printf("%s: Inconsistent RX state\n", __FUNCTION__);
1156 for (i = 0; i < cpd->rx_ring_cnt; i++) {
1157 rxd = cpd->rx_ring + i*LANCE_RD_SIZE;
1159 rstat = _SU32(rxd, LANCE_RD_PTR);
1160 blen = _SU16(rxd, LANCE_RD_BLEN);
1161 mlen = _SU16(rxd, LANCE_RD_MLEN);
1162 db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
1171 db_printf("#####Rx packet at index %d\n", cpd->rxpacket);
1175 INCR_STAT( rx_count );
1176 cpd->rx_ring_next++;
1177 if (cpd->rx_ring_next == cpd->rx_ring_cnt) cpd->rx_ring_next = 0;
1179 len = _SU16(rxd, LANCE_RD_MLEN);
1181 #ifdef KEEP_STATISTICS
1182 //if ( rstat & LANCE_RD_PTR_FRAM ) INCR_STAT( rx_frame_errors );
1183 //if ( rstat & LANCE_RD_PTR_OFLO ) INCR_STAT( );
1184 if ( rstat & LANCE_RD_PTR_CRC ) INCR_STAT( rx_crc_errors );
1185 //if ( rstat & LANCE_RD_PTR_BUFF ) INCR_STAT( );
1186 #endif // KEEP_STATISTICS
1188 if (0 == (rstat & LANCE_RD_PTR_ERR)) {
1190 INCR_STAT( rx_good );
1193 db_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);
1195 // Check for bogusly short packets; can happen in promisc
1196 // mode: Asserted against and checked by upper layer
1199 if ( len > sizeof( struct ether_header ) )
1200 // then it is acceptable; offer the data to the network stack
1202 (sc->funs->eth_drv->recv)(sc, len);
1204 // Not OK for one reason or another...
1206 db_printf("RxEvent - No RX bit: stat: 0x%08x, len: 0x%04x\n",
1211 // Free packet (clear all status flags, and set OWN)
1212 _SU32(rxd, LANCE_RD_PTR) &= LANCE_RD_PTR_MASK;
1213 _SU32(rxd, LANCE_RD_PTR) |= LANCE_RD_PTR_OWN;
1216 // Ack RX interrupt set
1217 ints = get_reg(sc, LANCE_CSR_CSCR);
1218 ints &= LANCE_CSR_CSCR_EV_MASK;
1219 ints |= LANCE_CSR_CSCR_RINT;
1220 put_reg(sc, LANCE_CSR_CSCR, ints);
1224 // This function is called as a result of the "eth_drv_recv()" call above.
1225 // Its job is to actually fetch data for a packet from the hardware once
1226 // memory buffers have been allocated for the packet. Note that the buffers
1227 // may come in pieces, using a scatter-gather list. This allows for more
1228 // efficient processing in the upper layers of the stack.
1231 lancepci_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
1233 struct lancepci_priv_data *cpd =
1234 (struct lancepci_priv_data *)sc->driver_private;
1235 int i, mlen=0, plen;
1236 cyg_uint8 *data, *rxd, *buf;
1240 rxd = cpd->rx_ring + cpd->rxpacket*LANCE_RD_SIZE;
1241 buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;
1243 INCR_STAT( rx_deliver );
1245 plen = _SU16(rxd, LANCE_RD_MLEN);
1247 for (i = 0; i < sg_len; i++) {
1248 data = (cyg_uint8*)sg_list[i].buf;
1249 mlen = sg_list[i].len;
1252 db_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);
1265 lancepci_poll(struct eth_drv_sc *sc)
1268 struct lancepci_priv_data *cpd =
1269 (struct lancepci_priv_data *)sc->driver_private;
1271 // DEBUG_FUNCTION();
1274 // Get the (unmasked) requests
1280 event = get_reg(sc, LANCE_CSR_CSCR);
1281 if (!((LANCE_CSR_CSCR_ERR|LANCE_CSR_CSCR_INTR) & event))
1284 if (event & LANCE_CSR_CSCR_RINT) {
1285 lancepci_RxEvent(sc);
1287 else if (event & LANCE_CSR_CSCR_TINT) {
1288 cpd->txbusyh=0; // again , for polled mode
1289 lancepci_TxEvent(sc, event);
1291 else if (event & LANCE_CSR_CSCR_MISS) {
1295 cyg_uint16 mlen, blen;
1297 struct lancepci_priv_data *cpd =
1298 (struct lancepci_priv_data *)sc->driver_private;
1300 db_printf("%s: Ran out of RX buffers (%04x)\n", __FUNCTION__, event);
1301 for (i = 0; i < cpd->rx_ring_cnt; i++) {
1302 rxd = cpd->rx_ring + i*LANCE_TD_SIZE;
1304 rstat = _SU32(rxd, LANCE_RD_PTR);
1305 blen = _SU16(rxd, LANCE_RD_BLEN);
1306 mlen = _SU16(rxd, LANCE_RD_MLEN);
1307 db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
1310 event &= LANCE_CSR_CSCR_EV_MASK;
1311 event |= LANCE_CSR_CSCR_MISS;
1312 put_reg(sc, LANCE_CSR_CSCR, event);
1316 db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);
1318 put_reg(sc, LANCE_CSR_CSCR, event);
1323 // EOF if_lancepci.c