1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
4 Author: Martin Renters.
7 This code is based heavily on David Greenman's if_ed.c driver and
8 Andres Vega Garcia's if_ep.c driver.
10 Copyright (C) 1993-1994, David Greenman, Martin Renters.
11 Copyright (C) 1993-1995, Andres Vega Garcia.
12 Copyright (C) 1995, Serge Babkin.
13 This software may be used, modified, copied, distributed, and sold, in
14 both source and binary form provided that the above copyright and these
15 terms are retained. Under no circumstances are the authors responsible for
16 the proper functioning of this software, nor do the authors assume any
17 responsibility for damages incurred with its use.
19 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
23 ***************************************************************************/
27 #include "etherboot.h"
33 #define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
35 static unsigned short eth_nic_base
;
36 static enum { none
, bnc
, utp
} connector
= none
; /* for 3C509 */
40 * This table and several other pieces of the MCA support
41 * code were shamelessly borrowed from the Linux kernel source.
43 * MCA support added by Adam Fritzler (mid@auk.cx)
46 struct el3_mca_adapters_struct
{
50 static struct el3_mca_adapters_struct el3_mca_adapters
[] = {
51 { "3Com 3c529 EtherLink III (10base2)", 0x627c },
52 { "3Com 3c529 EtherLink III (10baseT)", 0x627d },
53 { "3Com 3c529 EtherLink III (test mode)", 0x62db },
54 { "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 },
55 { "3Com 3c529 EtherLink III (TP)", 0x62f7 },
60 /**************************************************************************
61 ETH_RESET - Reset adapter
62 ***************************************************************************/
63 static void t509_reset(struct nic
*nic
)
67 /***********************************************************
69 *************************************************************/
72 outw(RX_DISABLE
, BASE
+ EP_COMMAND
);
73 outw(RX_DISCARD_TOP_PACK
, BASE
+ EP_COMMAND
);
74 while (inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
)
76 outw(TX_DISABLE
, BASE
+ EP_COMMAND
);
77 outw(STOP_TRANSCEIVER
, BASE
+ EP_COMMAND
);
79 outw(RX_RESET
, BASE
+ EP_COMMAND
);
80 outw(TX_RESET
, BASE
+ EP_COMMAND
);
81 outw(C_INTR_LATCH
, BASE
+ EP_COMMAND
);
82 outw(SET_RD_0_MASK
, BASE
+ EP_COMMAND
);
83 outw(SET_INTR_MASK
, BASE
+ EP_COMMAND
);
84 outw(SET_RX_FILTER
, BASE
+ EP_COMMAND
);
89 while (inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
)
94 /* Disable the card */
95 outw(0, BASE
+ EP_W0_CONFIG_CTRL
);
97 /* Configure IRQ to none */
98 outw(SET_IRQ(0), BASE
+ EP_W0_RESOURCE_CFG
);
100 /* Enable the card */
101 outw(ENABLE_DRQ_IRQ
, BASE
+ EP_W0_CONFIG_CTRL
);
105 /* Reload the ether_addr. */
106 for (i
= 0; i
< ETH_ALEN
; i
++)
107 outb(nic
->node_addr
[i
], BASE
+ EP_W2_ADDR_0
+ i
);
109 outw(RX_RESET
, BASE
+ EP_COMMAND
);
110 outw(TX_RESET
, BASE
+ EP_COMMAND
);
112 /* Window 1 is operating window */
114 for (i
= 0; i
< 31; i
++)
115 inb(BASE
+ EP_W1_TX_STATUS
);
117 /* get rid of stray intr's */
118 outw(ACK_INTR
| 0xff, BASE
+ EP_COMMAND
);
120 outw(SET_RD_0_MASK
| S_5_INTS
, BASE
+ EP_COMMAND
);
122 outw(SET_INTR_MASK
, BASE
+ EP_COMMAND
);
124 outw(SET_RX_FILTER
| FIL_INDIVIDUAL
| FIL_BRDCST
, BASE
+ EP_COMMAND
);
127 if (connector
== bnc
) {
128 outw(START_TRANSCEIVER
, BASE
+ EP_COMMAND
);
132 else if (connector
== utp
) {
134 outw(ENABLE_UTP
, BASE
+ EP_W4_MEDIA_TYPE
);
135 sleep(2); /* Give time for media to negotiate */
139 /* start transceiver and receiver */
140 outw(RX_ENABLE
, BASE
+ EP_COMMAND
);
141 outw(TX_ENABLE
, BASE
+ EP_COMMAND
);
143 /* set early threshold for minimal packet length */
144 outw(SET_RX_EARLY_THRESH
| ETH_ZLEN
, BASE
+ EP_COMMAND
);
145 outw(SET_TX_START_THRESH
| 16, BASE
+ EP_COMMAND
);
148 /**************************************************************************
149 ETH_TRANSMIT - Transmit a frame
150 ***************************************************************************/
151 static char padmap
[] = {
154 static void t509_transmit(
156 const char *d
, /* Destination */
157 unsigned int t
, /* Type */
158 unsigned int s
, /* size */
159 const char *p
) /* Packet */
161 register unsigned int len
;
166 printf("{l=%d,t=%hX}",s
+ETH_HLEN
,t
);
169 /* swap bytes of type */
172 len
=s
+ETH_HLEN
; /* actual length of packet */
173 pad
= padmap
[len
& 3];
176 * The 3c509 automatically pads short packets to minimum ethernet length,
177 * but we drop packets that are too large. Perhaps we should truncate
180 if (len
+ pad
> ETH_FRAME_LEN
) {
184 /* drop acknowledgements */
185 while ((status
=inb(BASE
+ EP_W1_TX_STATUS
)) & TXS_COMPLETE
) {
186 if (status
& (TXS_UNDERRUN
|TXS_MAX_COLLISION
|TXS_STATUS_OVERFLOW
)) {
187 outw(TX_RESET
, BASE
+ EP_COMMAND
);
188 outw(TX_ENABLE
, BASE
+ EP_COMMAND
);
190 outb(0x0, BASE
+ EP_W1_TX_STATUS
);
193 while (inw(BASE
+ EP_W1_FREE_TX
) < (unsigned short)len
+ pad
+ 4)
194 ; /* no room in FIFO */
196 outw(len
, BASE
+ EP_W1_TX_PIO_WR_1
);
197 outw(0x0, BASE
+ EP_W1_TX_PIO_WR_1
); /* Second dword meaningless */
200 outsw(BASE
+ EP_W1_TX_PIO_WR_1
, d
, ETH_ALEN
/2);
201 outsw(BASE
+ EP_W1_TX_PIO_WR_1
, nic
->node_addr
, ETH_ALEN
/2);
202 outw(t
, BASE
+ EP_W1_TX_PIO_WR_1
);
203 outsw(BASE
+ EP_W1_TX_PIO_WR_1
, p
, s
/ 2);
205 outb(*(p
+s
- 1), BASE
+ EP_W1_TX_PIO_WR_1
);
208 outb(0, BASE
+ EP_W1_TX_PIO_WR_1
); /* Padding */
210 /* wait for Tx complete */
211 while((inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
) != 0)
215 /**************************************************************************
216 ETH_POLL - Wait for a frame
217 ***************************************************************************/
218 static int t509_poll(struct nic
*nic
)
220 /* common variables */
221 unsigned short type
= 0; /* used by EDEBUG */
222 /* variables for 3C509 */
224 register short rx_fifo
;
226 cst
=inw(BASE
+ EP_STATUS
);
233 if( (cst
& S_RX_COMPLETE
)==0 ) {
234 /* acknowledge everything */
235 outw(ACK_INTR
| (cst
& S_5_INTS
), BASE
+ EP_COMMAND
);
236 outw(C_INTR_LATCH
, BASE
+ EP_COMMAND
);
241 status
= inw(BASE
+ EP_W1_RX_STATUS
);
243 printf("*%hX*",status
);
246 if (status
& ERR_RX
) {
247 outw(RX_DISCARD_TOP_PACK
, BASE
+ EP_COMMAND
);
251 rx_fifo
= status
& RX_BYTES_MASK
;
257 printf("[l=%d",rx_fifo
);
259 insw(BASE
+ EP_W1_RX_PIO_RD_1
, nic
->packet
, rx_fifo
/ 2);
261 nic
->packet
[rx_fifo
-1]=inb(BASE
+ EP_W1_RX_PIO_RD_1
);
262 nic
->packetlen
=rx_fifo
;
265 status
= inw(BASE
+ EP_W1_RX_STATUS
);
267 printf("*%hX*",status
);
269 rx_fifo
= status
& RX_BYTES_MASK
;
271 insw(BASE
+ EP_W1_RX_PIO_RD_1
, nic
->packet
+nic
->packetlen
, rx_fifo
/ 2);
273 nic
->packet
[nic
->packetlen
+rx_fifo
-1]=inb(BASE
+ EP_W1_RX_PIO_RD_1
);
274 nic
->packetlen
+=rx_fifo
;
276 printf("+%d",rx_fifo
);
279 if(( status
& RX_INCOMPLETE
)==0) {
281 printf("=%d",nic
->packetlen
);
285 udelay(1000); /* if incomplete wait 1 ms */
287 /* acknowledge reception of packet */
288 outw(RX_DISCARD_TOP_PACK
, BASE
+ EP_COMMAND
);
289 while (inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
)
292 type
= (nic
->packet
[12]<<8) | nic
->packet
[13];
293 if(nic
->packet
[0]+nic
->packet
[1]+nic
->packet
[2]+nic
->packet
[3]+nic
->packet
[4]+
294 nic
->packet
[5] == 0xFF*ETH_ALEN
)
295 printf(",t=%hX,b]",type
);
297 printf(",t=%hX]",type
);
302 /*************************************************************************
303 3Com 509 - specific routines
304 **************************************************************************/
311 for (i
= 0; is_eeprom_busy(IS_BASE
) && i
< MAX_EEPROMBUSY
; i
++);
312 if (i
>= MAX_EEPROMBUSY
) {
313 /* printf("3c509: eeprom failed to come ready.\n"); */
314 printf("3c509: eeprom busy.\n"); /* memory in EPROM is tight */
321 * get_e: gets a 16 bits word from the EEPROM. we must have set the window
329 outw(EEPROM_CMD_RD
| offset
, IS_BASE
+ EP_W0_EEPROM_COMMAND
);
332 return (inw(IS_BASE
+ EP_W0_EEPROM_DATA
));
336 send_ID_sequence(int port
)
340 for (al
= 0xff, cx
= 0; cx
< 255; cx
++) {
351 * We get eeprom data from the id_port given an offset into the eeprom.
352 * Basically; after the ID_sequence is sent to all of the cards; they enter
353 * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
354 * the eeprom data. We then read the port 16 times and with every read; the
355 * cards check for contention (ie: if one card writes a 0 bit and another
356 * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
357 * compares the data on the bus; if there is a difference then that card goes
358 * into ID_WAIT state again). In the meantime; one bit of data is returned in
359 * the AX register which is conveniently returned to us by inb(). Hence; we
360 * read 16 times getting one bit of data with each read.
363 get_eeprom_data(int id_port
, int offset
)
366 outb(0x80 + offset
, id_port
);
367 /* Do we really need this wait? Won't be noticeable anyway */
369 for (i
= 0; i
< 16; i
++)
370 data
= (data
<< 1) | (inw(id_port
) & 1);
374 static void t509_disable(struct nic
*nic
)
376 outb(0xc0, EP_ID_PORT
);
379 /**************************************************************************
380 ETH_PROBE - Look for an adapter
381 ***************************************************************************/
383 struct nic
*t529_probe(struct nic
*nic
, unsigned short *probe_addrs
)
385 struct nic
*t509_probe(struct nic
*nic
, unsigned short *probe_addrs
)
388 /* common variables */
393 struct el3_mca_adapters_struct
*mcafound
= NULL
;
394 int mca_pos4
= 0, mca_pos5
= 0, mca_irq
= 0;
397 t509_disable(nic
); /* in case board was active */
398 /* note that nic is not used */
399 for (failcount
= 0; failcount
< 4000; failcount
++) {
400 int data
, j
, io_base
, id_port
;
408 id_port
= EP_ID_PORT
;
409 ep_current_tag
= EP_LAST_TAG
+ 1;
411 /*********************************************************
412 Search for 3Com 509 card
413 ***********************************************************/
416 * XXX: We should really check to make sure we have an MCA
417 * bus controller before going ahead with this...
419 * For now, we avoid any hassle by making it a compile
423 printf("\nWarning: Assuming presence of MCA bus\n");
425 /* Make sure motherboard setup is off */
426 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
428 /* Cycle through slots */
429 for(curboard
=0; curboard
<MCA_MAX_SLOT_NR
; curboard
++) {
433 outb_p(0x8|(curboard
&0xf), MCA_ADAPTER_SETUP_REG
);
435 boardid
= inb_p(MCA_POS_REG(0));
436 boardid
+= inb_p(MCA_POS_REG(1)) << 8;
439 while (el3_mca_adapters
[curcard
].name
) {
440 if (el3_mca_adapters
[curcard
].id
== boardid
) {
441 mcafound
= &el3_mca_adapters
[curcard
];
443 mca_pos4
= inb_p(MCA_POS_REG(4));
444 mca_pos5
= inb_p(MCA_POS_REG(5));
454 /* Kill all setup modes */
455 outb_p(0, MCA_ADAPTER_SETUP_REG
);
458 eth_nic_base
= ((short)((mca_pos4
&0xfc)|0x02)) << 8;
459 mca_irq
= mca_pos5
& 0x0f;
463 printf("MCA Card not found\n");
465 /* Look for the EISA boards, leave them activated */
466 /* search for the first card, ignore all others */
467 for(j
= 1; j
< 16; j
++) {
468 io_base
= (j
* EP_EISA_START
) | EP_EISA_W0
;
469 if (inw(io_base
+ EP_W0_MFG_ID
) != MFG_ID
)
472 /* we must have found 0x1f if the board is EISA configurated */
473 if ((inw(io_base
+ EP_W0_ADDRESS_CFG
) & 0x1f) != 0x1f)
476 /* Reset and Enable the card */
477 outb(W0_P4_CMD_RESET_ADAPTER
, io_base
+ EP_W0_CONFIG_CTRL
);
478 udelay(1000); /* Must wait 800 µs, be conservative */
479 outb(W0_P4_CMD_ENABLE_ADAPTER
, io_base
+ EP_W0_CONFIG_CTRL
);
482 * Once activated, all the registers are mapped in the range
483 * x000 - x00F, where x is the slot number.
485 eth_nic_base
= j
* EP_EISA_START
;
490 /* Look for the ISA boards. Init and leave them actived */
491 /* search for the first card, ignore all others */
492 outb(0xc0, id_port
); /* Global reset */
493 udelay(1000); /* wait 1 ms */
494 for (i
= 0; i
< EP_MAX_BOARDS
; i
++) {
497 send_ID_sequence(id_port
);
499 data
= get_eeprom_data(id_port
, EEPROM_MFG_ID
);
503 /* resolve contention using the Ethernet address */
504 for (j
= 0; j
< 3; j
++)
505 data
= get_eeprom_data(id_port
, j
);
508 (get_eeprom_data(id_port
, EEPROM_ADDR_CFG
) & 0x1f) * 0x10 + 0x200;
509 outb(ep_current_tag
, id_port
); /* tags board */
510 outb(ACTIVATE_ADAPTER_TO_CONFIG
, id_port
);
515 if (i
>= EP_MAX_BOARDS
)
519 * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
523 k
= get_e(EEPROM_PROD_ID
);
526 * On MCA, the PROD_ID matches the MCA card ID (POS0+POS1)
529 if (mcafound
->id
!= k
) {
530 printf("MCA: PROD_ID in EEPROM does not match MCA card ID! (%hX != %hX)\n", k
, mcafound
->id
);
533 } else { /* for ISA/EISA */
534 if ((k
& 0xf0ff) != (PROD_ID
& 0xf0ff))
538 if ((k
& 0xf0ff) != (PROD_ID
& 0xf0ff))
544 printf("%s board found on MCA at %#hx IRQ %d -",
545 mcafound
->name
, eth_nic_base
, mca_irq
);
548 if(eth_nic_base
>= EP_EISA_START
)
549 printf("3C5x9 board on EISA at %#hx - ",eth_nic_base
);
551 printf("3C5x9 board on ISA at %#hx - ",eth_nic_base
);
556 /* test for presence of connectors */
557 i
= inw(IS_BASE
+ EP_W0_CONFIG_CTRL
);
558 j
= (inw(IS_BASE
+ EP_W0_ADDRESS_CFG
) >> 14) & 0x3;
567 printf("10baseT not present\n");
575 printf("10base5 not present\n");
585 printf("10base2 not present\n");
590 printf("unknown connector\n");
594 * Read the station address from the eeprom
596 p
= (unsigned short *) nic
->node_addr
;
597 for (i
= 0; i
< ETH_ALEN
/ 2; i
++) {
599 p
[i
] = htons(get_e(i
));
601 outw(ntohs(p
[i
]), BASE
+ EP_W2_ADDR_0
+ (i
* 2));
603 printf("Ethernet address: %!\n", nic
->node_addr
);
605 nic
->reset
= t509_reset
;
606 nic
->poll
= t509_poll
;
607 nic
->transmit
= t509_transmit
;
608 nic
->disable
= t509_disable
;
611 printf("(probe fail)");