1 //==========================================================================
5 // Ethernet device driver for AMD PCNET compatible controllers
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.
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.
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
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.
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.
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.
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####
42 // -------------------------------------------
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.
47 // -------------------------------------------
49 //####BSDCOPYRIGHTEND####
50 //==========================================================================
51 //#####DESCRIPTIONBEGIN####
53 // Author(s): jskov, based on lan91cxx driver by hmt & jskov
54 // Contributors: gthomas, jskov, hmt
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).
63 // The KEEP_STATISTICS code is not implemented yet. Look
66 //####DESCRIPTIONEND####
68 //==========================================================================
70 #include <pkgconf/system.h>
71 #include <pkgconf/devs_eth_amd_pcnet.h>
72 #include <pkgconf/io_eth_drivers.h>
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
82 #include <cyg/io/eth/netdev.h>
83 #include <cyg/io/eth/eth_drv.h>
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>
90 #include CYGHWR_MEMORY_LAYOUT_H
93 #include <cyg/io/pci.h>
95 #error "Need PCI package here"
100 #define _BUF_SIZE 1544
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;
109 #include "amd_pcnet.h"
111 #include CYGDAT_DEVS_ETH_AMD_PCNET_INL
114 #if defined(CYGPKG_REDBOOT) && DEBUG
116 static void db_printf( char *fmt, ... )
118 extern int start_console(void);
119 extern void end_console(int);
123 old_console = start_console();
124 diag_vprintf( fmt, a );
125 end_console(old_console);
131 #define db_printf diag_printf
135 static void pcnet_poll(struct eth_drv_sc *sc);
137 // This ISR is called when the ethernet interrupt occurs
139 pcnet_isr(cyg_vector_t vector, cyg_addrword_t data)
141 struct pcnet_priv_data *cpd = (struct pcnet_priv_data *)data;
145 INCR_STAT( interrupts );
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
153 pcnet_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
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);
163 // but here, it must be a *sc:
164 eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
166 # ifndef CYGPKG_REDBOOT
167 # error Empty PCnet ethernet DSR is compiled. Is this what you want?
173 // The deliver function (ex-DSR) handles the ethernet [logical] processing
175 pcnet_deliver(struct eth_drv_sc *sc)
177 struct pcnet_priv_data *cpd =
178 (struct pcnet_priv_data *)sc->driver_private;
182 // Service the interrupt:
184 // Allow interrupts to happen again
185 cyg_drv_interrupt_unmask(cpd->interrupt);
189 pcnet_int_vector(struct eth_drv_sc *sc)
191 struct pcnet_priv_data *cpd =
192 (struct pcnet_priv_data *)sc->driver_private;
194 return (cpd->interrupt);
197 // ------------------------------------------------------------------------
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;
206 pciwindow_mem_alloc(int size)
212 (CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE <= (int)pcnet_heap_free)
214 ((CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE +
215 CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE) > (int)pcnet_heap_free)
217 (0 < pcnet_heap_size)
219 (CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE >= pcnet_heap_size)
221 (CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE == (int)pcnet_heap_base),
222 "Heap variables corrupted" );
224 p_memory = (void *)0;
225 size = (size + 3) & ~3;
226 if ( (pcnet_heap_free+size) < (pcnet_heap_base+pcnet_heap_size) ) {
228 p_memory = (void *)pcnet_heap_free;
229 pcnet_heap_free += size;
230 for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )
235 db_printf("Allocated %d bytes at 0x%08x\n", size, p_memory);
241 static cyg_pci_match_func find_pcnet_match_func;
244 find_pcnet_match_func( cyg_uint16 v, cyg_uint16 d, cyg_uint32 c, void *p )
247 db_printf("PCI match vendor 0x%04x device 0x%04x\n", v, d);
249 return (0x1022 == v) && (0x2000 == d);
253 pci_init_find_pcnet( void )
255 cyg_pci_device_id devid;
256 cyg_pci_device dev_info;
259 int found_devices = 0;
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" );
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" );
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" );
277 #ifdef CYGARC_UNCACHED_ADDRESS
278 CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) !=
280 (CYG_ADDRWORD)CYGMEM_SECTION_pci_window !=
282 CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE
284 CYGMEM_SECTION_pci_window_SIZE !=
285 CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE ) {
287 db_printf("pci_init_find_pcnets(): PCI window misconfigured\n");
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;
297 db_printf("pcimem : 0x%08x size: 0x%08x\n", pcnet_heap_base, pcnet_heap_size);
302 db_printf("Finished cyg_pci_init();\n");
305 devid = CYG_PCI_NULL_DEVID;
307 for (device_index = 0;
308 device_index < CYGNUM_DEVS_ETH_AMD_PCNET_DEV_COUNT;
310 struct pcnet_priv_data* cpd = pcnet_priv_array[device_index];
312 cpd->index = device_index;
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 )) {
319 db_printf("eth%d = pcnet\n", device_index);
321 cyg_pci_get_device_info(devid, &dev_info);
323 cpd->interrupt_handle = 0; // Flag not attached.
324 if (cyg_pci_translate_interrupt(&dev_info, &cpd->interrupt)) {
326 db_printf(" Wired to HAL vector %d\n", cpd->interrupt);
328 cyg_drv_interrupt_create(
330 1, // Priority - unused
331 (cyg_addrword_t)cpd,// Data item passed to ISR & DSR
334 &cpd->interrupt_handle, // handle to intr obj
335 &cpd->interrupt_object ); // space for int obj
337 cyg_drv_interrupt_attach(cpd->interrupt_handle);
339 // Don't unmask the interrupt yet, that could get us into a
345 db_printf(" Does not generate interrupts.\n");
349 if (cyg_pci_configure_device(&dev_info)) {
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));
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");
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);
365 db_printf(" Class/Rev 0x%08x", dev_info.class_rev);
366 db_printf("\n Header 0x%02x\n", dev_info.header_type);
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);
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]);
377 db_printf(" eth%d configured\n", device_index);
383 cpd->base = (unsigned char*) dev_info.base_map[0];
385 db_printf(" I/O address = 0x%08x\n", cpd->base);
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);
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);
403 db_printf(" Enabled interrupt %d\n", cpd->interrupt);
407 db_printf(" **** Device enabled for I/O and Memory "
415 db_printf("Failed to configure device %d\n", device_index);
423 db_printf("eth%d not found\n", device_index);
428 if (0 == found_devices)
436 amd_pcnet_init(struct cyg_netdevtab_entry *tab)
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;
446 cyg_uint8* init_table;
452 if ( 0 == initialized++ ) {
453 // then this is the first time ever:
454 if ( ! pci_init_find_pcnet() ) {
456 db_printf( "pci_init_find_pcnet failed" );
462 // If this device is not present, exit
469 db_printf("PCNet at base 0x%08x, EEPROM key 0x%04x\n",
470 cpd->base, _SU16(cpd->base, PCNET_IO_ID));
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");
482 db_printf("pcimem : %08x size: %08x\n", pcnet_heap_base, pcnet_heap_size);
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++)
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] );
499 #ifdef CYGSEM_DEVS_ETH_AMD_PCNET_FORCE_10MBPS
500 if (get_reg(sc,PCNET_ANR_AAR) & PCNET_ANR_AAR_100) {
505 db_printf("%s: Forcing 10Mbps negotiation\n", __FUNCTION__);
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);
512 anr = get_reg(sc,PCNET_ANR_PHYCTRL);
513 anr |= PCNET_ANR_PHYCTRL_RENEGOTIATE;
514 put_reg(sc,PCNET_ANR_PHYCTRL,anr);
516 while (loop>0 && !(get_reg(sc,PCNET_ANR_PHYSTAT) & PCNET_ANR_PHYSTAT_AUTONEG_COMP))
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));
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);
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);
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);
540 cpd->rx_ring_next = 0;
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);
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;
552 cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
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;
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));
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);
589 HAL_PCI_IO_READ_UINT16(cpd->base+PCNET_IO_RESET, val);
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));
610 put_reg(sc, PCNET_CSR_CSCR, PCNET_CSR_CSCR_STOP);
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));
630 val = get_reg(sc, PCNET_CSR_ID_LO);
631 db_printf("PCnet ID 0x%04x (%s) ",
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);
639 // and record the net dev pointer
640 cpd->ndp = (void *)tab;
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));
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));
651 db_printf("Failed to start the controller\n");
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
662 val = get_reg(sc, PCNET_CSR_ECI);
663 } while (0 == (val & PCNET_CSR_ECI_SPND));
666 // Initialize upper level driver
667 (sc->funs->eth_drv->init)(sc, cpd->esa);
676 pcnet_stop(struct eth_drv_sc *sc)
679 struct pcnet_priv_data *cpd =
680 (struct pcnet_priv_data *)sc->driver_private;
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
689 reg = get_reg(sc, PCNET_CSR_ECI);
690 } while (0 == (reg & PCNET_CSR_ECI_SPND));
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.
701 pcnet_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
704 struct pcnet_priv_data *cpd =
705 (struct pcnet_priv_data *)sc->driver_private;
707 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
711 // If device is already active, suspend it
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
718 reg = get_reg(sc, PCNET_CSR_ECI);
719 } while (0 == (reg & PCNET_CSR_ECI_SPND));
725 #ifdef ETH_DRV_FLAGS_PROMISC_MODE
726 != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
728 ) || (ifp->if_flags & IFF_PROMISC)
730 // Then we select promiscuous mode.
732 rcr = get_reg(sc, PCNET_CSR_MODE );
733 rcr |= PCNET_CSR_MODE_PROM;
734 put_reg(sc, PCNET_CSR_MODE, rcr );
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);
746 // This routine is called to perform special "control" opertions
749 pcnet_control(struct eth_drv_sc *sc, unsigned long key,
750 void *data, int data_length)
752 cyg_uint8 *esa = (cyg_uint8 *)data;
755 struct pcnet_priv_data *cpd =
756 (struct pcnet_priv_data *)sc->driver_private;
757 cyg_bool was_active = cpd->active;
761 // If device is already active, suspend it
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
768 reg = get_reg(sc, PCNET_CSR_ECI);
769 } while (0 == (reg & PCNET_CSR_ECI_SPND));
773 res = 0; // expect success
775 case ETH_DRV_SET_MAC_ADDRESS:
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] );
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 );
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
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));
801 #ifdef ETH_DRV_GET_IF_STATS_UD
802 case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
805 #ifdef ETH_DRV_GET_IF_STATS
806 case ETH_DRV_GET_IF_STATS:
809 #if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
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;
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" );
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
829 p->operational = 3; // LINK UP
830 anr = get_reg(sc, PCNET_ANR_PHYCTRL);
832 if (anr & PCNET_ANR_PHYCTRL_DUPLEX)
833 p->duplex = 3; // 3 = DUPLEX
835 p->duplex = 2; // 2 = SIMPLEX
836 p->speed = (anr & PCNET_ANR_PHYCTRL_100MBPS) ? 100 * 1000000 : 10 * 1000000;
840 #ifdef KEEP_STATISTICS
842 struct amd_pcnet_stats *ps = &(cpd->stats);
845 p->supports_dot3 = true;
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 ;
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 ;
876 #endif // KEEP_STATISTICS
888 // Restore controller state
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);
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.
904 pcnet_can_send(struct eth_drv_sc *sc)
906 struct pcnet_priv_data *cpd =
907 (struct pcnet_priv_data *)sc->driver_private;
912 stat = get_reg(sc, PCNET_ANR_PHYSTAT);
913 if ((stat & PCNET_ANR_PHYSTAT_LINK) == 0) {
914 return 0; // Link not connected
917 return (0 == cpd->txbusy);
921 // This routine is called to send data to the hardware.
923 pcnet_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
924 int total_len, unsigned long key)
926 struct pcnet_priv_data *cpd =
927 (struct pcnet_priv_data *)sc->driver_private;
928 int i, len, plen, ring_entry;
930 cyg_uint8* sdata = NULL;
931 cyg_uint8 *d, *buf, *txd;
937 INCR_STAT( tx_count );
942 // Find packet length
944 for (i = 0; i < sg_len; i++)
945 plen += sg_list[i].len;
947 CYG_ASSERT( plen == total_len, "sg data length mismatch" );
949 // Get next TX descriptor
950 ring_entry = cpd->tx_ring_free;
952 if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {
953 // Is this a dead end? Probably is.
955 db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );
961 cpd->tx_ring_owned++;
962 if (cpd->tx_ring_free == cpd->tx_ring_cnt)
963 cpd->tx_ring_free = 0;
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");
972 db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",
976 // Put data into buffer
978 for (i = 0; i < sg_len; i++) {
979 sdata = (cyg_uint8 *)sg_list[i].buf;
980 len = sg_list[i].len;
982 CYG_ASSERT( sdata, "No sg data pointer here" );
986 CYG_ASSERT( sdata, "No sg data pointer outside" );
989 db_printf("CSCR %04x\n", get_reg(sc, PCNET_CSR_CSCR));
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);
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));
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);
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);
1018 ints = get_reg(sc, PCNET_CSR_CSCR);
1019 db_printf("%s:END: ints at TX: 0x%04x\n", __FUNCTION__, ints);
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);
1029 pcnet_TxEvent(struct eth_drv_sc *sc, int stat)
1031 struct pcnet_priv_data *cpd =
1032 (struct pcnet_priv_data *)sc->driver_private;
1036 cyg_uint32 pkt_stat;
1040 if (0 == cpd->tx_ring_owned) {
1042 db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);
1047 INCR_STAT( tx_complete );
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) {
1053 db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);
1055 // first dirty ring entry not freed - wtf?
1058 if (pkt_stat & PCNET_TD_PTR_ERR) {
1059 // We had an error. Tell the stack.
1062 db_printf("%s: TX failure, retrying...\n", __FUNCTION__);
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--;
1072 #ifdef KEEP_STATISTICS
1076 reg = get_reg( sc, PCNET_CSR_CSCR );
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 );
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;
1101 // We do not need to look in the Counter Register (PCNET_COUNTER)
1102 // because it just mimics the info we already have above.
1104 #endif // KEEP_STATISTICS
1107 // Ack the TX int which clears the packet from the TX completion
1109 ints = get_reg(sc, PCNET_CSR_CSCR);
1110 ints |= PCNET_CSR_CSCR_TINT;
1111 put_reg(sc, PCNET_CSR_CSCR, ints);
1114 db_printf("#####Tx packet freed 0x%08x\n", txd );
1117 if ( cpd->txbusy ) {
1119 (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);
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.
1132 pcnet_RxEvent(struct eth_drv_sc *sc)
1134 struct pcnet_priv_data *cpd =
1135 (struct pcnet_priv_data *)sc->driver_private;
1138 cyg_uint16 ints, len;
1142 ints = get_reg(sc, PCNET_CSR_CSCR);
1144 db_printf("RxEvent - CSR: 0x%04x\n", ints);
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);
1153 // Keep going until we hit an entry that is owned by the
1155 if (rstat & PCNET_RD_PTR_OWN) {
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);
1162 if (!(rstat & PCNET_RD_PTR_OWN)) {
1165 cyg_uint16 mlen, blen;
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;
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);
1184 db_printf("#####Rx packet at index %d\n", cpd->rxpacket);
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;
1192 len = _SU16(rxd, PCNET_RD_MLEN);
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
1201 if (0 == (rstat & PCNET_RD_PTR_ERR)) {
1203 INCR_STAT( rx_good );
1206 db_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);
1208 // Check for bogusly short packets; can happen in promisc
1209 // mode: Asserted against and checked by upper layer
1212 if ( len > sizeof( struct ether_header ) )
1213 // then it is acceptable; offer the data to the network stack
1215 (sc->funs->eth_drv->recv)(sc, len);
1217 // Not OK for one reason or another...
1219 db_printf("RxEvent - No RX bit: stat: 0x%08x, len: 0x%04x\n",
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;
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);
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.
1244 pcnet_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
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;
1253 rxd = cpd->rx_ring + cpd->rxpacket*PCNET_RD_SIZE;
1254 buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;
1256 INCR_STAT( rx_deliver );
1258 plen = _SU16(rxd, PCNET_RD_MLEN);
1260 for (i = 0; i < sg_len; i++) {
1261 data = (cyg_uint8*)sg_list[i].buf;
1262 mlen = sg_list[i].len;
1265 db_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);
1278 pcnet_poll(struct eth_drv_sc *sc)
1282 // DEBUG_FUNCTION();
1285 // Get the (unmasked) requests
1286 event = get_reg(sc, PCNET_CSR_CSCR);
1287 if (!((PCNET_CSR_CSCR_ERR|PCNET_CSR_CSCR_INTR) & event))
1290 if (event & PCNET_CSR_CSCR_RINT) {
1293 else if (event & PCNET_CSR_CSCR_TINT) {
1294 pcnet_TxEvent(sc, event);
1296 else if (event & PCNET_CSR_CSCR_MISS) {
1300 cyg_uint16 mlen, blen;
1302 struct pcnet_priv_data *cpd =
1303 (struct pcnet_priv_data *)sc->driver_private;
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;
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);
1315 event &= PCNET_CSR_CSCR_EV_MASK;
1316 event |= PCNET_CSR_CSCR_MISS;
1317 put_reg(sc, PCNET_CSR_CSCR, event);
1321 db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);
1323 put_reg(sc, PCNET_CSR_CSCR, event);