xref: /onnv-gate/usr/src/grub/grub-0.97/netboot/eepro100.c (revision 8044:b3af80bbf173)
1*8044SWilliam.Kucharski@Sun.COM /*
2*8044SWilliam.Kucharski@Sun.COM  * eepro100.c -- This file implements the eepro100 driver for etherboot.
3*8044SWilliam.Kucharski@Sun.COM  *
4*8044SWilliam.Kucharski@Sun.COM  *
5*8044SWilliam.Kucharski@Sun.COM  * Copyright (C) AW Computer Systems.
6*8044SWilliam.Kucharski@Sun.COM  * written by R.E.Wolff -- R.E.Wolff@BitWizard.nl
7*8044SWilliam.Kucharski@Sun.COM  *
8*8044SWilliam.Kucharski@Sun.COM  *
9*8044SWilliam.Kucharski@Sun.COM  * AW Computer Systems is contributing to the free software community
10*8044SWilliam.Kucharski@Sun.COM  * by paying for this driver and then putting the result under GPL.
11*8044SWilliam.Kucharski@Sun.COM  *
12*8044SWilliam.Kucharski@Sun.COM  * If you need a Linux device driver, please contact BitWizard for a
13*8044SWilliam.Kucharski@Sun.COM  * quote.
14*8044SWilliam.Kucharski@Sun.COM  *
15*8044SWilliam.Kucharski@Sun.COM  *
16*8044SWilliam.Kucharski@Sun.COM  * This program is free software; you can redistribute it and/or
17*8044SWilliam.Kucharski@Sun.COM  * modify it under the terms of the GNU General Public License as
18*8044SWilliam.Kucharski@Sun.COM  * published by the Free Software Foundation; either version 2, or (at
19*8044SWilliam.Kucharski@Sun.COM  * your option) any later version.
20*8044SWilliam.Kucharski@Sun.COM  *
21*8044SWilliam.Kucharski@Sun.COM  * This program is distributed in the hope that it will be useful, but
22*8044SWilliam.Kucharski@Sun.COM  * WITHOUT ANY WARRANTY; without even the implied warranty of
23*8044SWilliam.Kucharski@Sun.COM  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24*8044SWilliam.Kucharski@Sun.COM  * General Public License for more details.
25*8044SWilliam.Kucharski@Sun.COM  *
26*8044SWilliam.Kucharski@Sun.COM  * You should have received a copy of the GNU General Public License
27*8044SWilliam.Kucharski@Sun.COM  * along with this program; if not, write to the Free Software
28*8044SWilliam.Kucharski@Sun.COM  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29*8044SWilliam.Kucharski@Sun.COM  *
30*8044SWilliam.Kucharski@Sun.COM  *
31*8044SWilliam.Kucharski@Sun.COM  *              date       version  by   what
32*8044SWilliam.Kucharski@Sun.COM  *  Written:    May 29 1997  V0.10  REW  Initial revision.
33*8044SWilliam.Kucharski@Sun.COM  * changes:     May 31 1997  V0.90  REW  Works!
34*8044SWilliam.Kucharski@Sun.COM  *              Jun 1  1997  V0.91  REW  Cleanup
35*8044SWilliam.Kucharski@Sun.COM  *              Jun 2  1997  V0.92  REW  Add some code documentation
36*8044SWilliam.Kucharski@Sun.COM  *              Jul 25 1997  V1.00  REW  Tested by AW to work in a PROM
37*8044SWilliam.Kucharski@Sun.COM  *                                       Cleanup for publication
38*8044SWilliam.Kucharski@Sun.COM  *
39*8044SWilliam.Kucharski@Sun.COM  * This is the etherboot intel etherexpress Pro/100B driver.
40*8044SWilliam.Kucharski@Sun.COM  *
41*8044SWilliam.Kucharski@Sun.COM  * It was written from scratch, with Donald Beckers eepro100.c kernel
42*8044SWilliam.Kucharski@Sun.COM  * driver as a guideline. Mostly the 82557 related definitions and the
43*8044SWilliam.Kucharski@Sun.COM  * lower level routines have been cut-and-pasted into this source.
44*8044SWilliam.Kucharski@Sun.COM  *
45*8044SWilliam.Kucharski@Sun.COM  * The driver was finished before Intel got the NDA out of the closet.
46*8044SWilliam.Kucharski@Sun.COM  * I still don't have the docs.
47*8044SWilliam.Kucharski@Sun.COM  * */
48*8044SWilliam.Kucharski@Sun.COM 
49*8044SWilliam.Kucharski@Sun.COM /* Philosophy of this driver.
50*8044SWilliam.Kucharski@Sun.COM  *
51*8044SWilliam.Kucharski@Sun.COM  * Probing:
52*8044SWilliam.Kucharski@Sun.COM  *
53*8044SWilliam.Kucharski@Sun.COM  * Using the pci.c functions of the Etherboot code, the 82557 chip is detected.
54*8044SWilliam.Kucharski@Sun.COM  * It is verified that the BIOS initialized everything properly and if
55*8044SWilliam.Kucharski@Sun.COM  * something is missing it is done now.
56*8044SWilliam.Kucharski@Sun.COM  *
57*8044SWilliam.Kucharski@Sun.COM  *
58*8044SWilliam.Kucharski@Sun.COM  * Initialization:
59*8044SWilliam.Kucharski@Sun.COM  *
60*8044SWilliam.Kucharski@Sun.COM  *
61*8044SWilliam.Kucharski@Sun.COM  * The chip is then initialized to "know" its ethernet address, and to
62*8044SWilliam.Kucharski@Sun.COM  * start recieving packets. The Linux driver has a whole transmit and
63*8044SWilliam.Kucharski@Sun.COM  * recieve ring of buffers. This is neat if you need high performance:
64*8044SWilliam.Kucharski@Sun.COM  * you can write the buffers asynchronously to the chip reading the
65*8044SWilliam.Kucharski@Sun.COM  * buffers and transmitting them over the network.  Performance is NOT
66*8044SWilliam.Kucharski@Sun.COM  * an issue here. We can boot a 400k kernel in about two
67*8044SWilliam.Kucharski@Sun.COM  * seconds. (Theory: 0.4 seconds). Booting a system is going to take
68*8044SWilliam.Kucharski@Sun.COM  * about half a minute anyway, so getting 10 times closer to the
69*8044SWilliam.Kucharski@Sun.COM  * theoretical limit is going to make a difference of a few percent.
70*8044SWilliam.Kucharski@Sun.COM  *
71*8044SWilliam.Kucharski@Sun.COM  *
72*8044SWilliam.Kucharski@Sun.COM  * Transmitting and recieving.
73*8044SWilliam.Kucharski@Sun.COM  *
74*8044SWilliam.Kucharski@Sun.COM  * We have only one transmit descriptor. It has two buffer descriptors:
75*8044SWilliam.Kucharski@Sun.COM  * one for the header, and the other for the data.
76*8044SWilliam.Kucharski@Sun.COM  * We have only one receive buffer. The chip is told to recieve packets,
77*8044SWilliam.Kucharski@Sun.COM  * and suspend itself once it got one. The recieve (poll) routine simply
78*8044SWilliam.Kucharski@Sun.COM  * looks at the recieve buffer to see if there is already a packet there.
79*8044SWilliam.Kucharski@Sun.COM  * if there is, the buffer is copied, and the reciever is restarted.
80*8044SWilliam.Kucharski@Sun.COM  *
81*8044SWilliam.Kucharski@Sun.COM  * Caveats:
82*8044SWilliam.Kucharski@Sun.COM  *
83*8044SWilliam.Kucharski@Sun.COM  * The Etherboot framework moves the code to the 48k segment from
84*8044SWilliam.Kucharski@Sun.COM  * 0x94000 to 0xa0000. There is just a little room between the end of
85*8044SWilliam.Kucharski@Sun.COM  * this driver and the 0xa0000 address. If you compile in too many
86*8044SWilliam.Kucharski@Sun.COM  * features, this will overflow.
87*8044SWilliam.Kucharski@Sun.COM  * The number under "hex" in the output of size that scrolls by while
88*8044SWilliam.Kucharski@Sun.COM  * compiling should be less than 8000. Maybe even the stack is up there,
89*8044SWilliam.Kucharski@Sun.COM  * so that you need even more headroom.
90*8044SWilliam.Kucharski@Sun.COM  */
91*8044SWilliam.Kucharski@Sun.COM 
92*8044SWilliam.Kucharski@Sun.COM /* The etherboot authors seem to dislike the argument ordering in
93*8044SWilliam.Kucharski@Sun.COM  * outb macros that Linux uses. I disklike the confusion that this
94*8044SWilliam.Kucharski@Sun.COM  * has caused even more.... This file uses the Linux argument ordering.  */
95*8044SWilliam.Kucharski@Sun.COM /* Sorry not us. It's inherited code from FreeBSD. [The authors] */
96*8044SWilliam.Kucharski@Sun.COM 
97*8044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
98*8044SWilliam.Kucharski@Sun.COM #include "nic.h"
99*8044SWilliam.Kucharski@Sun.COM #include "pci.h"
100*8044SWilliam.Kucharski@Sun.COM #include "timer.h"
101*8044SWilliam.Kucharski@Sun.COM 
102*8044SWilliam.Kucharski@Sun.COM static int ioaddr;
103*8044SWilliam.Kucharski@Sun.COM 
104*8044SWilliam.Kucharski@Sun.COM typedef unsigned char  u8;
105*8044SWilliam.Kucharski@Sun.COM typedef   signed char  s8;
106*8044SWilliam.Kucharski@Sun.COM typedef unsigned short u16;
107*8044SWilliam.Kucharski@Sun.COM typedef   signed short s16;
108*8044SWilliam.Kucharski@Sun.COM typedef unsigned int   u32;
109*8044SWilliam.Kucharski@Sun.COM typedef   signed int   s32;
110*8044SWilliam.Kucharski@Sun.COM 
111*8044SWilliam.Kucharski@Sun.COM enum speedo_offsets {
112*8044SWilliam.Kucharski@Sun.COM   SCBStatus = 0, SCBCmd = 2,      /* Rx/Command Unit command and status. */
113*8044SWilliam.Kucharski@Sun.COM   SCBPointer = 4,                 /* General purpose pointer. */
114*8044SWilliam.Kucharski@Sun.COM   SCBPort = 8,                    /* Misc. commands and operands.  */
115*8044SWilliam.Kucharski@Sun.COM   SCBflash = 12, SCBeeprom = 14,  /* EEPROM and flash memory control. */
116*8044SWilliam.Kucharski@Sun.COM   SCBCtrlMDI = 16,                /* MDI interface control. */
117*8044SWilliam.Kucharski@Sun.COM   SCBEarlyRx = 20,                /* Early receive byte count. */
118*8044SWilliam.Kucharski@Sun.COM };
119*8044SWilliam.Kucharski@Sun.COM 
120*8044SWilliam.Kucharski@Sun.COM enum SCBCmdBits {
121*8044SWilliam.Kucharski@Sun.COM 	SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
122*8044SWilliam.Kucharski@Sun.COM 	SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
123*8044SWilliam.Kucharski@Sun.COM 	SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
124*8044SWilliam.Kucharski@Sun.COM 	/* The rest are Rx and Tx commands. */
125*8044SWilliam.Kucharski@Sun.COM 	CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
126*8044SWilliam.Kucharski@Sun.COM 	CUCmdBase=0x0060,	/* CU Base address (set to zero) . */
127*8044SWilliam.Kucharski@Sun.COM 	CUDumpStats=0x0070, /* Dump then reset stats counters. */
128*8044SWilliam.Kucharski@Sun.COM 	RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
129*8044SWilliam.Kucharski@Sun.COM 	RxResumeNoResources=0x0007,
130*8044SWilliam.Kucharski@Sun.COM };
131*8044SWilliam.Kucharski@Sun.COM 
132*8044SWilliam.Kucharski@Sun.COM static int do_eeprom_cmd(int cmd, int cmd_len);
133*8044SWilliam.Kucharski@Sun.COM void hd(void *where, int n);
134*8044SWilliam.Kucharski@Sun.COM 
135*8044SWilliam.Kucharski@Sun.COM /***********************************************************************/
136*8044SWilliam.Kucharski@Sun.COM /*                       I82557 related defines                        */
137*8044SWilliam.Kucharski@Sun.COM /***********************************************************************/
138*8044SWilliam.Kucharski@Sun.COM 
139*8044SWilliam.Kucharski@Sun.COM /* Serial EEPROM section.
140*8044SWilliam.Kucharski@Sun.COM    A "bit" grungy, but we work our way through bit-by-bit :->. */
141*8044SWilliam.Kucharski@Sun.COM /*  EEPROM_Ctrl bits. */
142*8044SWilliam.Kucharski@Sun.COM #define EE_SHIFT_CLK    0x01    /* EEPROM shift clock. */
143*8044SWilliam.Kucharski@Sun.COM #define EE_CS           0x02    /* EEPROM chip select. */
144*8044SWilliam.Kucharski@Sun.COM #define EE_DATA_WRITE   0x04    /* EEPROM chip data in. */
145*8044SWilliam.Kucharski@Sun.COM #define EE_DATA_READ    0x08    /* EEPROM chip data out. */
146*8044SWilliam.Kucharski@Sun.COM #define EE_WRITE_0      0x4802
147*8044SWilliam.Kucharski@Sun.COM #define EE_WRITE_1      0x4806
148*8044SWilliam.Kucharski@Sun.COM #define EE_ENB          (0x4800 | EE_CS)
149*8044SWilliam.Kucharski@Sun.COM 
150*8044SWilliam.Kucharski@Sun.COM /* The EEPROM commands include the alway-set leading bit. */
151*8044SWilliam.Kucharski@Sun.COM #define EE_READ_CMD     6
152*8044SWilliam.Kucharski@Sun.COM 
153*8044SWilliam.Kucharski@Sun.COM /* The SCB accepts the following controls for the Tx and Rx units: */
154*8044SWilliam.Kucharski@Sun.COM #define  CU_START       0x0010
155*8044SWilliam.Kucharski@Sun.COM #define  CU_RESUME      0x0020
156*8044SWilliam.Kucharski@Sun.COM #define  CU_STATSADDR   0x0040
157*8044SWilliam.Kucharski@Sun.COM #define  CU_SHOWSTATS   0x0050  /* Dump statistics counters. */
158*8044SWilliam.Kucharski@Sun.COM #define  CU_CMD_BASE    0x0060  /* Base address to add to add CU commands. */
159*8044SWilliam.Kucharski@Sun.COM #define  CU_DUMPSTATS   0x0070  /* Dump then reset stats counters. */
160*8044SWilliam.Kucharski@Sun.COM 
161*8044SWilliam.Kucharski@Sun.COM #define  RX_START       0x0001
162*8044SWilliam.Kucharski@Sun.COM #define  RX_RESUME      0x0002
163*8044SWilliam.Kucharski@Sun.COM #define  RX_ABORT       0x0004
164*8044SWilliam.Kucharski@Sun.COM #define  RX_ADDR_LOAD   0x0006
165*8044SWilliam.Kucharski@Sun.COM #define  RX_RESUMENR    0x0007
166*8044SWilliam.Kucharski@Sun.COM #define INT_MASK        0x0100
167*8044SWilliam.Kucharski@Sun.COM #define DRVR_INT        0x0200          /* Driver generated interrupt. */
168*8044SWilliam.Kucharski@Sun.COM 
169*8044SWilliam.Kucharski@Sun.COM enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
170*8044SWilliam.Kucharski@Sun.COM                                          S80C24, PhyUndefined, DP83840A=10, };
171*8044SWilliam.Kucharski@Sun.COM 
172*8044SWilliam.Kucharski@Sun.COM /* Commands that can be put in a command list entry. */
173*8044SWilliam.Kucharski@Sun.COM enum commands {
174*8044SWilliam.Kucharski@Sun.COM   CmdNOp = 0,
175*8044SWilliam.Kucharski@Sun.COM   CmdIASetup = 1,
176*8044SWilliam.Kucharski@Sun.COM   CmdConfigure = 2,
177*8044SWilliam.Kucharski@Sun.COM   CmdMulticastList = 3,
178*8044SWilliam.Kucharski@Sun.COM   CmdTx = 4,
179*8044SWilliam.Kucharski@Sun.COM   CmdTDR = 5,
180*8044SWilliam.Kucharski@Sun.COM   CmdDump = 6,
181*8044SWilliam.Kucharski@Sun.COM   CmdDiagnose = 7,
182*8044SWilliam.Kucharski@Sun.COM 
183*8044SWilliam.Kucharski@Sun.COM   /* And some extra flags: */
184*8044SWilliam.Kucharski@Sun.COM   CmdSuspend = 0x4000,      /* Suspend after completion. */
185*8044SWilliam.Kucharski@Sun.COM   CmdIntr = 0x2000,         /* Interrupt after completion. */
186*8044SWilliam.Kucharski@Sun.COM   CmdTxFlex = 0x0008,       /* Use "Flexible mode" for CmdTx command. */
187*8044SWilliam.Kucharski@Sun.COM };
188*8044SWilliam.Kucharski@Sun.COM 
189*8044SWilliam.Kucharski@Sun.COM /* How to wait for the command unit to accept a command.
190*8044SWilliam.Kucharski@Sun.COM    Typically this takes 0 ticks. */
wait_for_cmd_done(int cmd_ioaddr)191*8044SWilliam.Kucharski@Sun.COM static inline void wait_for_cmd_done(int cmd_ioaddr)
192*8044SWilliam.Kucharski@Sun.COM {
193*8044SWilliam.Kucharski@Sun.COM   int wait = 0;
194*8044SWilliam.Kucharski@Sun.COM   int delayed_cmd;
195*8044SWilliam.Kucharski@Sun.COM 
196*8044SWilliam.Kucharski@Sun.COM   do
197*8044SWilliam.Kucharski@Sun.COM     if (inb(cmd_ioaddr) == 0) return;
198*8044SWilliam.Kucharski@Sun.COM   while(++wait <= 100);
199*8044SWilliam.Kucharski@Sun.COM   delayed_cmd = inb(cmd_ioaddr);
200*8044SWilliam.Kucharski@Sun.COM   do
201*8044SWilliam.Kucharski@Sun.COM     if (inb(cmd_ioaddr) == 0) break;
202*8044SWilliam.Kucharski@Sun.COM   while(++wait <= 10000);
203*8044SWilliam.Kucharski@Sun.COM   printf("Command %2.2x was not immediately accepted, %d ticks!\n",
204*8044SWilliam.Kucharski@Sun.COM       delayed_cmd, wait);
205*8044SWilliam.Kucharski@Sun.COM }
206*8044SWilliam.Kucharski@Sun.COM 
207*8044SWilliam.Kucharski@Sun.COM /* Elements of the dump_statistics block. This block must be lword aligned. */
208*8044SWilliam.Kucharski@Sun.COM static struct speedo_stats {
209*8044SWilliam.Kucharski@Sun.COM         u32 tx_good_frames;
210*8044SWilliam.Kucharski@Sun.COM         u32 tx_coll16_errs;
211*8044SWilliam.Kucharski@Sun.COM         u32 tx_late_colls;
212*8044SWilliam.Kucharski@Sun.COM         u32 tx_underruns;
213*8044SWilliam.Kucharski@Sun.COM         u32 tx_lost_carrier;
214*8044SWilliam.Kucharski@Sun.COM         u32 tx_deferred;
215*8044SWilliam.Kucharski@Sun.COM         u32 tx_one_colls;
216*8044SWilliam.Kucharski@Sun.COM         u32 tx_multi_colls;
217*8044SWilliam.Kucharski@Sun.COM         u32 tx_total_colls;
218*8044SWilliam.Kucharski@Sun.COM         u32 rx_good_frames;
219*8044SWilliam.Kucharski@Sun.COM         u32 rx_crc_errs;
220*8044SWilliam.Kucharski@Sun.COM         u32 rx_align_errs;
221*8044SWilliam.Kucharski@Sun.COM         u32 rx_resource_errs;
222*8044SWilliam.Kucharski@Sun.COM         u32 rx_overrun_errs;
223*8044SWilliam.Kucharski@Sun.COM         u32 rx_colls_errs;
224*8044SWilliam.Kucharski@Sun.COM         u32 rx_runt_errs;
225*8044SWilliam.Kucharski@Sun.COM         u32 done_marker;
226*8044SWilliam.Kucharski@Sun.COM } lstats;
227*8044SWilliam.Kucharski@Sun.COM 
228*8044SWilliam.Kucharski@Sun.COM /* A speedo3 TX buffer descriptor with two buffers... */
229*8044SWilliam.Kucharski@Sun.COM static struct TxFD {
230*8044SWilliam.Kucharski@Sun.COM 	volatile s16 status;
231*8044SWilliam.Kucharski@Sun.COM 	s16 command;
232*8044SWilliam.Kucharski@Sun.COM 	u32 link;          /* void * */
233*8044SWilliam.Kucharski@Sun.COM 	u32 tx_desc_addr;  /* (almost) Always points to the tx_buf_addr element. */
234*8044SWilliam.Kucharski@Sun.COM 	s32 count;         /* # of TBD (=2), Tx start thresh., etc. */
235*8044SWilliam.Kucharski@Sun.COM 	/* This constitutes two "TBD" entries: hdr and data */
236*8044SWilliam.Kucharski@Sun.COM 	u32 tx_buf_addr0;  /* void *, header of frame to be transmitted.  */
237*8044SWilliam.Kucharski@Sun.COM 	s32 tx_buf_size0;  /* Length of Tx hdr. */
238*8044SWilliam.Kucharski@Sun.COM 	u32 tx_buf_addr1;  /* void *, data to be transmitted.  */
239*8044SWilliam.Kucharski@Sun.COM 	s32 tx_buf_size1;  /* Length of Tx data. */
240*8044SWilliam.Kucharski@Sun.COM } txfd;
241*8044SWilliam.Kucharski@Sun.COM 
242*8044SWilliam.Kucharski@Sun.COM struct RxFD {               /* Receive frame descriptor. */
243*8044SWilliam.Kucharski@Sun.COM 	volatile s16 status;
244*8044SWilliam.Kucharski@Sun.COM 	s16 command;
245*8044SWilliam.Kucharski@Sun.COM 	u32 link;                 /* struct RxFD * */
246*8044SWilliam.Kucharski@Sun.COM 	u32 rx_buf_addr;          /* void * */
247*8044SWilliam.Kucharski@Sun.COM 	u16 count;
248*8044SWilliam.Kucharski@Sun.COM 	u16 size;
249*8044SWilliam.Kucharski@Sun.COM 	char packet[1518];
250*8044SWilliam.Kucharski@Sun.COM };
251*8044SWilliam.Kucharski@Sun.COM 
252*8044SWilliam.Kucharski@Sun.COM static struct RxFD rxfd;
253*8044SWilliam.Kucharski@Sun.COM #define ACCESS(x) x.
254*8044SWilliam.Kucharski@Sun.COM 
255*8044SWilliam.Kucharski@Sun.COM static int congenb = 0;         /* Enable congestion control in the DP83840. */
256*8044SWilliam.Kucharski@Sun.COM static int txfifo = 8;          /* Tx FIFO threshold in 4 byte units, 0-15 */
257*8044SWilliam.Kucharski@Sun.COM static int rxfifo = 8;          /* Rx FIFO threshold, default 32 bytes. */
258*8044SWilliam.Kucharski@Sun.COM static int txdmacount = 0;      /* Tx DMA burst length, 0-127, default 0. */
259*8044SWilliam.Kucharski@Sun.COM static int rxdmacount = 0;      /* Rx DMA length, 0 means no preemption. */
260*8044SWilliam.Kucharski@Sun.COM 
261*8044SWilliam.Kucharski@Sun.COM /* I don't understand a byte in this structure. It was copied from the
262*8044SWilliam.Kucharski@Sun.COM  * Linux kernel initialization for the eepro100. -- REW */
263*8044SWilliam.Kucharski@Sun.COM static struct ConfCmd {
264*8044SWilliam.Kucharski@Sun.COM   s16 status;
265*8044SWilliam.Kucharski@Sun.COM   s16 command;
266*8044SWilliam.Kucharski@Sun.COM   u32 link;
267*8044SWilliam.Kucharski@Sun.COM   unsigned char data[22];
268*8044SWilliam.Kucharski@Sun.COM } confcmd = {
269*8044SWilliam.Kucharski@Sun.COM   0, 0, 0, /* filled in later */
270*8044SWilliam.Kucharski@Sun.COM   {22, 0x08, 0, 0,  0, 0x80, 0x32, 0x03,  1, /* 1=Use MII  0=Use AUI */
271*8044SWilliam.Kucharski@Sun.COM    0, 0x2E, 0,  0x60, 0,
272*8044SWilliam.Kucharski@Sun.COM    0xf2, 0x48,   0, 0x40, 0xf2, 0x80,        /* 0x40=Force full-duplex */
273*8044SWilliam.Kucharski@Sun.COM    0x3f, 0x05, }
274*8044SWilliam.Kucharski@Sun.COM };
275*8044SWilliam.Kucharski@Sun.COM 
276*8044SWilliam.Kucharski@Sun.COM /***********************************************************************/
277*8044SWilliam.Kucharski@Sun.COM /*                       Locally used functions                        */
278*8044SWilliam.Kucharski@Sun.COM /***********************************************************************/
279*8044SWilliam.Kucharski@Sun.COM 
280*8044SWilliam.Kucharski@Sun.COM /* Support function: mdio_write
281*8044SWilliam.Kucharski@Sun.COM  *
282*8044SWilliam.Kucharski@Sun.COM  * This probably writes to the "physical media interface chip".
283*8044SWilliam.Kucharski@Sun.COM  * -- REW
284*8044SWilliam.Kucharski@Sun.COM  */
285*8044SWilliam.Kucharski@Sun.COM 
mdio_write(int phy_id,int location,int value)286*8044SWilliam.Kucharski@Sun.COM static int mdio_write(int phy_id, int location, int value)
287*8044SWilliam.Kucharski@Sun.COM {
288*8044SWilliam.Kucharski@Sun.COM 	int val, boguscnt = 64*4;         /* <64 usec. to complete, typ 27 ticks */
289*8044SWilliam.Kucharski@Sun.COM 
290*8044SWilliam.Kucharski@Sun.COM 	outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
291*8044SWilliam.Kucharski@Sun.COM 	     ioaddr + SCBCtrlMDI);
292*8044SWilliam.Kucharski@Sun.COM 	do {
293*8044SWilliam.Kucharski@Sun.COM 		udelay(16);
294*8044SWilliam.Kucharski@Sun.COM 
295*8044SWilliam.Kucharski@Sun.COM 		val = inl(ioaddr + SCBCtrlMDI);
296*8044SWilliam.Kucharski@Sun.COM 		if (--boguscnt < 0) {
297*8044SWilliam.Kucharski@Sun.COM 			printf(" mdio_write() timed out with val = %X.\n", val);
298*8044SWilliam.Kucharski@Sun.COM 			break;
299*8044SWilliam.Kucharski@Sun.COM 		}
300*8044SWilliam.Kucharski@Sun.COM 	} while (! (val & 0x10000000));
301*8044SWilliam.Kucharski@Sun.COM 	return val & 0xffff;
302*8044SWilliam.Kucharski@Sun.COM }
303*8044SWilliam.Kucharski@Sun.COM 
304*8044SWilliam.Kucharski@Sun.COM /* Support function: mdio_read
305*8044SWilliam.Kucharski@Sun.COM  *
306*8044SWilliam.Kucharski@Sun.COM  * This probably reads a register in the "physical media interface chip".
307*8044SWilliam.Kucharski@Sun.COM  * -- REW
308*8044SWilliam.Kucharski@Sun.COM  */
mdio_read(int phy_id,int location)309*8044SWilliam.Kucharski@Sun.COM static int mdio_read(int phy_id, int location)
310*8044SWilliam.Kucharski@Sun.COM {
311*8044SWilliam.Kucharski@Sun.COM 	int val, boguscnt = 64*4;               /* <64 usec. to complete, typ 27 ticks */
312*8044SWilliam.Kucharski@Sun.COM 	outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
313*8044SWilliam.Kucharski@Sun.COM 	do {
314*8044SWilliam.Kucharski@Sun.COM 		udelay(16);
315*8044SWilliam.Kucharski@Sun.COM 
316*8044SWilliam.Kucharski@Sun.COM 		val = inl(ioaddr + SCBCtrlMDI);
317*8044SWilliam.Kucharski@Sun.COM 
318*8044SWilliam.Kucharski@Sun.COM 		if (--boguscnt < 0) {
319*8044SWilliam.Kucharski@Sun.COM 			printf( " mdio_read() timed out with val = %X.\n", val);
320*8044SWilliam.Kucharski@Sun.COM 			break;
321*8044SWilliam.Kucharski@Sun.COM 		}
322*8044SWilliam.Kucharski@Sun.COM 	} while (! (val & 0x10000000));
323*8044SWilliam.Kucharski@Sun.COM 	return val & 0xffff;
324*8044SWilliam.Kucharski@Sun.COM }
325*8044SWilliam.Kucharski@Sun.COM 
326*8044SWilliam.Kucharski@Sun.COM /* The fixes for the code were kindly provided by Dragan Stancevic
327*8044SWilliam.Kucharski@Sun.COM    <visitor@valinux.com> to strictly follow Intel specifications of EEPROM
328*8044SWilliam.Kucharski@Sun.COM    access timing.
329*8044SWilliam.Kucharski@Sun.COM    The publicly available sheet 64486302 (sec. 3.1) specifies 1us access
330*8044SWilliam.Kucharski@Sun.COM    interval for serial EEPROM.  However, it looks like that there is an
331*8044SWilliam.Kucharski@Sun.COM    additional requirement dictating larger udelay's in the code below.
332*8044SWilliam.Kucharski@Sun.COM    2000/05/24  SAW */
do_eeprom_cmd(int cmd,int cmd_len)333*8044SWilliam.Kucharski@Sun.COM static int do_eeprom_cmd(int cmd, int cmd_len)
334*8044SWilliam.Kucharski@Sun.COM {
335*8044SWilliam.Kucharski@Sun.COM 	unsigned retval = 0;
336*8044SWilliam.Kucharski@Sun.COM 	long ee_addr = ioaddr + SCBeeprom;
337*8044SWilliam.Kucharski@Sun.COM 
338*8044SWilliam.Kucharski@Sun.COM 	outw(EE_ENB, ee_addr); udelay(2);
339*8044SWilliam.Kucharski@Sun.COM 	outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2);
340*8044SWilliam.Kucharski@Sun.COM 
341*8044SWilliam.Kucharski@Sun.COM 	/* Shift the command bits out. */
342*8044SWilliam.Kucharski@Sun.COM 	do {
343*8044SWilliam.Kucharski@Sun.COM 		short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
344*8044SWilliam.Kucharski@Sun.COM 		outw(dataval, ee_addr); udelay(2);
345*8044SWilliam.Kucharski@Sun.COM 		outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2);
346*8044SWilliam.Kucharski@Sun.COM 		retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
347*8044SWilliam.Kucharski@Sun.COM 	} while (--cmd_len >= 0);
348*8044SWilliam.Kucharski@Sun.COM 	outw(EE_ENB, ee_addr); udelay(2);
349*8044SWilliam.Kucharski@Sun.COM 
350*8044SWilliam.Kucharski@Sun.COM 	/* Terminate the EEPROM access. */
351*8044SWilliam.Kucharski@Sun.COM 	outw(EE_ENB & ~EE_CS, ee_addr);
352*8044SWilliam.Kucharski@Sun.COM 	return retval;
353*8044SWilliam.Kucharski@Sun.COM }
354*8044SWilliam.Kucharski@Sun.COM 
355*8044SWilliam.Kucharski@Sun.COM #if 0
356*8044SWilliam.Kucharski@Sun.COM static inline void whereami (const char *str)
357*8044SWilliam.Kucharski@Sun.COM {
358*8044SWilliam.Kucharski@Sun.COM   printf ("%s\n", str);
359*8044SWilliam.Kucharski@Sun.COM   sleep (2);
360*8044SWilliam.Kucharski@Sun.COM }
361*8044SWilliam.Kucharski@Sun.COM #else
362*8044SWilliam.Kucharski@Sun.COM #define whereami(s)
363*8044SWilliam.Kucharski@Sun.COM #endif
364*8044SWilliam.Kucharski@Sun.COM 
eepro100_irq(struct nic * nic __unused,irq_action_t action __unused)365*8044SWilliam.Kucharski@Sun.COM static void eepro100_irq(struct nic *nic __unused, irq_action_t action __unused)
366*8044SWilliam.Kucharski@Sun.COM {
367*8044SWilliam.Kucharski@Sun.COM   switch ( action ) {
368*8044SWilliam.Kucharski@Sun.COM   case DISABLE :
369*8044SWilliam.Kucharski@Sun.COM     break;
370*8044SWilliam.Kucharski@Sun.COM   case ENABLE :
371*8044SWilliam.Kucharski@Sun.COM     break;
372*8044SWilliam.Kucharski@Sun.COM   case FORCE :
373*8044SWilliam.Kucharski@Sun.COM     break;
374*8044SWilliam.Kucharski@Sun.COM   }
375*8044SWilliam.Kucharski@Sun.COM }
376*8044SWilliam.Kucharski@Sun.COM 
377*8044SWilliam.Kucharski@Sun.COM /* function: eepro100_transmit
378*8044SWilliam.Kucharski@Sun.COM  * This transmits a packet.
379*8044SWilliam.Kucharski@Sun.COM  *
380*8044SWilliam.Kucharski@Sun.COM  * Arguments: char d[6]:          destination ethernet address.
381*8044SWilliam.Kucharski@Sun.COM  *            unsigned short t:   ethernet protocol type.
382*8044SWilliam.Kucharski@Sun.COM  *            unsigned short s:   size of the data-part of the packet.
383*8044SWilliam.Kucharski@Sun.COM  *            char *p:            the data for the packet.
384*8044SWilliam.Kucharski@Sun.COM  * returns:   void.
385*8044SWilliam.Kucharski@Sun.COM  */
386*8044SWilliam.Kucharski@Sun.COM 
eepro100_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)387*8044SWilliam.Kucharski@Sun.COM static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
388*8044SWilliam.Kucharski@Sun.COM {
389*8044SWilliam.Kucharski@Sun.COM 	struct eth_hdr {
390*8044SWilliam.Kucharski@Sun.COM 		unsigned char dst_addr[ETH_ALEN];
391*8044SWilliam.Kucharski@Sun.COM 		unsigned char src_addr[ETH_ALEN];
392*8044SWilliam.Kucharski@Sun.COM 		unsigned short type;
393*8044SWilliam.Kucharski@Sun.COM 	} hdr;
394*8044SWilliam.Kucharski@Sun.COM 	unsigned short status;
395*8044SWilliam.Kucharski@Sun.COM 	int s1, s2;
396*8044SWilliam.Kucharski@Sun.COM 
397*8044SWilliam.Kucharski@Sun.COM 	status = inw(ioaddr + SCBStatus);
398*8044SWilliam.Kucharski@Sun.COM 	/* Acknowledge all of the current interrupt sources ASAP. */
399*8044SWilliam.Kucharski@Sun.COM 	outw(status & 0xfc00, ioaddr + SCBStatus);
400*8044SWilliam.Kucharski@Sun.COM 
401*8044SWilliam.Kucharski@Sun.COM #ifdef	DEBUG
402*8044SWilliam.Kucharski@Sun.COM 	printf ("transmitting type %hX packet (%d bytes). status = %hX, cmd=%hX\n",
403*8044SWilliam.Kucharski@Sun.COM 		t, s, status, inw (ioaddr + SCBCmd));
404*8044SWilliam.Kucharski@Sun.COM #endif
405*8044SWilliam.Kucharski@Sun.COM 
406*8044SWilliam.Kucharski@Sun.COM 	memcpy (&hdr.dst_addr, d, ETH_ALEN);
407*8044SWilliam.Kucharski@Sun.COM 	memcpy (&hdr.src_addr, nic->node_addr, ETH_ALEN);
408*8044SWilliam.Kucharski@Sun.COM 
409*8044SWilliam.Kucharski@Sun.COM 	hdr.type = htons (t);
410*8044SWilliam.Kucharski@Sun.COM 
411*8044SWilliam.Kucharski@Sun.COM 	txfd.status = 0;
412*8044SWilliam.Kucharski@Sun.COM 	txfd.command = CmdSuspend | CmdTx | CmdTxFlex;
413*8044SWilliam.Kucharski@Sun.COM 	txfd.link   = virt_to_bus (&txfd);
414*8044SWilliam.Kucharski@Sun.COM 	txfd.count   = 0x02208000;
415*8044SWilliam.Kucharski@Sun.COM 	txfd.tx_desc_addr = virt_to_bus(&txfd.tx_buf_addr0);
416*8044SWilliam.Kucharski@Sun.COM 
417*8044SWilliam.Kucharski@Sun.COM 	txfd.tx_buf_addr0 = virt_to_bus (&hdr);
418*8044SWilliam.Kucharski@Sun.COM 	txfd.tx_buf_size0 = sizeof (hdr);
419*8044SWilliam.Kucharski@Sun.COM 
420*8044SWilliam.Kucharski@Sun.COM 	txfd.tx_buf_addr1 = virt_to_bus (p);
421*8044SWilliam.Kucharski@Sun.COM 	txfd.tx_buf_size1 = s;
422*8044SWilliam.Kucharski@Sun.COM 
423*8044SWilliam.Kucharski@Sun.COM #ifdef	DEBUG
424*8044SWilliam.Kucharski@Sun.COM 	printf ("txfd: \n");
425*8044SWilliam.Kucharski@Sun.COM 	hd (&txfd, sizeof (txfd));
426*8044SWilliam.Kucharski@Sun.COM #endif
427*8044SWilliam.Kucharski@Sun.COM 
428*8044SWilliam.Kucharski@Sun.COM 	outl(virt_to_bus(&txfd), ioaddr + SCBPointer);
429*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | CU_START, ioaddr + SCBCmd);
430*8044SWilliam.Kucharski@Sun.COM 	wait_for_cmd_done(ioaddr + SCBCmd);
431*8044SWilliam.Kucharski@Sun.COM 
432*8044SWilliam.Kucharski@Sun.COM 	s1 = inw (ioaddr + SCBStatus);
433*8044SWilliam.Kucharski@Sun.COM 	load_timer2(10*TICKS_PER_MS);		/* timeout 10 ms for transmit */
434*8044SWilliam.Kucharski@Sun.COM 	while (!txfd.status && timer2_running())
435*8044SWilliam.Kucharski@Sun.COM 		/* Wait */;
436*8044SWilliam.Kucharski@Sun.COM 	s2 = inw (ioaddr + SCBStatus);
437*8044SWilliam.Kucharski@Sun.COM 
438*8044SWilliam.Kucharski@Sun.COM #ifdef	DEBUG
439*8044SWilliam.Kucharski@Sun.COM 	printf ("s1 = %hX, s2 = %hX.\n", s1, s2);
440*8044SWilliam.Kucharski@Sun.COM #endif
441*8044SWilliam.Kucharski@Sun.COM }
442*8044SWilliam.Kucharski@Sun.COM 
443*8044SWilliam.Kucharski@Sun.COM /*
444*8044SWilliam.Kucharski@Sun.COM  * Sometimes the receiver stops making progress.  This routine knows how to
445*8044SWilliam.Kucharski@Sun.COM  * get it going again, without losing packets or being otherwise nasty like
446*8044SWilliam.Kucharski@Sun.COM  * a chip reset would be.  Previously the driver had a whole sequence
447*8044SWilliam.Kucharski@Sun.COM  * of if RxSuspended, if it's no buffers do one thing, if it's no resources,
448*8044SWilliam.Kucharski@Sun.COM  * do another, etc.  But those things don't really matter.  Separate logic
449*8044SWilliam.Kucharski@Sun.COM  * in the ISR provides for allocating buffers--the other half of operation
450*8044SWilliam.Kucharski@Sun.COM  * is just making sure the receiver is active.  speedo_rx_soft_reset does that.
451*8044SWilliam.Kucharski@Sun.COM  * This problem with the old, more involved algorithm is shown up under
452*8044SWilliam.Kucharski@Sun.COM  * ping floods on the order of 60K packets/second on a 100Mbps fdx network.
453*8044SWilliam.Kucharski@Sun.COM  */
454*8044SWilliam.Kucharski@Sun.COM static void
speedo_rx_soft_reset(void)455*8044SWilliam.Kucharski@Sun.COM speedo_rx_soft_reset(void)
456*8044SWilliam.Kucharski@Sun.COM {
457*8044SWilliam.Kucharski@Sun.COM   wait_for_cmd_done(ioaddr + SCBCmd);
458*8044SWilliam.Kucharski@Sun.COM 	/*
459*8044SWilliam.Kucharski@Sun.COM 	* Put the hardware into a known state.
460*8044SWilliam.Kucharski@Sun.COM 	*/
461*8044SWilliam.Kucharski@Sun.COM 	outb(RX_ABORT, ioaddr + SCBCmd);
462*8044SWilliam.Kucharski@Sun.COM 
463*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)rx_buf_addr = 0xffffffff;
464*8044SWilliam.Kucharski@Sun.COM 
465*8044SWilliam.Kucharski@Sun.COM   wait_for_cmd_done(ioaddr + SCBCmd);
466*8044SWilliam.Kucharski@Sun.COM 
467*8044SWilliam.Kucharski@Sun.COM 	outb(RX_START, ioaddr + SCBCmd);
468*8044SWilliam.Kucharski@Sun.COM }
469*8044SWilliam.Kucharski@Sun.COM 
470*8044SWilliam.Kucharski@Sun.COM /* function: eepro100_poll / eth_poll
471*8044SWilliam.Kucharski@Sun.COM  * This recieves a packet from the network.
472*8044SWilliam.Kucharski@Sun.COM  *
473*8044SWilliam.Kucharski@Sun.COM  * Arguments: none
474*8044SWilliam.Kucharski@Sun.COM  *
475*8044SWilliam.Kucharski@Sun.COM  * returns:   1 if a packet was recieved.
476*8044SWilliam.Kucharski@Sun.COM  *            0 if no pacet was recieved.
477*8044SWilliam.Kucharski@Sun.COM  * side effects:
478*8044SWilliam.Kucharski@Sun.COM  *            returns the packet in the array nic->packet.
479*8044SWilliam.Kucharski@Sun.COM  *            returns the length of the packet in nic->packetlen.
480*8044SWilliam.Kucharski@Sun.COM  */
481*8044SWilliam.Kucharski@Sun.COM 
eepro100_poll(struct nic * nic,int retrieve)482*8044SWilliam.Kucharski@Sun.COM static int eepro100_poll(struct nic *nic, int retrieve)
483*8044SWilliam.Kucharski@Sun.COM {
484*8044SWilliam.Kucharski@Sun.COM   unsigned int status;
485*8044SWilliam.Kucharski@Sun.COM   status = inw(ioaddr + SCBStatus);
486*8044SWilliam.Kucharski@Sun.COM 
487*8044SWilliam.Kucharski@Sun.COM 	if (!ACCESS(rxfd)status)
488*8044SWilliam.Kucharski@Sun.COM 		return 0;
489*8044SWilliam.Kucharski@Sun.COM 
490*8044SWilliam.Kucharski@Sun.COM 	/* There is a packet ready */
491*8044SWilliam.Kucharski@Sun.COM 	if ( ! retrieve ) return 1;
492*8044SWilliam.Kucharski@Sun.COM 
493*8044SWilliam.Kucharski@Sun.COM   /*
494*8044SWilliam.Kucharski@Sun.COM    * The chip may have suspended reception for various reasons.
495*8044SWilliam.Kucharski@Sun.COM    * Check for that, and re-prime it should this be the case.
496*8044SWilliam.Kucharski@Sun.COM    */
497*8044SWilliam.Kucharski@Sun.COM   switch ((status >> 2) & 0xf) {
498*8044SWilliam.Kucharski@Sun.COM   case 0: /* Idle */
499*8044SWilliam.Kucharski@Sun.COM     break;
500*8044SWilliam.Kucharski@Sun.COM   case 1:	/* Suspended */
501*8044SWilliam.Kucharski@Sun.COM   case 2:	/* No resources (RxFDs) */
502*8044SWilliam.Kucharski@Sun.COM   case 9:	/* Suspended with no more RBDs */
503*8044SWilliam.Kucharski@Sun.COM   case 10: /* No resources due to no RBDs */
504*8044SWilliam.Kucharski@Sun.COM   case 12: /* Ready with no RBDs */
505*8044SWilliam.Kucharski@Sun.COM     speedo_rx_soft_reset();
506*8044SWilliam.Kucharski@Sun.COM     break;
507*8044SWilliam.Kucharski@Sun.COM   case 3:  case 5:  case 6:  case 7:  case 8:
508*8044SWilliam.Kucharski@Sun.COM   case 11:  case 13:  case 14:  case 15:
509*8044SWilliam.Kucharski@Sun.COM     /* these are all reserved values */
510*8044SWilliam.Kucharski@Sun.COM     break;
511*8044SWilliam.Kucharski@Sun.COM   }
512*8044SWilliam.Kucharski@Sun.COM 
513*8044SWilliam.Kucharski@Sun.COM 	/* Ok. We got a packet. Now restart the reciever.... */
514*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)status = 0;
515*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)command = 0xc000;
516*8044SWilliam.Kucharski@Sun.COM 	outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer);
517*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | RX_START, ioaddr + SCBCmd);
518*8044SWilliam.Kucharski@Sun.COM 	wait_for_cmd_done(ioaddr + SCBCmd);
519*8044SWilliam.Kucharski@Sun.COM 
520*8044SWilliam.Kucharski@Sun.COM #ifdef	DEBUG
521*8044SWilliam.Kucharski@Sun.COM 	printf ("Got a packet: Len = %d.\n", ACCESS(rxfd)count & 0x3fff);
522*8044SWilliam.Kucharski@Sun.COM #endif
523*8044SWilliam.Kucharski@Sun.COM 	nic->packetlen =  ACCESS(rxfd)count & 0x3fff;
524*8044SWilliam.Kucharski@Sun.COM 	memcpy (nic->packet, ACCESS(rxfd)packet, nic->packetlen);
525*8044SWilliam.Kucharski@Sun.COM #ifdef	DEBUG
526*8044SWilliam.Kucharski@Sun.COM 	hd (nic->packet, 0x30);
527*8044SWilliam.Kucharski@Sun.COM #endif
528*8044SWilliam.Kucharski@Sun.COM 	return 1;
529*8044SWilliam.Kucharski@Sun.COM }
530*8044SWilliam.Kucharski@Sun.COM 
531*8044SWilliam.Kucharski@Sun.COM /* function: eepro100_disable
532*8044SWilliam.Kucharski@Sun.COM  * resets the card. This is used to allow Etherboot or Linux
533*8044SWilliam.Kucharski@Sun.COM  * to probe the card again from a "virginal" state....
534*8044SWilliam.Kucharski@Sun.COM  * Arguments: none
535*8044SWilliam.Kucharski@Sun.COM  *
536*8044SWilliam.Kucharski@Sun.COM  * returns:   void.
537*8044SWilliam.Kucharski@Sun.COM  */
eepro100_disable(struct dev * dev __unused)538*8044SWilliam.Kucharski@Sun.COM static void eepro100_disable(struct dev *dev __unused)
539*8044SWilliam.Kucharski@Sun.COM {
540*8044SWilliam.Kucharski@Sun.COM /* from eepro100_reset */
541*8044SWilliam.Kucharski@Sun.COM 	outl(0, ioaddr + SCBPort);
542*8044SWilliam.Kucharski@Sun.COM /* from eepro100_disable */
543*8044SWilliam.Kucharski@Sun.COM 	/* See if this PartialReset solves the problem with interfering with
544*8044SWilliam.Kucharski@Sun.COM 	   kernel operation after Etherboot hands over. - Ken 20001102 */
545*8044SWilliam.Kucharski@Sun.COM 	outl(2, ioaddr + SCBPort);
546*8044SWilliam.Kucharski@Sun.COM 
547*8044SWilliam.Kucharski@Sun.COM 	/* The following is from the Intel e100 driver.
548*8044SWilliam.Kucharski@Sun.COM 	 * This hopefully solves the problem with hanging hard DOS images. */
549*8044SWilliam.Kucharski@Sun.COM 
550*8044SWilliam.Kucharski@Sun.COM 	/* wait for the reset to take effect */
551*8044SWilliam.Kucharski@Sun.COM 	udelay(20);
552*8044SWilliam.Kucharski@Sun.COM 
553*8044SWilliam.Kucharski@Sun.COM 	/* Mask off our interrupt line -- it is unmasked after reset */
554*8044SWilliam.Kucharski@Sun.COM 	{
555*8044SWilliam.Kucharski@Sun.COM 		u16 intr_status;
556*8044SWilliam.Kucharski@Sun.COM 		/* Disable interrupts on our PCI board by setting the mask bit */
557*8044SWilliam.Kucharski@Sun.COM 		outw(INT_MASK, ioaddr + SCBCmd);
558*8044SWilliam.Kucharski@Sun.COM 		intr_status = inw(ioaddr + SCBStatus);
559*8044SWilliam.Kucharski@Sun.COM 		/* ack and clear intrs */
560*8044SWilliam.Kucharski@Sun.COM 		outw(intr_status, ioaddr + SCBStatus);
561*8044SWilliam.Kucharski@Sun.COM 		inw(ioaddr + SCBStatus);
562*8044SWilliam.Kucharski@Sun.COM 	}
563*8044SWilliam.Kucharski@Sun.COM }
564*8044SWilliam.Kucharski@Sun.COM 
565*8044SWilliam.Kucharski@Sun.COM /* exported function: eepro100_probe / eth_probe
566*8044SWilliam.Kucharski@Sun.COM  * initializes a card
567*8044SWilliam.Kucharski@Sun.COM  *
568*8044SWilliam.Kucharski@Sun.COM  * side effects:
569*8044SWilliam.Kucharski@Sun.COM  *            leaves the ioaddress of the 82557 chip in the variable ioaddr.
570*8044SWilliam.Kucharski@Sun.COM  *            leaves the 82557 initialized, and ready to recieve packets.
571*8044SWilliam.Kucharski@Sun.COM  */
572*8044SWilliam.Kucharski@Sun.COM 
eepro100_probe(struct dev * dev,struct pci_device * p)573*8044SWilliam.Kucharski@Sun.COM static int eepro100_probe(struct dev *dev, struct pci_device *p)
574*8044SWilliam.Kucharski@Sun.COM {
575*8044SWilliam.Kucharski@Sun.COM 	struct nic *nic = (struct nic *)dev;
576*8044SWilliam.Kucharski@Sun.COM 	unsigned short sum = 0;
577*8044SWilliam.Kucharski@Sun.COM 	int i;
578*8044SWilliam.Kucharski@Sun.COM 	int read_cmd, ee_size;
579*8044SWilliam.Kucharski@Sun.COM 	int options;
580*8044SWilliam.Kucharski@Sun.COM 	int rx_mode;
581*8044SWilliam.Kucharski@Sun.COM 
582*8044SWilliam.Kucharski@Sun.COM 	/* we cache only the first few words of the EEPROM data
583*8044SWilliam.Kucharski@Sun.COM 	   be careful not to access beyond this array */
584*8044SWilliam.Kucharski@Sun.COM 	unsigned short eeprom[16];
585*8044SWilliam.Kucharski@Sun.COM 
586*8044SWilliam.Kucharski@Sun.COM 	if (p->ioaddr == 0)
587*8044SWilliam.Kucharski@Sun.COM 		return 0;
588*8044SWilliam.Kucharski@Sun.COM 	ioaddr = p->ioaddr & ~3; /* Mask the bit that says "this is an io addr" */
589*8044SWilliam.Kucharski@Sun.COM 	nic->ioaddr = ioaddr;
590*8044SWilliam.Kucharski@Sun.COM 
591*8044SWilliam.Kucharski@Sun.COM 	adjust_pci_device(p);
592*8044SWilliam.Kucharski@Sun.COM 
593*8044SWilliam.Kucharski@Sun.COM 	/* Copy IRQ from PCI information */
594*8044SWilliam.Kucharski@Sun.COM 	/* nic->irqno = pci->irq; */
595*8044SWilliam.Kucharski@Sun.COM 	nic->irqno = 0;
596*8044SWilliam.Kucharski@Sun.COM 
597*8044SWilliam.Kucharski@Sun.COM 	if ((do_eeprom_cmd(EE_READ_CMD << 24, 27) & 0xffe0000)
598*8044SWilliam.Kucharski@Sun.COM 		== 0xffe0000) {
599*8044SWilliam.Kucharski@Sun.COM 		ee_size = 0x100;
600*8044SWilliam.Kucharski@Sun.COM 		read_cmd = EE_READ_CMD << 24;
601*8044SWilliam.Kucharski@Sun.COM 	} else {
602*8044SWilliam.Kucharski@Sun.COM 		ee_size = 0x40;
603*8044SWilliam.Kucharski@Sun.COM 		read_cmd = EE_READ_CMD << 22;
604*8044SWilliam.Kucharski@Sun.COM 	}
605*8044SWilliam.Kucharski@Sun.COM 
606*8044SWilliam.Kucharski@Sun.COM 	for (i = 0, sum = 0; i < ee_size; i++) {
607*8044SWilliam.Kucharski@Sun.COM 		unsigned short value = do_eeprom_cmd(read_cmd | (i << 16), 27);
608*8044SWilliam.Kucharski@Sun.COM 		if (i < (int)(sizeof(eeprom)/sizeof(eeprom[0])))
609*8044SWilliam.Kucharski@Sun.COM 			eeprom[i] = value;
610*8044SWilliam.Kucharski@Sun.COM 		sum += value;
611*8044SWilliam.Kucharski@Sun.COM 	}
612*8044SWilliam.Kucharski@Sun.COM 
613*8044SWilliam.Kucharski@Sun.COM 	for (i=0;i<ETH_ALEN;i++) {
614*8044SWilliam.Kucharski@Sun.COM 		nic->node_addr[i] =  (eeprom[i/2] >> (8*(i&1))) & 0xff;
615*8044SWilliam.Kucharski@Sun.COM 	}
616*8044SWilliam.Kucharski@Sun.COM 	printf ("Ethernet addr: %!\n", nic->node_addr);
617*8044SWilliam.Kucharski@Sun.COM 
618*8044SWilliam.Kucharski@Sun.COM 	if (sum != 0xBABA)
619*8044SWilliam.Kucharski@Sun.COM 		printf("eepro100: Invalid EEPROM checksum %#hX, "
620*8044SWilliam.Kucharski@Sun.COM 		       "check settings before activating this device!\n", sum);
621*8044SWilliam.Kucharski@Sun.COM 	outl(0, ioaddr + SCBPort);
622*8044SWilliam.Kucharski@Sun.COM 	udelay (10000);
623*8044SWilliam.Kucharski@Sun.COM 	whereami ("Got eeprom.");
624*8044SWilliam.Kucharski@Sun.COM 
625*8044SWilliam.Kucharski@Sun.COM 	/* Base = 0 */
626*8044SWilliam.Kucharski@Sun.COM 	outl(0, ioaddr + SCBPointer);
627*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd);
628*8044SWilliam.Kucharski@Sun.COM 	wait_for_cmd_done(ioaddr + SCBCmd);
629*8044SWilliam.Kucharski@Sun.COM 	whereami ("set rx base addr.");
630*8044SWilliam.Kucharski@Sun.COM 
631*8044SWilliam.Kucharski@Sun.COM 	outl(virt_to_bus(&lstats), ioaddr + SCBPointer);
632*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd);
633*8044SWilliam.Kucharski@Sun.COM 	wait_for_cmd_done(ioaddr + SCBCmd);
634*8044SWilliam.Kucharski@Sun.COM 	whereami ("set stats addr.");
635*8044SWilliam.Kucharski@Sun.COM 
636*8044SWilliam.Kucharski@Sun.COM 	/* INIT RX stuff. */
637*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)status  = 0x0001;
638*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)command = 0x0000;
639*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)link    = virt_to_bus(&(ACCESS(rxfd)status));
640*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)rx_buf_addr = virt_to_bus(&nic->packet);
641*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)count   = 0;
642*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)size    = 1528;
643*8044SWilliam.Kucharski@Sun.COM 
644*8044SWilliam.Kucharski@Sun.COM 	outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer);
645*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | RX_START, ioaddr + SCBCmd);
646*8044SWilliam.Kucharski@Sun.COM 	wait_for_cmd_done(ioaddr + SCBCmd);
647*8044SWilliam.Kucharski@Sun.COM 
648*8044SWilliam.Kucharski@Sun.COM 	whereami ("started RX process.");
649*8044SWilliam.Kucharski@Sun.COM 
650*8044SWilliam.Kucharski@Sun.COM 	/* Start the reciever.... */
651*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)status = 0;
652*8044SWilliam.Kucharski@Sun.COM 	ACCESS(rxfd)command = 0xc000;
653*8044SWilliam.Kucharski@Sun.COM 	outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer);
654*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | RX_START, ioaddr + SCBCmd);
655*8044SWilliam.Kucharski@Sun.COM 
656*8044SWilliam.Kucharski@Sun.COM 	/* INIT TX stuff. */
657*8044SWilliam.Kucharski@Sun.COM 
658*8044SWilliam.Kucharski@Sun.COM 	/* Base = 0 */
659*8044SWilliam.Kucharski@Sun.COM 	outl(0, ioaddr + SCBPointer);
660*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd);
661*8044SWilliam.Kucharski@Sun.COM 	wait_for_cmd_done(ioaddr + SCBCmd);
662*8044SWilliam.Kucharski@Sun.COM 
663*8044SWilliam.Kucharski@Sun.COM 	whereami ("set TX base addr.");
664*8044SWilliam.Kucharski@Sun.COM 
665*8044SWilliam.Kucharski@Sun.COM 	txfd.command      = (CmdIASetup);
666*8044SWilliam.Kucharski@Sun.COM 	txfd.status       = 0x0000;
667*8044SWilliam.Kucharski@Sun.COM 	txfd.link         = virt_to_bus (&confcmd);
668*8044SWilliam.Kucharski@Sun.COM 
669*8044SWilliam.Kucharski@Sun.COM 	{
670*8044SWilliam.Kucharski@Sun.COM 		char *t = (char *)&txfd.tx_desc_addr;
671*8044SWilliam.Kucharski@Sun.COM 
672*8044SWilliam.Kucharski@Sun.COM 		for (i=0;i<ETH_ALEN;i++)
673*8044SWilliam.Kucharski@Sun.COM 			t[i] = nic->node_addr[i];
674*8044SWilliam.Kucharski@Sun.COM 	}
675*8044SWilliam.Kucharski@Sun.COM 
676*8044SWilliam.Kucharski@Sun.COM #ifdef	DEBUG
677*8044SWilliam.Kucharski@Sun.COM 	printf ("Setup_eaddr:\n");
678*8044SWilliam.Kucharski@Sun.COM 	hd (&txfd, 0x20);
679*8044SWilliam.Kucharski@Sun.COM #endif
680*8044SWilliam.Kucharski@Sun.COM 	/*      options = 0x40; */ /* 10mbps half duplex... */
681*8044SWilliam.Kucharski@Sun.COM 	options = 0x00;            /* Autosense */
682*8044SWilliam.Kucharski@Sun.COM 
683*8044SWilliam.Kucharski@Sun.COM #ifdef PROMISC
684*8044SWilliam.Kucharski@Sun.COM 	rx_mode = 3;
685*8044SWilliam.Kucharski@Sun.COM #elif ALLMULTI
686*8044SWilliam.Kucharski@Sun.COM 	rx_mode = 1;
687*8044SWilliam.Kucharski@Sun.COM #else
688*8044SWilliam.Kucharski@Sun.COM 	rx_mode = 0;
689*8044SWilliam.Kucharski@Sun.COM #endif
690*8044SWilliam.Kucharski@Sun.COM 
691*8044SWilliam.Kucharski@Sun.COM 	if (   ((eeprom[6]>>8) & 0x3f) == DP83840
692*8044SWilliam.Kucharski@Sun.COM 	       || ((eeprom[6]>>8) & 0x3f) == DP83840A) {
693*8044SWilliam.Kucharski@Sun.COM 		int mdi_reg23 = mdio_read(eeprom[6] & 0x1f, 23) | 0x0422;
694*8044SWilliam.Kucharski@Sun.COM 		if (congenb)
695*8044SWilliam.Kucharski@Sun.COM 			mdi_reg23 |= 0x0100;
696*8044SWilliam.Kucharski@Sun.COM 		printf("  DP83840 specific setup, setting register 23 to %hX.\n",
697*8044SWilliam.Kucharski@Sun.COM 		       mdi_reg23);
698*8044SWilliam.Kucharski@Sun.COM 		mdio_write(eeprom[6] & 0x1f, 23, mdi_reg23);
699*8044SWilliam.Kucharski@Sun.COM 	}
700*8044SWilliam.Kucharski@Sun.COM 	whereami ("Done DP8340 special setup.");
701*8044SWilliam.Kucharski@Sun.COM 	if (options != 0) {
702*8044SWilliam.Kucharski@Sun.COM 		mdio_write(eeprom[6] & 0x1f, 0,
703*8044SWilliam.Kucharski@Sun.COM 			   ((options & 0x20) ? 0x2000 : 0) |    /* 100mbps? */
704*8044SWilliam.Kucharski@Sun.COM 			   ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
705*8044SWilliam.Kucharski@Sun.COM 		whereami ("set mdio_register.");
706*8044SWilliam.Kucharski@Sun.COM 	}
707*8044SWilliam.Kucharski@Sun.COM 
708*8044SWilliam.Kucharski@Sun.COM 	confcmd.command  = CmdSuspend | CmdConfigure;
709*8044SWilliam.Kucharski@Sun.COM 	confcmd.status   = 0x0000;
710*8044SWilliam.Kucharski@Sun.COM 	confcmd.link     = virt_to_bus (&txfd);
711*8044SWilliam.Kucharski@Sun.COM 	confcmd.data[1]  = (txfifo << 4) | rxfifo;
712*8044SWilliam.Kucharski@Sun.COM 	confcmd.data[4]  = rxdmacount;
713*8044SWilliam.Kucharski@Sun.COM 	confcmd.data[5]  = txdmacount + 0x80;
714*8044SWilliam.Kucharski@Sun.COM 	confcmd.data[15] = (rx_mode & 2) ? 0x49: 0x48;
715*8044SWilliam.Kucharski@Sun.COM 	confcmd.data[19] = (options & 0x10) ? 0xC0 : 0x80;
716*8044SWilliam.Kucharski@Sun.COM 	confcmd.data[21] = (rx_mode & 1) ? 0x0D: 0x05;
717*8044SWilliam.Kucharski@Sun.COM 
718*8044SWilliam.Kucharski@Sun.COM 	outl(virt_to_bus(&txfd), ioaddr + SCBPointer);
719*8044SWilliam.Kucharski@Sun.COM 	outw(INT_MASK | CU_START, ioaddr + SCBCmd);
720*8044SWilliam.Kucharski@Sun.COM 	wait_for_cmd_done(ioaddr + SCBCmd);
721*8044SWilliam.Kucharski@Sun.COM 
722*8044SWilliam.Kucharski@Sun.COM 	whereami ("started TX thingy (config, iasetup).");
723*8044SWilliam.Kucharski@Sun.COM 
724*8044SWilliam.Kucharski@Sun.COM 	load_timer2(10*TICKS_PER_MS);
725*8044SWilliam.Kucharski@Sun.COM 	while (!txfd.status && timer2_running())
726*8044SWilliam.Kucharski@Sun.COM 		/* Wait */;
727*8044SWilliam.Kucharski@Sun.COM 
728*8044SWilliam.Kucharski@Sun.COM 	/* Read the status register once to disgard stale data */
729*8044SWilliam.Kucharski@Sun.COM 	mdio_read(eeprom[6] & 0x1f, 1);
730*8044SWilliam.Kucharski@Sun.COM 	/* Check to see if the network cable is plugged in.
731*8044SWilliam.Kucharski@Sun.COM 	 * This allows for faster failure if there is nothing
732*8044SWilliam.Kucharski@Sun.COM 	 * we can do.
733*8044SWilliam.Kucharski@Sun.COM 	 */
734*8044SWilliam.Kucharski@Sun.COM 	if (!(mdio_read(eeprom[6] & 0x1f, 1) & (1 << 2))) {
735*8044SWilliam.Kucharski@Sun.COM 		printf("Valid link not established\n");
736*8044SWilliam.Kucharski@Sun.COM 		eepro100_disable(dev);
737*8044SWilliam.Kucharski@Sun.COM 		return 0;
738*8044SWilliam.Kucharski@Sun.COM 	}
739*8044SWilliam.Kucharski@Sun.COM 
740*8044SWilliam.Kucharski@Sun.COM 	dev->disable  = eepro100_disable;
741*8044SWilliam.Kucharski@Sun.COM 	nic->poll     = eepro100_poll;
742*8044SWilliam.Kucharski@Sun.COM 	nic->transmit = eepro100_transmit;
743*8044SWilliam.Kucharski@Sun.COM 	nic->irq      = eepro100_irq;
744*8044SWilliam.Kucharski@Sun.COM 	return 1;
745*8044SWilliam.Kucharski@Sun.COM }
746*8044SWilliam.Kucharski@Sun.COM 
747*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
748*8044SWilliam.Kucharski@Sun.COM 
749*8044SWilliam.Kucharski@Sun.COM #ifdef	DEBUG
750*8044SWilliam.Kucharski@Sun.COM 
751*8044SWilliam.Kucharski@Sun.COM /* Hexdump a number of bytes from memory... */
hd(void * where,int n)752*8044SWilliam.Kucharski@Sun.COM void hd (void *where, int n)
753*8044SWilliam.Kucharski@Sun.COM {
754*8044SWilliam.Kucharski@Sun.COM 	int i;
755*8044SWilliam.Kucharski@Sun.COM 
756*8044SWilliam.Kucharski@Sun.COM 	while (n > 0) {
757*8044SWilliam.Kucharski@Sun.COM 		printf ("%X ", where);
758*8044SWilliam.Kucharski@Sun.COM 		for (i=0;i < ( (n>16)?16:n);i++)
759*8044SWilliam.Kucharski@Sun.COM 			printf (" %hhX", ((char *)where)[i]);
760*8044SWilliam.Kucharski@Sun.COM 		printf ("\n");
761*8044SWilliam.Kucharski@Sun.COM 		n -= 16;
762*8044SWilliam.Kucharski@Sun.COM 		where += 16;
763*8044SWilliam.Kucharski@Sun.COM 	}
764*8044SWilliam.Kucharski@Sun.COM }
765*8044SWilliam.Kucharski@Sun.COM #endif
766*8044SWilliam.Kucharski@Sun.COM 
767*8044SWilliam.Kucharski@Sun.COM static struct pci_id eepro100_nics[] = {
768*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1029, "id1029",        "Intel EtherExpressPro100 ID1029"),
769*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1030, "id1030",        "Intel EtherExpressPro100 ID1030"),
770*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1031, "82801cam",      "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),
771*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1032, "eepro100-1032", "Intel PRO/100 VE Network Connection"),
772*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1033, "eepro100-1033", "Intel PRO/100 VM Network Connection"),
773*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1034, "eepro100-1034", "Intel PRO/100 VM Network Connection"),
774*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1035, "eepro100-1035", "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),
775*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1036, "eepro100-1036", "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),
776*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1037, "eepro100-1037", "Intel 82801CAM (ICH3) Chipset Ethernet Controller"),
777*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1038, "id1038",        "Intel PRO/100 VM Network Connection"),
778*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1039, "82562et",       "Intel PRO100 VE 82562ET"),
779*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x103a, "id103a",        "Intel Corporation 82559 InBusiness 10/100"),
780*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x103b, "82562etb",      "Intel PRO100 VE 82562ETB"),
781*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x103c, "eepro100-103c", "Intel PRO/100 VM Network Connection"),
782*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x103d, "eepro100-103d", "Intel PRO/100 VE Network Connection"),
783*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x103e, "eepro100-103e", "Intel PRO/100 VM Network Connection"),
784*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1059, "82551qm",       "Intel PRO/100 M Mobile Connection"),
785*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1209, "82559er",       "Intel EtherExpressPro100 82559ER"),
786*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1227, "82865",         "Intel 82865 EtherExpress PRO/100A"),
787*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1228, "82556",         "Intel 82556 EtherExpress PRO/100 Smart"),
788*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1229, "eepro100",      "Intel EtherExpressPro100"),
789*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x2449, "82562em",       "Intel EtherExpressPro100 82562EM"),
790*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x2459, "82562-1",       "Intel 82562 based Fast Ethernet Connection"),
791*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x245d, "82562-2",       "Intel 82562 based Fast Ethernet Connection"),
792*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x1050, "82562ez",       "Intel 82562EZ Network Connection"),
793*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server"),
794*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server"),
795*8044SWilliam.Kucharski@Sun.COM };
796*8044SWilliam.Kucharski@Sun.COM 
797*8044SWilliam.Kucharski@Sun.COM /* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need
798*8044SWilliam.Kucharski@Sun.COM  * a workaround for hardware bug on 10 mbit half duplex (see linux driver eepro100.c)
799*8044SWilliam.Kucharski@Sun.COM  * 2003/03/17 gbaum */
800*8044SWilliam.Kucharski@Sun.COM 
801*8044SWilliam.Kucharski@Sun.COM 
802*8044SWilliam.Kucharski@Sun.COM struct pci_driver eepro100_driver = {
803*8044SWilliam.Kucharski@Sun.COM 	.type      = NIC_DRIVER,
804*8044SWilliam.Kucharski@Sun.COM 	.name      = "EEPRO100",
805*8044SWilliam.Kucharski@Sun.COM 	.probe     = eepro100_probe,
806*8044SWilliam.Kucharski@Sun.COM 	.ids       = eepro100_nics,
807*8044SWilliam.Kucharski@Sun.COM 	.id_count  = sizeof(eepro100_nics)/sizeof(eepro100_nics[0]),
808*8044SWilliam.Kucharski@Sun.COM 	.class     = 0
809*8044SWilliam.Kucharski@Sun.COM };
810