1 /* $NetBSD: elink3.c,v 1.4 2008/12/14 18:46:33 christos Exp $ */
3 /* stripped down from freebsd:sys/i386/netboot/3c509.c */
5 /**************************************************************************
6 NETBOOT - BOOTP/TFTP Bootstrap Program
8 Author: Martin Renters.
11 This code is based heavily on David Greenman's if_ed.c driver and
12 Andres Vega Garcia's if_ep.c driver.
14 Copyright (C) 1993-1994, David Greenman, Martin Renters.
15 Copyright (C) 1993-1995, Andres Vega Garcia.
16 Copyright (C) 1995, Serge Babkin.
17 This software may be used, modified, copied, distributed, and sold, in
18 both source and binary form provided that the above copyright and these
19 terms are retained. Under no circumstances are the authors responsible for
20 the proper functioning of this software, nor do the authors assume any
21 responsibility for damages incurred with its use.
23 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
25 3c509.c,v 1.2 1995/05/30 07:58:52 rgrimes Exp
27 ***************************************************************************/
29 #include <sys/types.h>
30 #include <machine/pio.h>
32 #include <lib/libsa/stand.h>
39 extern unsigned short eth_base
;
41 extern u_char eth_myaddr
[6];
48 outw(BASE
+ EP_COMMAND
, RX_DISABLE
);
49 outw(BASE
+ EP_COMMAND
, RX_DISCARD_TOP_PACK
);
50 while (inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
);
52 outw(BASE
+ EP_COMMAND
, TX_DISABLE
);
53 outw(BASE
+ EP_COMMAND
, STOP_TRANSCEIVER
);
55 outw(BASE
+ EP_COMMAND
, RX_RESET
);
56 outw(BASE
+ EP_COMMAND
, TX_RESET
);
58 outw(BASE
+ EP_COMMAND
, C_INTR_LATCH
);
59 outw(BASE
+ EP_COMMAND
, SET_RD_0_MASK
);
60 outw(BASE
+ EP_COMMAND
, SET_INTR_MASK
);
61 outw(BASE
+ EP_COMMAND
, SET_RX_FILTER
);
69 outw(BASE
+ EP_COMMAND
, GLOBAL_RESET
);
73 /**************************************************************************
74 ETH_RESET - Reset adapter
75 ***************************************************************************/
81 /***********************************************************
83 *************************************************************/
90 while (inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
)
95 /* Disable the card */
96 outw(BASE
+ EP_W0_CONFIG_CTRL
, 0);
98 /* Configure IRQ to none */
99 outw(BASE
+ EP_W0_RESOURCE_CFG
, SET_IRQ(0));
101 /* Enable the card */
102 outw(BASE
+ EP_W0_CONFIG_CTRL
, ENABLE_DRQ_IRQ
);
106 /* Reload the ether_addr. */
107 for (i
= 0; i
< 6; i
++)
108 outb(BASE
+ EP_W2_ADDR_0
+ i
, eth_myaddr
[i
]);
110 outw(BASE
+ EP_COMMAND
, RX_RESET
);
111 outw(BASE
+ EP_COMMAND
, TX_RESET
);
113 /* Window 1 is operating window */
115 for (i
= 0; i
< 31; i
++)
116 inb(BASE
+ EP_W1_TX_STATUS
);
118 /* get rid of stray intr's */
119 outw(BASE
+ EP_COMMAND
, ACK_INTR
| 0xff);
121 outw(BASE
+ EP_COMMAND
, SET_RD_0_MASK
| S_5_INTS
);
123 outw(BASE
+ EP_COMMAND
, SET_INTR_MASK
);
125 outw(BASE
+ EP_COMMAND
, SET_RX_FILTER
| FIL_INDIVIDUAL
|
129 if (ether_medium
== ETHERMEDIUM_BNC
) {
130 outw(BASE
+ EP_COMMAND
, START_TRANSCEIVER
);
134 if (ether_medium
== ETHERMEDIUM_UTP
) {
136 outw(BASE
+ EP_W4_MEDIA_TYPE
, ENABLE_UTP
);
140 /* start tranciever and receiver */
141 outw(BASE
+ EP_COMMAND
, RX_ENABLE
);
142 outw(BASE
+ EP_COMMAND
, TX_ENABLE
);
144 /* set early threshold for minimal packet length */
145 outw(BASE
+ EP_COMMAND
, SET_RX_EARLY_THRESH
| 64);
147 outw(BASE
+ EP_COMMAND
, SET_TX_START_THRESH
| 16);
150 /**************************************************************************
151 ETH_TRANSMIT - Transmit a frame
152 ***************************************************************************/
153 static const char padmap
[] = {
157 EtherSend(char *pkt
, int len
)
163 printf("{l=%d}", len
);
166 pad
= padmap
[len
& 3];
169 * The 3c509 automatically pads short packets to minimum ethernet length,
170 * but we drop packets that are too large. Perhaps we should truncate
173 if (len
+ pad
> ETHER_MAX_LEN
) {
177 /* drop acknowledgements */
178 while ((status
= inb(BASE
+ EP_W1_TX_STATUS
)) & TXS_COMPLETE
) {
179 if (status
& (TXS_UNDERRUN
| TXS_MAX_COLLISION
|
180 TXS_STATUS_OVERFLOW
)) {
181 outw(BASE
+ EP_COMMAND
, TX_RESET
);
182 outw(BASE
+ EP_COMMAND
, TX_ENABLE
);
185 outb(BASE
+ EP_W1_TX_STATUS
, 0x0);
188 while (inw(BASE
+ EP_W1_FREE_TX
) < len
+ pad
+ 4) {
189 /* no room in FIFO */
193 outw(BASE
+ EP_W1_TX_PIO_WR_1
, len
);
194 outw(BASE
+ EP_W1_TX_PIO_WR_1
, 0x0); /* Second dword meaningless */
197 outsw(BASE
+ EP_W1_TX_PIO_WR_1
, pkt
, len
/ 2);
199 outb(BASE
+ EP_W1_TX_PIO_WR_1
, *(pkt
+ len
- 1));
202 outb(BASE
+ EP_W1_TX_PIO_WR_1
, 0); /* Padding */
204 /* timeout after sending */
209 /**************************************************************************
210 ETH_POLL - Wait for a frame
211 ***************************************************************************/
213 EtherReceive(char *pkt
, int maxlen
)
215 /* common variables */
217 /* variables for 3C509 */
219 register short rx_fifo
;
221 cst
= inw(BASE
+ EP_STATUS
);
228 if ((cst
& (S_RX_COMPLETE
|S_RX_EARLY
)) == 0) {
229 /* acknowledge everything */
230 outw(BASE
+ EP_COMMAND
, ACK_INTR
| (cst
& S_5_INTS
));
231 outw(BASE
+ EP_COMMAND
, C_INTR_LATCH
);
236 status
= inw(BASE
+ EP_W1_RX_STATUS
);
238 printf("*%x*",status
);
241 if (status
& ERR_RX
) {
242 outw(BASE
+ EP_COMMAND
, RX_DISCARD_TOP_PACK
);
246 rx_fifo
= status
& RX_BYTES_MASK
;
250 if (rx_fifo
> maxlen
)
255 printf("[l=%d",rx_fifo
);
257 insw(BASE
+ EP_W1_RX_PIO_RD_1
, pkt
, rx_fifo
/ 2);
259 pkt
[rx_fifo
-1] = inb(BASE
+ EP_W1_RX_PIO_RD_1
);
263 status
= inw(BASE
+ EP_W1_RX_STATUS
);
265 printf("*%x*",status
);
267 rx_fifo
= status
& RX_BYTES_MASK
;
270 if ((len
+ rx_fifo
) > maxlen
)
273 insw(BASE
+ EP_W1_RX_PIO_RD_1
, pkt
+ len
, rx_fifo
/ 2);
275 pkt
[len
+ rx_fifo
-1] = inb(BASE
+ EP_W1_RX_PIO_RD_1
);
278 printf("+%d",rx_fifo
);
282 if ((status
& RX_INCOMPLETE
) == 0) {
292 /* acknowledge reception of packet */
293 outw(BASE
+ EP_COMMAND
, RX_DISCARD_TOP_PACK
);
294 while (inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
)
300 outw(BASE
+ EP_COMMAND
, RX_DISCARD_TOP_PACK
);
301 while (inw(BASE
+ EP_STATUS
) & S_COMMAND_IN_PROGRESS
)
306 /*************************************************************************
307 3Com 509 - specific routines
308 **************************************************************************/
315 for (i
= 0; is_eeprom_busy(IS_BASE
) && i
< MAX_EEPROMBUSY
; i
++);
316 if (i
>= MAX_EEPROMBUSY
) {
317 printf("3c509: eeprom failed to come ready.\r\n");
324 * get_e: gets a 16 bits word from the EEPROM. we must have set the window
332 outw(IS_BASE
+ EP_W0_EEPROM_COMMAND
, EEPROM_CMD_RD
| offset
);
335 return inw(IS_BASE
+ EP_W0_EEPROM_DATA
);