From ca67b09c015d4af3ae3cce12aa72e60941dbb8b5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:29:52 +0200 Subject: Adding debian version 2.06-13+deb12u1. Signed-off-by: Daniel Baumann --- .../disabled/gpxe/src/drivers/net/eepro100.c | 853 +++++++++++++++++++++ 1 file changed, 853 insertions(+) create mode 100644 debian/grub-extras/disabled/gpxe/src/drivers/net/eepro100.c (limited to 'debian/grub-extras/disabled/gpxe/src/drivers/net/eepro100.c') diff --git a/debian/grub-extras/disabled/gpxe/src/drivers/net/eepro100.c b/debian/grub-extras/disabled/gpxe/src/drivers/net/eepro100.c new file mode 100644 index 0000000..85d7571 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/drivers/net/eepro100.c @@ -0,0 +1,853 @@ +/* + * eepro100.c -- This file implements the eepro100 driver for etherboot. + * + * + * Copyright (C) AW Computer Systems. + * written by R.E.Wolff -- R.E.Wolff@BitWizard.nl + * + * + * AW Computer Systems is contributing to the free software community + * by paying for this driver and then putting the result under GPL. + * + * If you need a Linux device driver, please contact BitWizard for a + * quote. + * + * + * 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, 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. + * + * + * date version by what + * Written: May 29 1997 V0.10 REW Initial revision. + * changes: May 31 1997 V0.90 REW Works! + * Jun 1 1997 V0.91 REW Cleanup + * Jun 2 1997 V0.92 REW Add some code documentation + * Jul 25 1997 V1.00 REW Tested by AW to work in a PROM + * Cleanup for publication + * Dez 11 2004 V1.10 Kiszka Add RX ring buffer support + * + * This is the etherboot intel etherexpress Pro/100B driver. + * + * It was written from scratch, with Donald Beckers eepro100.c kernel + * driver as a guideline. Mostly the 82557 related definitions and the + * lower level routines have been cut-and-pasted into this source. + * + * The driver was finished before Intel got the NDA out of the closet. + * I still don't have the docs. + * + * + * Datasheet is now published and available from + * ftp://download.intel.com/design/network/manuals/8255X_OpenSDM.pdf + * - Michael Brown + * */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/* Philosophy of this driver. + * + * Probing: + * + * Using the pci.c functions of the Etherboot code, the 82557 chip is detected. + * It is verified that the BIOS initialized everything properly and if + * something is missing it is done now. + * + * + * Initialization: + * + * + * The chip is then initialized to "know" its ethernet address, and to + * start recieving packets. The Linux driver has a whole transmit and + * recieve ring of buffers. This is neat if you need high performance: + * you can write the buffers asynchronously to the chip reading the + * buffers and transmitting them over the network. Performance is NOT + * an issue here. We can boot a 400k kernel in about two + * seconds. (Theory: 0.4 seconds). Booting a system is going to take + * about half a minute anyway, so getting 10 times closer to the + * theoretical limit is going to make a difference of a few percent. */ +/* Not totally true: busy networks can cause packet drops due to RX + * buffer overflows. Fixed in V1.10 of this driver. [Kiszka] */ +/* + * + * Transmitting and recieving. + * + * We have only one transmit descriptor. It has two buffer descriptors: + * one for the header, and the other for the data. + * We have multiple receive buffers (currently: 4). The chip is told to + * receive packets and suspend itself once it ran on the last free buffer. + * The recieve (poll) routine simply looks at the current recieve buffer, + * picks the packet if any, and releases this buffer again (classic ring + * buffer concept). This helps to avoid packet drops on busy networks. + * + * Caveats: + * + * The Etherboot framework moves the code to the 48k segment from + * 0x94000 to 0xa0000. There is just a little room between the end of + * this driver and the 0xa0000 address. If you compile in too many + * features, this will overflow. + * The number under "hex" in the output of size that scrolls by while + * compiling should be less than 8000. Maybe even the stack is up there, + * so that you need even more headroom. + */ + +/* The etherboot authors seem to dislike the argument ordering in + * outb macros that Linux uses. I disklike the confusion that this + * has caused even more.... This file uses the Linux argument ordering. */ +/* Sorry not us. It's inherited code from FreeBSD. [The authors] */ + +#include "etherboot.h" +#include "nic.h" +#include +#include + +static int ioaddr; + +enum speedo_offsets { + SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ + SCBPointer = 4, /* General purpose pointer. */ + SCBPort = 8, /* Misc. commands and operands. */ + SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ + SCBCtrlMDI = 16, /* MDI interface control. */ + SCBEarlyRx = 20, /* Early receive byte count. */ +}; + +enum SCBCmdBits { + SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000, + SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400, + SCBTriggerIntr=0x0200, SCBMaskAll=0x0100, + /* The rest are Rx and Tx commands. */ + CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050, + CUCmdBase=0x0060, /* CU Base address (set to zero) . */ + CUDumpStats=0x0070, /* Dump then reset stats counters. */ + RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006, + RxResumeNoResources=0x0007, +}; + +static int do_eeprom_cmd(int cmd, int cmd_len); +void hd(void *where, int n); + +/***********************************************************************/ +/* I82557 related defines */ +/***********************************************************************/ + +/* Serial EEPROM section. + A "bit" grungy, but we work our way through bit-by-bit :->. */ +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_WRITE_0 0x4802 +#define EE_WRITE_1 0x4806 +#define EE_ENB (0x4800 | EE_CS) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_READ_CMD 6 + +/* The SCB accepts the following controls for the Tx and Rx units: */ +#define CU_START 0x0010 +#define CU_RESUME 0x0020 +#define CU_STATSADDR 0x0040 +#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */ +#define CU_CMD_BASE 0x0060 /* Base address to add to add CU commands. */ +#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */ + +#define RX_START 0x0001 +#define RX_RESUME 0x0002 +#define RX_ABORT 0x0004 +#define RX_ADDR_LOAD 0x0006 +#define RX_RESUMENR 0x0007 +#define INT_MASK 0x0100 +#define DRVR_INT 0x0200 /* Driver generated interrupt. */ + +enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, + S80C24, PhyUndefined, DP83840A=10, }; + +/* Commands that can be put in a command list entry. */ +enum commands { + CmdNOp = 0, + CmdIASetup = 1, + CmdConfigure = 2, + CmdMulticastList = 3, + CmdTx = 4, + CmdTDR = 5, + CmdDump = 6, + CmdDiagnose = 7, + + /* And some extra flags: */ + CmdSuspend = 0x4000, /* Suspend after completion. */ + CmdIntr = 0x2000, /* Interrupt after completion. */ + CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */ +}; + +/* How to wait for the command unit to accept a command. + Typically this takes 0 ticks. */ +static inline void wait_for_cmd_done(int cmd_ioaddr) +{ + int wait = 0; + int delayed_cmd; + + do + if (inb(cmd_ioaddr) == 0) return; + while(++wait <= 100); + delayed_cmd = inb(cmd_ioaddr); + do + if (inb(cmd_ioaddr) == 0) break; + while(++wait <= 10000); + printf("Command %2.2x was not immediately accepted, %d ticks!\n", + delayed_cmd, wait); +} + +/* Elements of the dump_statistics block. This block must be lword aligned. */ +static struct speedo_stats { + u32 tx_good_frames; + u32 tx_coll16_errs; + u32 tx_late_colls; + u32 tx_underruns; + u32 tx_lost_carrier; + u32 tx_deferred; + u32 tx_one_colls; + u32 tx_multi_colls; + u32 tx_total_colls; + u32 rx_good_frames; + u32 rx_crc_errs; + u32 rx_align_errs; + u32 rx_resource_errs; + u32 rx_overrun_errs; + u32 rx_colls_errs; + u32 rx_runt_errs; + u32 done_marker; +} lstats; + +/* A speedo3 TX buffer descriptor with two buffers... */ +static struct TxFD { + volatile s16 status; + s16 command; + u32 link; /* void * */ + u32 tx_desc_addr; /* (almost) Always points to the tx_buf_addr element. */ + s32 count; /* # of TBD (=2), Tx start thresh., etc. */ + /* This constitutes two "TBD" entries: hdr and data */ + u32 tx_buf_addr0; /* void *, header of frame to be transmitted. */ + s32 tx_buf_size0; /* Length of Tx hdr. */ + u32 tx_buf_addr1; /* void *, data to be transmitted. */ + s32 tx_buf_size1; /* Length of Tx data. */ +} txfd; + +struct RxFD { /* Receive frame descriptor. */ + volatile s16 status; + s16 command; + u32 link; /* struct RxFD * */ + u32 rx_buf_addr; /* void * */ + u16 count; + u16 size; + char packet[1518]; +}; + +static struct nic_operations eepro100_operations; + +#define RXFD_COUNT 4 +struct { + struct RxFD rxfds[RXFD_COUNT]; +} eepro100_bufs __shared; +#define rxfds eepro100_bufs.rxfds +static unsigned int rxfd = 0; + +static int congenb = 0; /* Enable congestion control in the DP83840. */ +static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ +static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ +static int txdmacount = 0; /* Tx DMA burst length, 0-127, default 0. */ +static int rxdmacount = 0; /* Rx DMA length, 0 means no preemption. */ + +/* I don't understand a byte in this structure. It was copied from the + * Linux kernel initialization for the eepro100. -- REW */ +static struct ConfCmd { + s16 status; + s16 command; + u32 link; + unsigned char data[22]; +} confcmd = { + 0, 0, 0, /* filled in later */ + {22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ + 0, 0x2E, 0, 0x60, 0, + 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ + 0x3f, 0x05, } +}; + +/***********************************************************************/ +/* Locally used functions */ +/***********************************************************************/ + +/* Support function: mdio_write + * + * This probably writes to the "physical media interface chip". + * -- REW + */ + +static int mdio_write(int phy_id, int location, int value) +{ + int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + + outl(0x04000000 | (location<<16) | (phy_id<<21) | value, + ioaddr + SCBCtrlMDI); + do { + udelay(16); + + val = inl(ioaddr + SCBCtrlMDI); + if (--boguscnt < 0) { + printf(" mdio_write() timed out with val = %X.\n", val); + break; + } + } while (! (val & 0x10000000)); + return val & 0xffff; +} + +/* Support function: mdio_read + * + * This probably reads a register in the "physical media interface chip". + * -- REW + */ +static int mdio_read(int phy_id, int location) +{ + int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); + do { + udelay(16); + + val = inl(ioaddr + SCBCtrlMDI); + + if (--boguscnt < 0) { + printf( " mdio_read() timed out with val = %X.\n", val); + break; + } + } while (! (val & 0x10000000)); + return val & 0xffff; +} + +/* The fixes for the code were kindly provided by Dragan Stancevic + to strictly follow Intel specifications of EEPROM + access timing. + The publicly available sheet 64486302 (sec. 3.1) specifies 1us access + interval for serial EEPROM. However, it looks like that there is an + additional requirement dictating larger udelay's in the code below. + 2000/05/24 SAW */ +static int do_eeprom_cmd(int cmd, int cmd_len) +{ + unsigned retval = 0; + long ee_addr = ioaddr + SCBeeprom; + + outw(EE_ENB, ee_addr); udelay(2); + outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2); + + /* Shift the command bits out. */ + do { + short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; + outw(dataval, ee_addr); udelay(2); + outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2); + retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); + } while (--cmd_len >= 0); + outw(EE_ENB, ee_addr); udelay(2); + + /* Terminate the EEPROM access. */ + outw(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +#if 0 +static inline void whereami (const char *str) +{ + printf ("%s\n", str); + sleep (2); +} +#else +#define whereami(s) +#endif + +static void eepro100_irq(struct nic *nic __unused, irq_action_t action) +{ + uint16_t enabled_mask = ( SCBMaskCmdDone | SCBMaskCmdIdle | + SCBMaskEarlyRx | SCBMaskFlowCtl ); + + switch ( action ) { + case DISABLE : + outw(SCBMaskAll, ioaddr + SCBCmd); + break; + case ENABLE : + outw(enabled_mask, ioaddr + SCBCmd); + break; + case FORCE : + outw(enabled_mask | SCBTriggerIntr, ioaddr + SCBCmd); + break; + } +} + +/* function: eepro100_transmit + * This transmits a packet. + * + * Arguments: char d[6]: destination ethernet address. + * unsigned short t: ethernet protocol type. + * unsigned short s: size of the data-part of the packet. + * char *p: the data for the packet. + * returns: void. + */ + +static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p) +{ + struct eth_hdr { + unsigned char dst_addr[ETH_ALEN]; + unsigned char src_addr[ETH_ALEN]; + unsigned short type; + } hdr; + unsigned short status; + int s1, s2; + unsigned long ct; + + status = inw(ioaddr + SCBStatus); + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(status & 0xfc00, ioaddr + SCBStatus); + +#ifdef DEBUG + printf ("transmitting type %hX packet (%d bytes). status = %hX, cmd=%hX\n", + t, s, status, inw (ioaddr + SCBCmd)); +#endif + + memcpy (&hdr.dst_addr, d, ETH_ALEN); + memcpy (&hdr.src_addr, nic->node_addr, ETH_ALEN); + + hdr.type = htons (t); + + txfd.status = 0; + txfd.command = CmdSuspend | CmdTx | CmdTxFlex; + txfd.link = virt_to_bus (&txfd); + txfd.count = 0x02208000; + txfd.tx_desc_addr = virt_to_bus(&txfd.tx_buf_addr0); + + txfd.tx_buf_addr0 = virt_to_bus (&hdr); + txfd.tx_buf_size0 = sizeof (hdr); + + txfd.tx_buf_addr1 = virt_to_bus (p); + txfd.tx_buf_size1 = s; + +#ifdef DEBUG + printf ("txfd: \n"); + hd (&txfd, sizeof (txfd)); +#endif + + outl(virt_to_bus(&txfd), ioaddr + SCBPointer); + outb(CU_START, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + s1 = inw (ioaddr + SCBStatus); + + ct = currticks(); + /* timeout 10 ms for transmit */ + while (!txfd.status && ct + 10*1000) + /* Wait */; + s2 = inw (ioaddr + SCBStatus); + +#ifdef DEBUG + printf ("s1 = %hX, s2 = %hX.\n", s1, s2); +#endif +} + +/* + * Sometimes the receiver stops making progress. This routine knows how to + * get it going again, without losing packets or being otherwise nasty like + * a chip reset would be. Previously the driver had a whole sequence + * of if RxSuspended, if it's no buffers do one thing, if it's no resources, + * do another, etc. But those things don't really matter. Separate logic + * in the ISR provides for allocating buffers--the other half of operation + * is just making sure the receiver is active. speedo_rx_soft_reset does that. + * This problem with the old, more involved algorithm is shown up under + * ping floods on the order of 60K packets/second on a 100Mbps fdx network. + */ +static void +speedo_rx_soft_reset(void) +{ + int i; + + +#ifdef DEBUG + printf("reset\n"); +#endif + wait_for_cmd_done(ioaddr + SCBCmd); + /* + * Put the hardware into a known state. + */ + outb(RX_ABORT, ioaddr + SCBCmd); + + for (i = 0; i < RXFD_COUNT; i++) { + rxfds[i].status = 0; + rxfds[i].rx_buf_addr = 0xffffffff; + rxfds[i].count = 0; + rxfds[i].size = 1528; + } + + wait_for_cmd_done(ioaddr + SCBCmd); + + outl(virt_to_bus(&rxfds[rxfd]), ioaddr + SCBPointer); + outb(RX_START, ioaddr + SCBCmd); +} + +/* function: eepro100_poll / eth_poll + * This receives a packet from the network. + * + * Arguments: none + * + * returns: 1 if a packet was received. + * 0 if no packet was received. + * side effects: + * returns the packet in the array nic->packet. + * returns the length of the packet in nic->packetlen. + */ + +static int eepro100_poll(struct nic *nic, int retrieve) +{ + if (rxfds[rxfd].status) { + if (!retrieve) + return 1; +#ifdef DEBUG + printf("Got a packet: Len = %d, rxfd = %d.\n", + rxfds[rxfd].count & 0x3fff, rxfd); +#endif + /* First save the data from the rxfd */ + nic->packetlen = rxfds[rxfd].count & 0x3fff; + memcpy(nic->packet, rxfds[rxfd].packet, nic->packetlen); + + rxfds[rxfd].status = 0; + rxfds[rxfd].command = 0xc000; + rxfds[rxfd].rx_buf_addr = 0xFFFFFFFF; + rxfds[rxfd].count = 0; + rxfds[rxfd].size = 1528; + rxfds[(rxfd-1) % RXFD_COUNT].command = 0x0000; + rxfd = (rxfd+1) % RXFD_COUNT; + +#ifdef DEBUG + hd (nic->packet, 0x30); +#endif + + /* Acknowledge all conceivable interrupts */ + outw(0xff00, ioaddr + SCBStatus); + + return 1; + } + + /* + * The chip may have suspended reception for various reasons. + * Check for that, and re-prime it should this be the case. + */ + switch ((inw(ioaddr + SCBStatus) >> 2) & 0xf) { + case 0: /* Idle */ + break; + case 1: /* Suspended */ + case 2: /* No resources (RxFDs) */ + case 9: /* Suspended with no more RBDs */ + case 10: /* No resources due to no RBDs */ + case 12: /* Ready with no RBDs */ + speedo_rx_soft_reset(); + break; + default: + /* reserved values */ + break; + } + return 0; +} + +/* function: eepro100_disable + * resets the card. This is used to allow Etherboot or Linux + * to probe the card again from a "virginal" state.... + * Arguments: none + * + * returns: void. + */ +static void eepro100_disable ( struct nic *nic __unused ) { +/* from eepro100_reset */ + outl(0, ioaddr + SCBPort); +/* from eepro100_disable */ + /* See if this PartialReset solves the problem with interfering with + kernel operation after Etherboot hands over. - Ken 20001102 */ + outl(2, ioaddr + SCBPort); + + /* The following is from the Intel e100 driver. + * This hopefully solves the problem with hanging hard DOS images. */ + + /* wait for the reset to take effect */ + udelay(20); + + /* Mask off our interrupt line -- it is unmasked after reset */ + { + u16 intr_status; + /* Disable interrupts on our PCI board by setting the mask bit */ + outw(INT_MASK, ioaddr + SCBCmd); + intr_status = inw(ioaddr + SCBStatus); + /* ack and clear intrs */ + outw(intr_status, ioaddr + SCBStatus); + inw(ioaddr + SCBStatus); + } +} + +/* exported function: eepro100_probe / eth_probe + * initializes a card + * + * side effects: + * leaves the ioaddress of the 82557 chip in the variable ioaddr. + * leaves the 82557 initialized, and ready to recieve packets. + */ + +static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) { + + unsigned short sum = 0; + int i; + int read_cmd, ee_size; + int options; + int rx_mode; + unsigned long ct; + + /* we cache only the first few words of the EEPROM data + be careful not to access beyond this array */ + unsigned short eeprom[16]; + + if (pci->ioaddr == 0) + return 0; + + adjust_pci_device(pci); + + nic->ioaddr = pci->ioaddr; + nic->irqno = pci->irq; + + ioaddr = nic->ioaddr; + + if ((do_eeprom_cmd(EE_READ_CMD << 24, 27) & 0xffe0000) + == 0xffe0000) { + ee_size = 0x100; + read_cmd = EE_READ_CMD << 24; + } else { + ee_size = 0x40; + read_cmd = EE_READ_CMD << 22; + } + + for (i = 0, sum = 0; i < ee_size; i++) { + unsigned short value = do_eeprom_cmd(read_cmd | (i << 16), 27); + if (i < (int)(sizeof(eeprom)/sizeof(eeprom[0]))) + eeprom[i] = value; + sum += value; + } + + for (i=0;inode_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff; + } + + DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) ); + + if (sum != 0xBABA) + printf("eepro100: Invalid EEPROM checksum %#hX, " + "check settings before activating this device!\n", sum); + outl(0, ioaddr + SCBPort); + udelay (10000); + whereami ("Got eeprom."); + + /* Base = 0, disable all interrupts */ + outl(0, ioaddr + SCBPointer); + outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + whereami ("set rx base addr."); + + outl(virt_to_bus(&lstats), ioaddr + SCBPointer); + outb(CU_STATSADDR, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + whereami ("set stats addr."); + + /* INIT RX stuff. */ + for (i = 0; i < RXFD_COUNT; i++) { + rxfds[i].status = 0x0000; + rxfds[i].command = 0x0000; + rxfds[i].rx_buf_addr = 0xFFFFFFFF; + rxfds[i].count = 0; + rxfds[i].size = 1528; + rxfds[i].link = virt_to_bus(&rxfds[i+1]); + } + + rxfds[RXFD_COUNT-1].status = 0x0000; + rxfds[RXFD_COUNT-1].command = 0xC000; + rxfds[RXFD_COUNT-1].link = virt_to_bus(&rxfds[0]); + + outl(virt_to_bus(&rxfds[0]), ioaddr + SCBPointer); + outb(RX_START, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("started RX process."); + + /* INIT TX stuff. */ + + /* Base = 0 */ + outl(0, ioaddr + SCBPointer); + outb(CU_CMD_BASE, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("set TX base addr."); + + txfd.command = (CmdIASetup); + txfd.status = 0x0000; + txfd.link = virt_to_bus (&confcmd); + + { + char *t = (char *)&txfd.tx_desc_addr; + + for (i=0;inode_addr[i]; + } + +#ifdef DEBUG + printf ("Setup_eaddr:\n"); + hd (&txfd, 0x20); +#endif + /* options = 0x40; */ /* 10mbps half duplex... */ + options = 0x00; /* Autosense */ + +#ifdef PROMISC + rx_mode = 3; +#elif ALLMULTI + rx_mode = 1; +#else + rx_mode = 0; +#endif + + if ( ((eeprom[6]>>8) & 0x3f) == DP83840 + || ((eeprom[6]>>8) & 0x3f) == DP83840A) { + int mdi_reg23 = mdio_read(eeprom[6] & 0x1f, 23) | 0x0422; + if (congenb) + mdi_reg23 |= 0x0100; + printf(" DP83840 specific setup, setting register 23 to %hX.\n", + mdi_reg23); + mdio_write(eeprom[6] & 0x1f, 23, mdi_reg23); + } + whereami ("Done DP8340 special setup."); + if (options != 0) { + mdio_write(eeprom[6] & 0x1f, 0, + ((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + whereami ("set mdio_register."); + } + + confcmd.command = CmdSuspend | CmdConfigure; + confcmd.status = 0x0000; + confcmd.link = virt_to_bus (&txfd); + confcmd.data[1] = (txfifo << 4) | rxfifo; + confcmd.data[4] = rxdmacount; + confcmd.data[5] = txdmacount + 0x80; + confcmd.data[15] = (rx_mode & 2) ? 0x49: 0x48; + confcmd.data[19] = (options & 0x10) ? 0xC0 : 0x80; + confcmd.data[21] = (rx_mode & 1) ? 0x0D: 0x05; + + outl(virt_to_bus(&txfd), ioaddr + SCBPointer); + outb(CU_START, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("started TX thingy (config, iasetup)."); + + ct = currticks(); + while (!txfd.status && ct + 10*1000 < currticks()) + /* Wait */; + + /* Read the status register once to disgard stale data */ + mdio_read(eeprom[6] & 0x1f, 1); + /* Check to see if the network cable is plugged in. + * This allows for faster failure if there is nothing + * we can do. + */ + if (!(mdio_read(eeprom[6] & 0x1f, 1) & (1 << 2))) { + printf("Valid link not established\n"); + eepro100_disable(nic); + return 0; + } + nic->nic_op = &eepro100_operations; + return 1; +} + +/*********************************************************************/ + +#ifdef DEBUG + +/* Hexdump a number of bytes from memory... */ +void hd (void *where, int n) +{ + int i; + + while (n > 0) { + printf ("%X ", where); + for (i=0;i < ( (n>16)?16:n);i++) + printf (" %hhX", ((char *)where)[i]); + printf ("\n"); + n -= 16; + where += 16; + } +} +#endif + +static struct nic_operations eepro100_operations = { + .connect = dummy_connect, + .poll = eepro100_poll, + .transmit = eepro100_transmit, + .irq = eepro100_irq, + +}; + +static struct pci_device_id eepro100_nics[] = { +PCI_ROM(0x8086, 0x1029, "id1029", "Intel EtherExpressPro100 ID1029", 0), +PCI_ROM(0x8086, 0x1030, "id1030", "Intel EtherExpressPro100 ID1030", 0), +PCI_ROM(0x8086, 0x1031, "82801cam", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), +PCI_ROM(0x8086, 0x1032, "eepro100-1032", "Intel PRO/100 VE Network Connection", 0), +PCI_ROM(0x8086, 0x1033, "eepro100-1033", "Intel PRO/100 VM Network Connection", 0), +PCI_ROM(0x8086, 0x1034, "eepro100-1034", "Intel PRO/100 VM Network Connection", 0), +PCI_ROM(0x8086, 0x1035, "eepro100-1035", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), +PCI_ROM(0x8086, 0x1036, "eepro100-1036", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), +PCI_ROM(0x8086, 0x1037, "eepro100-1037", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0), +PCI_ROM(0x8086, 0x1038, "id1038", "Intel PRO/100 VM Network Connection", 0), +PCI_ROM(0x8086, 0x1039, "82562et", "Intel PRO100 VE 82562ET", 0), +PCI_ROM(0x8086, 0x103a, "id103a", "Intel Corporation 82559 InBusiness 10/100", 0), +PCI_ROM(0x8086, 0x103b, "82562etb", "Intel PRO100 VE 82562ETB", 0), +PCI_ROM(0x8086, 0x103c, "eepro100-103c", "Intel PRO/100 VM Network Connection", 0), +PCI_ROM(0x8086, 0x103d, "eepro100-103d", "Intel PRO/100 VE Network Connection", 0), +PCI_ROM(0x8086, 0x103e, "eepro100-103e", "Intel PRO/100 VM Network Connection", 0), +PCI_ROM(0x8086, 0x1051, "prove", "Intel PRO/100 VE Network Connection", 0), +PCI_ROM(0x8086, 0x1059, "82551qm", "Intel PRO/100 M Mobile Connection", 0), +PCI_ROM(0x8086, 0x1209, "82559er", "Intel EtherExpressPro100 82559ER", 0), +PCI_ROM(0x8086, 0x1227, "82865", "Intel 82865 EtherExpress PRO/100A", 0), +PCI_ROM(0x8086, 0x1228, "82556", "Intel 82556 EtherExpress PRO/100 Smart", 0), +PCI_ROM(0x8086, 0x1229, "eepro100", "Intel EtherExpressPro100", 0), +PCI_ROM(0x8086, 0x2449, "82562em", "Intel EtherExpressPro100 82562EM", 0), +PCI_ROM(0x8086, 0x2459, "82562-1", "Intel 82562 based Fast Ethernet Connection", 0), +PCI_ROM(0x8086, 0x245d, "82562-2", "Intel 82562 based Fast Ethernet Connection", 0), +PCI_ROM(0x8086, 0x1050, "82562ez", "Intel 82562EZ Network Connection", 0), +PCI_ROM(0x8086, 0x1051, "eepro100-1051", "Intel 82801EB/ER (ICH5/ICH5R) Chipset Ethernet Controller", 0), +PCI_ROM(0x8086, 0x1065, "82562-3", "Intel 82562 based Fast Ethernet Connection", 0), +PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server", 0), +PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0), +}; + +/* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need + * a workaround for hardware bug on 10 mbit half duplex (see linux driver eepro100.c) + * 2003/03/17 gbaum */ + + +PCI_DRIVER ( eepro100_driver, eepro100_nics, PCI_NO_CLASS ); + +DRIVER ( "EEPRO100", nic_driver, pci_driver, eepro100_driver, + eepro100_probe, eepro100_disable ); + +/* + * Local variables: + * c-basic-offset: 8 + * c-indent-level: 8 + * tab-width: 8 + * End: + */ -- cgit v1.2.3