diff options
Diffstat (limited to 'gpxe/src/drivers/net/pcnet32.c')
-rw-r--r-- | gpxe/src/drivers/net/pcnet32.c | 1021 |
1 files changed, 0 insertions, 1021 deletions
diff --git a/gpxe/src/drivers/net/pcnet32.c b/gpxe/src/drivers/net/pcnet32.c deleted file mode 100644 index 223bc1e2..00000000 --- a/gpxe/src/drivers/net/pcnet32.c +++ /dev/null @@ -1,1021 +0,0 @@ -/************************************************************************** -* -* pcnet32.c -- Etherboot device driver for the AMD PCnet32 -* Written 2003-2003 by Timothy Legge <tlegge@rogers.com> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Portions of this code based on: -* pcnet32.c: An AMD PCnet32 ethernet driver for linux: -* -* (C) 1996-1999 Thomas Bogendoerfer -* See Linux Driver for full information -* -* The transmit and poll functions were written with reference to: -* lance.c - LANCE NIC driver for Etherboot written by Ken Yap -* -* Linux Driver Version 1.27a, 10.02.2002 -* -* -* REVISION HISTORY: -* ================ -* v1.0 08-06-2003 timlegge Initial port of Linux driver -* v1.1 08-23-2003 timlegge Add multicast support -* v1.2 01-17-2004 timlegge Initial driver output cleanup -* v1.3 03-29-2004 timlegge More driver cleanup -* -* Indent Options: indent -kr -i8 -***************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "etherboot.h" -#include "nic.h" -#include <gpxe/pci.h> -#include <gpxe/ethernet.h> -#include "mii.h" - -/* void hex_dump(const char *data, const unsigned int len); */ - -/* Etherboot Specific definations */ -#define drv_version "v1.3" -#define drv_date "03-29-2004" - -static u32 ioaddr; /* Globally used for the card's io address */ -static struct nic_operations pcnet32_operations; - -#ifdef EDEBUG -#define dprintf(x) printf x -#else -#define dprintf(x) -#endif - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -/* End Etherboot Specific */ - -static int cards_found = 0 /* __initdata */ ; - -#ifdef REMOVE -/* FIXME: Remove these they are probably pointless */ - -/* - * VLB I/O addresses - */ -static unsigned int pcnet32_portlist[] /*__initdata */ = -{ 0x300, 0x320, 0x340, 0x360, 0 }; - -static int pcnet32_debug = 1; -static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ -static int pcnet32vlb; /* check for VLB cards ? */ - -static struct net_device *pcnet32_dev; - -static int max_interrupt_work = 80; -static int rx_copybreak = 200; -#endif -#define PCNET32_PORT_AUI 0x00 -#define PCNET32_PORT_10BT 0x01 -#define PCNET32_PORT_GPSI 0x02 -#define PCNET32_PORT_MII 0x03 - -#define PCNET32_PORT_PORTSEL 0x03 -#define PCNET32_PORT_ASEL 0x04 -#define PCNET32_PORT_100 0x40 -#define PCNET32_PORT_FD 0x80 - -#define PCNET32_DMA_MASK 0xffffffff - -/* - * table to translate option values from tulip - * to internal options - */ -static unsigned char options_mapping[] = { - PCNET32_PORT_ASEL, /* 0 Auto-select */ - PCNET32_PORT_AUI, /* 1 BNC/AUI */ - PCNET32_PORT_AUI, /* 2 AUI/BNC */ - PCNET32_PORT_ASEL, /* 3 not supported */ - PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ - PCNET32_PORT_ASEL, /* 5 not supported */ - PCNET32_PORT_ASEL, /* 6 not supported */ - PCNET32_PORT_ASEL, /* 7 not supported */ - PCNET32_PORT_ASEL, /* 8 not supported */ - PCNET32_PORT_MII, /* 9 MII 10baseT */ - PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ - PCNET32_PORT_MII, /* 11 MII (autosel) */ - PCNET32_PORT_10BT, /* 12 10BaseT */ - PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ - PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, /* 14 MII 100BaseTx-FD */ - PCNET32_PORT_ASEL /* 15 not supported */ -}; - -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS]; -static int full_duplex[MAX_UNITS]; - -/* - * Theory of Operation - * - * This driver uses the same software structure as the normal lance - * driver. So look for a verbose description in lance.c. The differences - * to the normal lance driver is the use of the 32bit mode of PCnet32 - * and PCnetPCI chips. Because these chips are 32bit chips, there is no - * 16MB limitation and we don't need bounce buffers. - */ - - - -/* - * Set the number of Tx and Rx buffers, using Log_2(# buffers). - * Reasonable default values are 4 Tx buffers, and 16 Rx buffers. - * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). - */ -#ifndef PCNET32_LOG_TX_BUFFERS -#define PCNET32_LOG_TX_BUFFERS 1 -#define PCNET32_LOG_RX_BUFFERS 2 -#endif - -#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -/* FIXME: Fix this to allow multiple tx_ring descriptors */ -#define TX_RING_LEN_BITS 0x0000 /*PCNET32_LOG_TX_BUFFERS) << 12) */ - -#define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) - -#define PKT_BUF_SZ 1544 - -/* Offsets from base I/O address. */ -#define PCNET32_WIO_RDP 0x10 -#define PCNET32_WIO_RAP 0x12 -#define PCNET32_WIO_RESET 0x14 -#define PCNET32_WIO_BDP 0x16 - -#define PCNET32_DWIO_RDP 0x10 -#define PCNET32_DWIO_RAP 0x14 -#define PCNET32_DWIO_RESET 0x18 -#define PCNET32_DWIO_BDP 0x1C - -#define PCNET32_TOTAL_SIZE 0x20 - -/* The PCNET32 Rx and Tx ring descriptors. */ -struct pcnet32_rx_head { - u32 base; - s16 buf_length; - s16 status; - u32 msg_length; - u32 reserved; -}; - -struct pcnet32_tx_head { - u32 base; - s16 length; - s16 status; - u32 misc; - u32 reserved; -}; - -/* The PCNET32 32-Bit initialization block, described in databook. */ -struct pcnet32_init_block { - u16 mode; - u16 tlen_rlen; - u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; - /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; -}; -/* PCnet32 access functions */ -struct pcnet32_access { - u16(*read_csr) (unsigned long, int); - void (*write_csr) (unsigned long, int, u16); - u16(*read_bcr) (unsigned long, int); - void (*write_bcr) (unsigned long, int, u16); - u16(*read_rap) (unsigned long); - void (*write_rap) (unsigned long, u16); - void (*reset) (unsigned long); -}; - -/* Define the TX and RX Descriptors and Rings */ -struct { - struct pcnet32_tx_head tx_ring[TX_RING_SIZE] - __attribute__ ((aligned(16))); - struct pcnet32_rx_head rx_ring[RX_RING_SIZE] - __attribute__ ((aligned(16))); - unsigned char txb[TX_RING_SIZE][PKT_BUF_SZ]; - unsigned char rxb[RX_RING_SIZE][PKT_BUF_SZ]; -} pcnet32_bufs __shared; - - -/* - * The first three fields of pcnet32_private are read by the ethernet device - * so we allocate the structure should be allocated by pci_alloc_consistent(). - */ -#define MII_CNT 4 -struct pcnet32_private { - struct pcnet32_init_block init_block; - struct pci_dev *pci_dev; /* Pointer to the associated pci device structure */ - const char *name; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - struct pcnet32_access a; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - char tx_full; - int options; - int shared_irq:1, /* shared irq possible */ - ltint:1, /* enable TxDone-intr inhibitor */ - dxsuflo:1, /* disable transmit stop on uflo */ - mii:1; /* mii port available */ - struct mii_if_info mii_if; - unsigned char phys[MII_CNT]; - struct net_device *next; - int full_duplex:1; -} lpx; - -static struct pcnet32_private *lp; - -static int mdio_read(struct nic *nic __unused, int phy_id, int reg_num); -#if 0 -static void mdio_write(struct nic *nic __unused, int phy_id, int reg_num, - int val); -#endif -enum pci_flags_bit { - PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, - PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 = - 0x10 << 2, PCI_ADDR3 = 0x10 << 3, -}; - - -static u16 pcnet32_wio_read_csr(unsigned long addr, int index) -{ - outw(index, addr + PCNET32_WIO_RAP); - return inw(addr + PCNET32_WIO_RDP); -} - -static void pcnet32_wio_write_csr(unsigned long addr, int index, u16 val) -{ - outw(index, addr + PCNET32_WIO_RAP); - outw(val, addr + PCNET32_WIO_RDP); -} - -static u16 pcnet32_wio_read_bcr(unsigned long addr, int index) -{ - outw(index, addr + PCNET32_WIO_RAP); - return inw(addr + PCNET32_WIO_BDP); -} - -static void pcnet32_wio_write_bcr(unsigned long addr, int index, u16 val) -{ - outw(index, addr + PCNET32_WIO_RAP); - outw(val, addr + PCNET32_WIO_BDP); -} - -static u16 pcnet32_wio_read_rap(unsigned long addr) -{ - return inw(addr + PCNET32_WIO_RAP); -} - -static void pcnet32_wio_write_rap(unsigned long addr, u16 val) -{ - outw(val, addr + PCNET32_WIO_RAP); -} - -static void pcnet32_wio_reset(unsigned long addr) -{ - inw(addr + PCNET32_WIO_RESET); -} - -static int pcnet32_wio_check(unsigned long addr) -{ - outw(88, addr + PCNET32_WIO_RAP); - return (inw(addr + PCNET32_WIO_RAP) == 88); -} - -static struct pcnet32_access pcnet32_wio = { - read_csr:pcnet32_wio_read_csr, - write_csr:pcnet32_wio_write_csr, - read_bcr:pcnet32_wio_read_bcr, - write_bcr:pcnet32_wio_write_bcr, - read_rap:pcnet32_wio_read_rap, - write_rap:pcnet32_wio_write_rap, - reset:pcnet32_wio_reset -}; - -static u16 pcnet32_dwio_read_csr(unsigned long addr, int index) -{ - outl(index, addr + PCNET32_DWIO_RAP); - return (inl(addr + PCNET32_DWIO_RDP) & 0xffff); -} - -static void pcnet32_dwio_write_csr(unsigned long addr, int index, u16 val) -{ - outl(index, addr + PCNET32_DWIO_RAP); - outl(val, addr + PCNET32_DWIO_RDP); -} - -static u16 pcnet32_dwio_read_bcr(unsigned long addr, int index) -{ - outl(index, addr + PCNET32_DWIO_RAP); - return (inl(addr + PCNET32_DWIO_BDP) & 0xffff); -} - -static void pcnet32_dwio_write_bcr(unsigned long addr, int index, u16 val) -{ - outl(index, addr + PCNET32_DWIO_RAP); - outl(val, addr + PCNET32_DWIO_BDP); -} - -static u16 pcnet32_dwio_read_rap(unsigned long addr) -{ - return (inl(addr + PCNET32_DWIO_RAP) & 0xffff); -} - -static void pcnet32_dwio_write_rap(unsigned long addr, u16 val) -{ - outl(val, addr + PCNET32_DWIO_RAP); -} - -static void pcnet32_dwio_reset(unsigned long addr) -{ - inl(addr + PCNET32_DWIO_RESET); -} - -static int pcnet32_dwio_check(unsigned long addr) -{ - outl(88, addr + PCNET32_DWIO_RAP); - return ((inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88); -} - -static struct pcnet32_access pcnet32_dwio = { - read_csr:pcnet32_dwio_read_csr, - write_csr:pcnet32_dwio_write_csr, - read_bcr:pcnet32_dwio_read_bcr, - write_bcr:pcnet32_dwio_write_bcr, - read_rap:pcnet32_dwio_read_rap, - write_rap:pcnet32_dwio_write_rap, - reset:pcnet32_dwio_reset -}; - - -/* Initialize the PCNET32 Rx and Tx rings. */ -static int pcnet32_init_ring(struct nic *nic) -{ - int i; - - lp->tx_full = 0; - lp->cur_rx = lp->cur_tx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - pcnet32_bufs.rx_ring[i].base = - virt_to_le32desc(&pcnet32_bufs.rxb[i]); - pcnet32_bufs.rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); - pcnet32_bufs.rx_ring[i].status = le16_to_cpu(0x8000); - } - - /* The Tx buffer address is filled in as needed, but we do need to clear - the upper ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - pcnet32_bufs.tx_ring[i].base = 0; - pcnet32_bufs.tx_ring[i].status = 0; - } - - - lp->init_block.tlen_rlen = - le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = nic->node_addr[i]; - lp->init_block.rx_ring = virt_to_le32desc(&pcnet32_bufs.rx_ring[0]); - lp->init_block.tx_ring = virt_to_le32desc(&pcnet32_bufs.tx_ring[0]); - return 0; -} - -/************************************************************************** -RESET - Reset adapter -***************************************************************************/ -static void pcnet32_reset(struct nic *nic) -{ - /* put the card in its initial state */ - u16 val; - int i; - - /* Reset the PCNET32 */ - lp->a.reset(ioaddr); - - /* switch pcnet32 to 32bit mode */ - lp->a.write_bcr(ioaddr, 20, 2); - - /* set/reset autoselect bit */ - val = lp->a.read_bcr(ioaddr, 2) & ~2; - if (lp->options & PCNET32_PORT_ASEL) - val |= 2; - lp->a.write_bcr(ioaddr, 2, val); - - /* handle full duplex setting */ - if (lp->full_duplex) { - val = lp->a.read_bcr(ioaddr, 9) & ~3; - if (lp->options & PCNET32_PORT_FD) { - val |= 1; - if (lp->options == - (PCNET32_PORT_FD | PCNET32_PORT_AUI)) - val |= 2; - } else if (lp->options & PCNET32_PORT_ASEL) { - /* workaround of xSeries250, turn on for 79C975 only */ - i = ((lp->a. - read_csr(ioaddr, - 88) | (lp->a.read_csr(ioaddr, - 89) << 16)) >> - 12) & 0xffff; - if (i == 0x2627) - val |= 3; - } - lp->a.write_bcr(ioaddr, 9, val); - } - - /* set/reset GPSI bit in test register */ - val = lp->a.read_csr(ioaddr, 124) & ~0x10; - if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI) - val |= 0x10; - lp->a.write_csr(ioaddr, 124, val); - - if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { - val = lp->a.read_bcr(ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */ - if (lp->options & PCNET32_PORT_FD) - val |= 0x10; - if (lp->options & PCNET32_PORT_100) - val |= 0x08; - lp->a.write_bcr(ioaddr, 32, val); - } else { - if (lp->options & PCNET32_PORT_ASEL) { /* enable auto negotiate, setup, disable fd */ - val = lp->a.read_bcr(ioaddr, 32) & ~0x98; - val |= 0x20; - lp->a.write_bcr(ioaddr, 32, val); - } - } - -#ifdef DO_DXSUFLO - if (lp->dxsuflo) { /* Disable transmit stop on underflow */ - val = lp->a.read_csr(ioaddr, 3); - val |= 0x40; - lp->a.write_csr(ioaddr, 3, val); - } -#endif - if (1) - { - //disable interrupts - val = lp->a.read_csr(ioaddr, 3); - val = val - | (1 << 14) //BABLM intr disabled - | (1 << 12) //MISSM missed frame mask intr disabled - | (1 << 10) //RINTM receive intr disabled - | (1 << 9) //TINTM transmit intr disabled - | (1 << 8) //IDONM init done intr disabled - ; - lp->a.write_csr(ioaddr, 3, val); - } - - if (lp->ltint) { /* Enable TxDone-intr inhibitor */ - val = lp->a.read_csr(ioaddr, 5); - val |= (1 << 14); - lp->a.write_csr(ioaddr, 5, val); - } - lp->init_block.mode = - le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); - lp->init_block.filter[0] = 0xffffffff; - lp->init_block.filter[1] = 0xffffffff; - - pcnet32_init_ring(nic); - - - /* Re-initialize the PCNET32, and start it when done. */ - lp->a.write_csr(ioaddr, 1, - (virt_to_bus(&lp->init_block)) & 0xffff); - lp->a.write_csr(ioaddr, 2, (virt_to_bus(&lp->init_block)) >> 16); - lp->a.write_csr(ioaddr, 4, 0x0915); - lp->a.write_csr(ioaddr, 0, 0x0001); - - - i = 0; - while (i++ < 100) - if (lp->a.read_csr(ioaddr, 0) & 0x0100) - break; - /* - * We used to clear the InitDone bit, 0x0100, here but Mark Stockton - * reports that doing so triggers a bug in the '974. - */ - lp->a.write_csr(ioaddr, 0, 0x0042); - - dprintf(("pcnet32 open, csr0 %hX.\n", lp->a.read_csr(ioaddr, 0))); - -} - -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int pcnet32_poll(struct nic *nic __unused, int retrieve) -{ - /* return true if there's an ethernet packet ready to read */ - /* nic->packet should contain data on return */ - /* nic->packetlen should contain length of data */ - - signed char status; - int entry; - - entry = lp->cur_rx & RX_RING_MOD_MASK; - status = (le16_to_cpu(pcnet32_bufs.rx_ring[entry].status) >> 8); - - if (status < 0) - return 0; - - if ( ! retrieve ) return 1; - - if (status == 0x03) { - nic->packetlen = - (le32_to_cpu(pcnet32_bufs.rx_ring[entry].msg_length) - & 0xfff) - 4; - memcpy(nic->packet, &pcnet32_bufs.rxb[entry], nic->packetlen); - - /* Andrew Boyd of QNX reports that some revs of the 79C765 - * clear the buffer length */ - pcnet32_bufs.rx_ring[entry].buf_length - = le16_to_cpu(-PKT_BUF_SZ); - /* prime for next receive */ - pcnet32_bufs.rx_ring[entry].status |= le16_to_cpu(0x8000); - /* Switch to the next Rx ring buffer */ - lp->cur_rx++; - - } else { - return 0; - } - - return 1; -} - -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void pcnet32_transmit(struct nic *nic __unused, const char *d, /* Destination */ - unsigned int t, /* Type */ - unsigned int s, /* size */ - const char *p) -{ /* Packet */ - /* send the packet to destination */ - unsigned long time; - u8 *ptxb; - u16 nstype; - u16 status; - int entry = 0; /*lp->cur_tx & TX_RING_MOD_MASK; */ - - status = 0x8300; - /* point to the current txb incase multiple tx_rings are used */ - ptxb = pcnet32_bufs.txb[lp->cur_tx]; - - /* copy the packet to ring buffer */ - memcpy(ptxb, d, ETH_ALEN); /* dst */ - memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ - nstype = htons((u16) t); /* type */ - memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* type */ - memcpy(ptxb + ETH_HLEN, p, s); - - s += ETH_HLEN; - while (s < ETH_ZLEN) /* pad to min length */ - ptxb[s++] = '\0'; - - pcnet32_bufs.tx_ring[entry].length = le16_to_cpu(-s); - pcnet32_bufs.tx_ring[entry].misc = 0x00000000; - pcnet32_bufs.tx_ring[entry].base = (u32) virt_to_le32desc(ptxb); - - /* we set the top byte as the very last thing */ - pcnet32_bufs.tx_ring[entry].status = le16_to_cpu(status); - - - /* Trigger an immediate send poll */ - lp->a.write_csr(ioaddr, 0, 0x0048); - - /* wait for transmit complete */ - lp->cur_tx = 0; /* (lp->cur_tx + 1); */ - time = currticks() + TICKS_PER_SEC; /* wait one second */ - while (currticks() < time && - ((short) le16_to_cpu(pcnet32_bufs.tx_ring[entry].status) < 0)); - - if ((short) le16_to_cpu(pcnet32_bufs.tx_ring[entry].status) < 0) - printf("PCNET32 timed out on transmit\n"); - - /* Stop pointing at the current txb - * otherwise the card continues to send the packet */ - pcnet32_bufs.tx_ring[entry].base = 0; - -} - -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void pcnet32_disable ( struct nic *nic __unused ) { - /* Stop the PCNET32 here -- it ocassionally polls memory if we don't */ - lp->a.write_csr(ioaddr, 0, 0x0004); - - /* - * Switch back to 16-bit mode to avoid problems with dumb - * DOS packet driver after a warm reboot - */ - lp->a.write_bcr(ioaddr, 20, 0); -} - -/************************************************************************** -IRQ - Enable, Disable, or Force interrupts -***************************************************************************/ -static void pcnet32_irq(struct nic *nic __unused, irq_action_t action __unused) -{ - switch ( action ) { - case DISABLE : - break; - case ENABLE : - break; - case FORCE : - break; - } -} - - -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -You should omit the last argument struct pci_device * for a non-PCI NIC -***************************************************************************/ -static int pcnet32_probe ( struct nic *nic, struct pci_device *pci ) { - - int i, media; - int fdx, mii, fset, dxsuflo, ltint; - int chip_version; - struct pcnet32_access *a = NULL; - char *chipname; - u8 promaddr[6]; - int shared = 1; - - if (pci->ioaddr == 0) - return 0; - - /* BASE is used throughout to address the card */ - ioaddr = pci->ioaddr; - printf("pcnet32.c: Found %s, Vendor=0x%hX Device=0x%hX\n", - pci->driver_name, pci->vendor, pci->device); - - nic->irqno = 0; - nic->ioaddr = pci->ioaddr & ~3; - - /* reset the chip */ - pcnet32_wio_reset(ioaddr); - - /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ - if (pcnet32_wio_read_csr(ioaddr, 0) == 4 - && pcnet32_wio_check(ioaddr)) { - a = &pcnet32_wio; - } else { - pcnet32_dwio_reset(ioaddr); - if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 - && pcnet32_dwio_check(ioaddr)) { - a = &pcnet32_dwio; - } else - return 0; - } - - chip_version = - a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16); - - dprintf(("PCnet chip version is 0x%X\n", chip_version)); - if ((chip_version & 0xfff) != 0x003) - return 0; - - /* initialize variables */ - fdx = mii = fset = dxsuflo = ltint = 0; - chip_version = (chip_version >> 12) & 0xffff; - - switch (chip_version) { - case 0x2420: - chipname = "PCnet/PCI 79C970"; /* PCI */ - break; - case 0x2430: - if (shared) - chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ - else - chipname = "PCnet/32 79C965"; /* 486/VL bus */ - break; - case 0x2621: - chipname = "PCnet/PCI II 79C970A"; /* PCI */ - fdx = 1; - break; - case 0x2623: - chipname = "PCnet/FAST 79C971"; /* PCI */ - fdx = 1; - mii = 1; - fset = 1; - ltint = 1; - break; - case 0x2624: - chipname = "PCnet/FAST+ 79C972"; /* PCI */ - fdx = 1; - mii = 1; - fset = 1; - break; - case 0x2625: - chipname = "PCnet/FAST III 79C973"; /* PCI */ - fdx = 1; - mii = 1; - break; - case 0x2626: - chipname = "PCnet/Home 79C978"; /* PCI */ - fdx = 1; - /* - * This is based on specs published at www.amd.com. This section - * assumes that a card with a 79C978 wants to go into 1Mb HomePNA - * mode. The 79C978 can also go into standard ethernet, and there - * probably should be some sort of module option to select the - * mode by which the card should operate - */ - /* switch to home wiring mode */ - media = a->read_bcr(ioaddr, 49); - - printf("media reset to %#x.\n", media); - a->write_bcr(ioaddr, 49, media); - break; - case 0x2627: - chipname = "PCnet/FAST III 79C975"; /* PCI */ - fdx = 1; - mii = 1; - break; - default: - chipname = "UNKNOWN"; - printf("PCnet version %#x, no PCnet32 chip.\n", - chip_version); - return 0; - } - - /* - * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit - * starting until the packet is loaded. Strike one for reliability, lose - * one for latency - although on PCI this isnt a big loss. Older chips - * have FIFO's smaller than a packet, so you can't do this. - */ - - if (fset) { - a->write_bcr(ioaddr, 18, - (a->read_bcr(ioaddr, 18) | 0x0800)); - a->write_csr(ioaddr, 80, - (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); - dxsuflo = 1; - ltint = 1; - } - - DBG ( "%s at %hX,", chipname, (unsigned int) ioaddr ); - - /* read PROM address */ - for (i = 0; i < 6; i++) - promaddr[i] = inb(ioaddr + i); - - /* Update the nic structure with the MAC Address */ - for (i = 0; i < ETH_ALEN; i++) { - nic->node_addr[i] = promaddr[i]; - } - - /* Print out some hardware info */ - DBG ( "%s: IO Addr 0x%hX, MAC Addr %s\n ", chipname, (unsigned int) ioaddr, - eth_ntoa ( nic->node_addr ) ); - - /* Set to pci bus master */ - adjust_pci_device(pci); - - /* point to private storage */ - lp = &lpx; - -#if EBDEBUG - if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */ - i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ - dprintf((" tx_start_pt(0x%hX):", i)); - switch (i >> 10) { - case 0: - dprintf((" 20 bytes,")); - break; - case 1: - dprintf((" 64 bytes,")); - break; - case 2: - dprintf((" 128 bytes,")); - break; - case 3: - dprintf(("~220 bytes,")); - break; - } - i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ - dprintf((" BCR18(%hX):", i & 0xffff)); - if (i & (1 << 5)) - dprintf(("BurstWrEn ")); - if (i & (1 << 6)) - dprintf(("BurstRdEn ")); - if (i & (1 << 7)) - dprintf(("DWordIO ")); - if (i & (1 << 11)) - dprintf(("NoUFlow ")); - i = a->read_bcr(ioaddr, 25); - dprintf((" SRAMSIZE=0x%hX,", i << 8)); - i = a->read_bcr(ioaddr, 26); - dprintf((" SRAM_BND=0x%hX,", i << 8)); - i = a->read_bcr(ioaddr, 27); - if (i & (1 << 14)) - dprintf(("LowLatRx")); - } -#endif - lp->name = chipname; - lp->shared_irq = shared; - lp->full_duplex = fdx; - lp->dxsuflo = dxsuflo; - lp->ltint = ltint; - lp->mii = mii; - /* FIXME: Fix Options for only one card */ - if ((cards_found >= MAX_UNITS) - || ((unsigned int) options[cards_found] > sizeof(options_mapping))) - lp->options = PCNET32_PORT_ASEL; - else - lp->options = options_mapping[options[cards_found]]; - - if (fdx && !(lp->options & PCNET32_PORT_ASEL) && - ((cards_found >= MAX_UNITS) || full_duplex[cards_found])) - lp->options |= PCNET32_PORT_FD; - - if (!a) { - printf("No access methods\n"); - return 0; - } - - // lp->a = *a; - // Causes a loader: - // bin/blib.a(pcnet32.o)(.text+0x6b6): In function `pcnet32_probe': - // drivers/net/pcnet32.c:871: undefined reference to `memcpy' - // make: *** [bin/pcnet32.dsk.tmp] Error 1 - // So we do: - memcpy ( &lp->a, a, sizeof ( lp->a ) ); - // To explicity call memcpy. - - /* detect special T1/E1 WAN card by checking for MAC address */ - if (nic->node_addr[0] == 0x00 && nic->node_addr[1] == 0xe0 - && nic->node_addr[2] == 0x75) - lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; - - lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ - lp->init_block.tlen_rlen = - le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = nic->node_addr[i]; - lp->init_block.filter[0] = 0xffffffff; - lp->init_block.filter[1] = 0xffffffff; - lp->init_block.rx_ring = virt_to_bus(&pcnet32_bufs.rx_ring); - lp->init_block.tx_ring = virt_to_bus(&pcnet32_bufs.tx_ring); - - /* switch pcnet32 to 32bit mode */ - a->write_bcr(ioaddr, 20, 2); - - a->write_csr(ioaddr, 1, (virt_to_bus(&lp->init_block)) & 0xffff); - a->write_csr(ioaddr, 2, (virt_to_bus(&lp->init_block)) >> 16); - - /* - * To auto-IRQ we enable the initialization-done and DMA error - * interrupts. For ISA boards we get a DMA error, but VLB and PCI - * boards will work. - */ - /* Trigger an initialization just for the interrupt. */ - - -// a->write_csr(ioaddr, 0, 0x41); -// mdelay(1); - - cards_found++; - - /* point to NIC specific routines */ - pcnet32_reset(nic); - if (mii) { - int tmp; - int phy, phy_idx = 0; - u16 mii_lpa; - lp->phys[0] = 1; /* Default Setting */ - for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(nic, phy, MII_BMSR); - if (mii_status != 0xffff && mii_status != 0x0000) { - lp->phys[phy_idx++] = phy; - lp->mii_if.advertising = - mdio_read(nic, phy, MII_ADVERTISE); - if ((mii_status & 0x0040) == 0) { - tmp = phy; - dprintf (("MII PHY found at address %d, status " - "%hX advertising %hX\n", phy, mii_status, - lp->mii_if.advertising)); - } - } - } - if (phy_idx == 0) - printf("No MII transceiver found!\n"); - lp->mii_if.phy_id = lp->phys[0]; - - lp->mii_if.advertising = - mdio_read(nic, lp->phys[0], MII_ADVERTISE); - - mii_lpa = mdio_read(nic, lp->phys[0], MII_LPA); - lp->mii_if.advertising &= mii_lpa; - if (lp->mii_if.advertising & ADVERTISE_100FULL) - printf("100Mbps Full-Duplex\n"); - else if (lp->mii_if.advertising & ADVERTISE_100HALF) - printf("100Mbps Half-Duplex\n"); - else if (lp->mii_if.advertising & ADVERTISE_10FULL) - printf("10Mbps Full-Duplex\n"); - else if (lp->mii_if.advertising & ADVERTISE_10HALF) - printf("10Mbps Half-Duplex\n"); - else - printf("\n"); - } else { - /* The older chips are fixed 10Mbps, and some support full duplex, - * although not via autonegotiation, but only via configuration. */ - if (fdx) - printf("10Mbps Full-Duplex\n"); - else - printf("10Mbps Half-Duplex\n"); - } - - nic->nic_op = &pcnet32_operations; - - return 1; -} -static int mdio_read(struct nic *nic __unused, int phy_id, int reg_num) -{ - u16 val_out; - int phyaddr; - - if (!lp->mii) - return 0; - - phyaddr = lp->a.read_bcr(ioaddr, 33); - - lp->a.write_bcr(ioaddr, 33, - ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); - val_out = lp->a.read_bcr(ioaddr, 34); - lp->a.write_bcr(ioaddr, 33, phyaddr); - - return val_out; -} - -#if 0 -static void mdio_write(struct nic *nic __unused, int phy_id, int reg_num, - int val) -{ - int phyaddr; - - if (!lp->mii) - return; - - phyaddr = lp->a.read_bcr(ioaddr, 33); - - lp->a.write_bcr(ioaddr, 33, - ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); - lp->a.write_bcr(ioaddr, 34, val); - lp->a.write_bcr(ioaddr, 33, phyaddr); -} -#endif - -static struct nic_operations pcnet32_operations = { - .connect = dummy_connect, - .poll = pcnet32_poll, - .transmit = pcnet32_transmit, - .irq = pcnet32_irq, - -}; - -static struct pci_device_id pcnet32_nics[] = { - PCI_ROM(0x1022, 0x2000, "pcnet32", "AMD PCnet/PCI", 0), - PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD PCNet FAST III", 0), - PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD PCnet/HomePNA", 0), -}; - -PCI_DRIVER ( pcnet32_driver, pcnet32_nics, PCI_NO_CLASS ); - -DRIVER ( "PCNET32/PCI", nic_driver, pci_driver, pcnet32_driver, - pcnet32_probe, pcnet32_disable ); - -/* - * Local variables: - * c-basic-offset: 8 - * c-indent-level: 8 - * tab-width: 8 - * End: - */ |