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