123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853 |
- /*
- * 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 <gpxe/ethernet.h>
- #include <gpxe/pci.h>
-
- 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
- <visitor@valinux.com> 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;i<ETH_ALEN;i++) {
- nic->node_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;i<ETH_ALEN;i++)
- t[i] = nic->node_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:
- */
|