1 /**************************************************************************
2 Etherboot - BOOTP/TFTP Bootstrap Program
4 Code freely taken from Jan-Pascal van Best and Andreas Mohr's
6 ***************************************************************************/
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2, or (at
12 * your option) any later version.
15 /* to get some global routines like printf */
16 #include "etherboot.h"
17 /* to get the interface to the body of the program */
19 /* to get our own prototype */
22 /* ni5010.h file included verbatim */
24 * Racal-Interlan ni5010 Ethernet definitions
26 * This is an extension to the Linux operating system, and is covered by the
27 * same Gnu Public License that covers that work.
29 * copyrights (c) 1996 by Jan-Pascal van Best (jvbest@wi.leidenuniv.nl)
31 * I have done a look in the following sources:
32 * crynwr-packet-driver by Russ Nelson
35 #define NI5010_BUFSIZE 2048 /* number of bytes in a buffer */
37 #define NI5010_MAGICVAL0 0x00 /* magic-values for ni5010 card */
38 #define NI5010_MAGICVAL1 0x55
39 #define NI5010_MAGICVAL2 0xAA
45 /* The number of low I/O ports used by the ni5010 ethercard. */
46 #define NI5010_IO_EXTENT 32
48 #define PRINTK(x) if (NI5010_DEBUG) printk x
49 #define PRINTK2(x) if (NI5010_DEBUG>=2) printk x
50 #define PRINTK3(x) if (NI5010_DEBUG>=3) printk x
52 /* The various IE command registers */
53 #define EDLC_XSTAT (ioaddr + 0x00) /* EDLC transmit csr */
54 #define EDLC_XCLR (ioaddr + 0x00) /* EDLC transmit "Clear IRQ" */
55 #define EDLC_XMASK (ioaddr + 0x01) /* EDLC transmit "IRQ Masks" */
56 #define EDLC_RSTAT (ioaddr + 0x02) /* EDLC receive csr */
57 #define EDLC_RCLR (ioaddr + 0x02) /* EDLC receive "Clear IRQ" */
58 #define EDLC_RMASK (ioaddr + 0x03) /* EDLC receive "IRQ Masks" */
59 #define EDLC_XMODE (ioaddr + 0x04) /* EDLC transmit Mode */
60 #define EDLC_RMODE (ioaddr + 0x05) /* EDLC receive Mode */
61 #define EDLC_RESET (ioaddr + 0x06) /* EDLC RESET register */
62 #define EDLC_TDR1 (ioaddr + 0x07) /* "Time Domain Reflectometry" reg1 */
63 #define EDLC_ADDR (ioaddr + 0x08) /* EDLC station address, 6 bytes */
64 /* 0x0E doesn't exist for r/w */
65 #define EDLC_TDR2 (ioaddr + 0x0f) /* "Time Domain Reflectometry" reg2 */
66 #define IE_GP (ioaddr + 0x10) /* GP pointer (word register) */
67 /* 0x11 is 2nd byte of GP Pointer */
68 #define IE_RCNT (ioaddr + 0x10) /* Count of bytes in rcv'd packet */
69 /* 0x11 is 2nd byte of "Byte Count" */
70 #define IE_MMODE (ioaddr + 0x12) /* Memory Mode register */
71 #define IE_DMA_RST (ioaddr + 0x13) /* IE DMA Reset. write only */
72 #define IE_ISTAT (ioaddr + 0x13) /* IE Interrupt Status. read only */
73 #define IE_RBUF (ioaddr + 0x14) /* IE Receive Buffer port */
74 #define IE_XBUF (ioaddr + 0x15) /* IE Transmit Buffer port */
75 #define IE_SAPROM (ioaddr + 0x16) /* window on station addr prom */
76 #define IE_RESET (ioaddr + 0x17) /* any write causes Board Reset */
78 /* bits in EDLC_XSTAT, interrupt clear on write, status when read */
79 #define XS_TPOK 0x80 /* transmit packet successful */
80 #define XS_CS 0x40 /* carrier sense */
81 #define XS_RCVD 0x20 /* transmitted packet received */
82 #define XS_SHORT 0x10 /* transmission media is shorted */
83 #define XS_UFLW 0x08 /* underflow. iff failed board */
84 #define XS_COLL 0x04 /* collision occurred */
85 #define XS_16COLL 0x02 /* 16th collision occurred */
86 #define XS_PERR 0x01 /* parity error */
88 #define XS_CLR_UFLW 0x08 /* clear underflow */
89 #define XS_CLR_COLL 0x04 /* clear collision */
90 #define XS_CLR_16COLL 0x02 /* clear 16th collision */
91 #define XS_CLR_PERR 0x01 /* clear parity error */
93 /* bits in EDLC_XMASK, mask/enable transmit interrupts. register is r/w */
94 #define XM_TPOK 0x80 /* =1 to enable Xmt Pkt OK interrupts */
95 #define XM_RCVD 0x20 /* =1 to enable Xmt Pkt Rcvd ints */
96 #define XM_UFLW 0x08 /* =1 to enable Xmt Underflow ints */
97 #define XM_COLL 0x04 /* =1 to enable Xmt Collision ints */
98 #define XM_COLL16 0x02 /* =1 to enable Xmt 16th Coll ints */
99 #define XM_PERR 0x01 /* =1 to enable Xmt Parity Error ints */
100 /* note: always clear this bit */
101 #define XM_ALL (XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16)
103 /* bits in EDLC_RSTAT, interrupt clear on write, status when read */
104 #define RS_PKT_OK 0x80 /* received good packet */
105 #define RS_RST_PKT 0x10 /* RESET packet received */
106 #define RS_RUNT 0x08 /* Runt Pkt rcvd. Len < 64 Bytes */
107 #define RS_ALIGN 0x04 /* Alignment error. not 8 bit aligned */
108 #define RS_CRC_ERR 0x02 /* Bad CRC on rcvd pkt */
109 #define RS_OFLW 0x01 /* overflow for rcv FIFO */
110 #define RS_VALID_BITS ( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW )
111 /* all valid RSTAT bits */
113 #define RS_CLR_PKT_OK 0x80 /* clear rcvd packet interrupt */
114 #define RS_CLR_RST_PKT 0x10 /* clear RESET packet received */
115 #define RS_CLR_RUNT 0x08 /* clear Runt Pckt received */
116 #define RS_CLR_ALIGN 0x04 /* clear Alignment error */
117 #define RS_CLR_CRC_ERR 0x02 /* clear CRC error */
118 #define RS_CLR_OFLW 0x01 /* clear rcv FIFO Overflow */
120 /* bits in EDLC_RMASK, mask/enable receive interrupts. register is r/w */
121 #define RM_PKT_OK 0x80 /* =1 to enable rcvd good packet ints */
122 #define RM_RST_PKT 0x10 /* =1 to enable RESET packet ints */
123 #define RM_RUNT 0x08 /* =1 to enable Runt Pkt rcvd ints */
124 #define RM_ALIGN 0x04 /* =1 to enable Alignment error ints */
125 #define RM_CRC_ERR 0x02 /* =1 to enable Bad CRC error ints */
126 #define RM_OFLW 0x01 /* =1 to enable overflow error ints */
128 /* bits in EDLC_RMODE, set Receive Packet mode. register is r/w */
129 #define RMD_TEST 0x80 /* =1 for Chip testing. normally 0 */
130 #define RMD_ADD_SIZ 0x10 /* =1 5-byte addr match. normally 0 */
131 #define RMD_EN_RUNT 0x08 /* =1 enable runt rcv. normally 0 */
132 #define RMD_EN_RST 0x04 /* =1 to rcv RESET pkt. normally 0 */
134 #define RMD_PROMISC 0x03 /* receive *all* packets. unusual */
135 #define RMD_MULTICAST 0x02 /* receive multicasts too. unusual */
136 #define RMD_BROADCAST 0x01 /* receive broadcasts & normal. usual */
137 #define RMD_NO_PACKETS 0x00 /* don't receive any packets. unusual */
139 /* bits in EDLC_XMODE, set Transmit Packet mode. register is r/w */
140 #define XMD_COLL_CNT 0xf0 /* coll's since success. read-only */
141 #define XMD_IG_PAR 0x08 /* =1 to ignore parity. ALWAYS set */
142 #define XMD_T_MODE 0x04 /* =1 to power xcvr. ALWAYS set this */
143 #define XMD_LBC 0x02 /* =1 for loopback. normally set */
144 #define XMD_DIS_C 0x01 /* =1 disables contention. normally 0 */
146 /* bits in EDLC_RESET, write only */
147 #define RS_RESET 0x80 /* =1 to hold EDLC in reset state */
149 /* bits in IE_MMODE, write only */
150 #define MM_EN_DMA 0x80 /* =1 begin DMA xfer, Cplt clrs it */
151 #define MM_EN_RCV 0x40 /* =1 allows Pkt rcv. clr'd by rcv */
152 #define MM_EN_XMT 0x20 /* =1 begin Xmt pkt. Cplt clrs it */
153 #define MM_BUS_PAGE 0x18 /* =00 ALWAYS. Used when MUX=1 */
154 #define MM_NET_PAGE 0x06 /* =00 ALWAYS. Used when MUX=0 */
155 #define MM_MUX 0x01 /* =1 means Rcv Buff on system bus */
156 /* =0 means Xmt Buff on system bus */
158 /* bits in IE_ISTAT, read only */
159 #define IS_TDIAG 0x80 /* =1 if Diagnostic problem */
160 #define IS_EN_RCV 0x20 /* =1 until frame is rcv'd cplt */
161 #define IS_EN_XMT 0x10 /* =1 until frame is xmt'd cplt */
162 #define IS_EN_DMA 0x08 /* =1 until DMA is cplt or aborted */
163 #define IS_DMA_INT 0x04 /* =0 iff DMA done interrupt. */
164 #define IS_R_INT 0x02 /* =0 iff unmasked Rcv interrupt */
165 #define IS_X_INT 0x01 /* =0 iff unmasked Xmt interrupt */
167 /* NIC specific static variables go here */
169 static unsigned short ioaddr
= 0;
170 static unsigned int bufsize_rcv
= 0;
173 static void show_registers(void)
175 printf("XSTAT %hhX ", inb(EDLC_XSTAT
));
176 printf("XMASK %hhX ", inb(EDLC_XMASK
));
177 printf("RSTAT %hhX ", inb(EDLC_RSTAT
));
178 printf("RMASK %hhX ", inb(EDLC_RMASK
));
179 printf("RMODE %hhX ", inb(EDLC_RMODE
));
180 printf("XMODE %hhX ", inb(EDLC_XMODE
));
181 printf("ISTAT %hhX\n", inb(IE_ISTAT
));
185 static void reset_receiver(void)
187 outw(0, IE_GP
); /* Receive packet at start of buffer */
188 outb(RS_VALID_BITS
, EDLC_RCLR
); /* Clear all pending Rcv interrupts */
189 outb(MM_EN_RCV
, IE_MMODE
); /* Enable rcv */
192 /**************************************************************************
193 RESET - Reset adapter
194 ***************************************************************************/
195 static void ni5010_reset(struct nic
*nic
)
199 /* Reset the hardware here. Don't forget to set the station address. */
200 outb(RS_RESET
, EDLC_RESET
); /* Hold up EDLC_RESET while configing board */
201 outb(0, IE_RESET
); /* Hardware reset of ni5010 board */
202 outb(0, EDLC_XMASK
); /* Disable all Xmt interrupts */
203 outb(0, EDLC_RMASK
); /* Disable all Rcv interrupt */
204 outb(0xFF, EDLC_XCLR
); /* Clear all pending Xmt interrupts */
205 outb(0xFF, EDLC_RCLR
); /* Clear all pending Rcv interrupts */
206 outb(XMD_LBC
, EDLC_XMODE
); /* Only loopback xmits */
207 /* Set the station address */
208 for(i
= 0; i
< ETH_ALEN
; i
++)
209 outb(nic
->node_addr
[i
], EDLC_ADDR
+ i
);
210 outb(XMD_IG_PAR
| XMD_T_MODE
| XMD_LBC
, EDLC_XMODE
);
211 /* Normal packet xmit mode */
212 outb(RMD_BROADCAST
, EDLC_RMODE
);
213 /* Receive broadcast and normal packets */
215 outb(0x00, EDLC_RESET
); /* Un-reset the ni5010 */
218 /**************************************************************************
219 POLL - Wait for a frame
220 ***************************************************************************/
221 static int ni5010_poll(struct nic
*nic
)
225 if (((rcv_stat
= inb(EDLC_RSTAT
)) & RS_VALID_BITS
) != RS_PKT_OK
) {
226 outb(rcv_stat
, EDLC_RSTAT
); /* Clear the status */
229 outb(rcv_stat
, EDLC_RCLR
); /* Clear the status */
230 nic
->packetlen
= inw(IE_RCNT
);
231 /* Read packet into buffer */
232 outb(MM_MUX
, IE_MMODE
); /* Rcv buffer to system bus */
233 outw(0, IE_GP
); /* Seek to beginning of packet */
234 insb(IE_RBUF
, nic
->packet
, nic
->packetlen
);
238 /**************************************************************************
239 TRANSMIT - Transmit a frame
240 ***************************************************************************/
241 static void ni5010_transmit(struct nic
*nic
,
242 const char *d
, /* Destination */
243 unsigned int t
, /* Type */
244 unsigned int s
, /* size */
245 const char *p
) /* Packet */
248 int buf_offs
, xmt_stat
;
254 buf_offs
= NI5010_BUFSIZE
- len
;
255 outb(0, EDLC_RMASK
); /* Mask all receive interrupts */
256 outb(0, IE_MMODE
); /* Put Xmit buffer on system bus */
257 outb(0xFF, EDLC_RCLR
); /* Clear out pending rcv interrupts */
258 outw(buf_offs
, IE_GP
); /* Point GP at start of packet */
259 outsb(IE_XBUF
, d
, ETH_ALEN
); /* Put dst in buffer */
260 outsb(IE_XBUF
, nic
->node_addr
, ETH_ALEN
);/* Put src in buffer */
261 outb(t
>> 8, IE_XBUF
);
263 outsb(IE_XBUF
, p
, s
); /* Put data in buffer */
264 while (s
++ < ETH_ZLEN
- ETH_HLEN
) /* Pad to min size */
266 outw(buf_offs
, IE_GP
); /* Rewrite where packet starts */
267 /* should work without that outb() (Crynwr used it) */
268 /*outb(MM_MUX, IE_MMODE);*/
269 /* Xmt buffer to EDLC bus */
270 outb(MM_EN_XMT
| MM_MUX
, IE_MMODE
); /* Begin transmission */
271 /* wait for transmit complete */
272 while (((xmt_stat
= inb(IE_ISTAT
)) & IS_EN_XMT
) != 0)
274 reset_receiver(); /* Immediately switch to receive */
277 /**************************************************************************
278 DISABLE - Turn off ethernet interface
279 ***************************************************************************/
280 static void ni5010_disable(struct nic
*nic
)
283 outb(RS_RESET
, EDLC_RESET
);
286 static inline int rd_port(void)
289 return inb(IE_SAPROM
);
292 static int ni5010_probe1(struct nic
*nic
)
294 int i
, boguscount
= 40, data
;
296 /* The tests are from the Linux NI5010 driver
297 I don't understand it all, but if it works for them... */
298 if (inb(ioaddr
) == 0xFF)
300 while ((rd_port() & rd_port() & rd_port()
301 & rd_port() & rd_port() & rd_port()) != 0xFF)
303 if (boguscount
-- <= 0)
306 for (i
= 0; i
< 32; i
++)
307 if ((data
= rd_port()) != 0xFF)
311 if (data
== SA_ADDR0
&& rd_port() == SA_ADDR1
&& rd_port() == SA_ADDR2
) {
312 for (i
= 0; i
< 4; i
++)
314 if (rd_port() != NI5010_MAGICVAL1
|| rd_port() != NI5010_MAGICVAL2
)
318 for (i
= 0; i
< ETH_ALEN
; i
++) {
320 nic
->node_addr
[i
] = inb(IE_SAPROM
);
322 printf("\nNI5010 ioaddr %#hX, addr %!\n", ioaddr
, nic
->node_addr
);
323 /* get the size of the onboard receive buffer
324 * higher addresses than bufsize are wrapped into real buffer
325 * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer
327 if (bufsize_rcv
== 0) {
328 outb(1, IE_MMODE
); /* Put Rcv buffer on system bus */
329 outw(0, IE_GP
); /* Point GP at start of packet */
330 outb(0, IE_RBUF
); /* set buffer byte 0 to 0 */
331 for (i
= 1; i
< 0xFF; i
++) {
332 outw(i
<< 8, IE_GP
); /* Point GP at packet size to be tested */
334 outw(0x0, IE_GP
); /* Point GP at start of packet */
336 if (data
== i
) break;
338 bufsize_rcv
= i
<< 8;
339 outw(0, IE_GP
); /* Point GP at start of packet */
340 outb(0, IE_RBUF
); /* set buffer byte 0 to 0 again */
342 printf("Bufsize rcv/xmt=%d/%d\n", bufsize_rcv
, NI5010_BUFSIZE
);
346 /**************************************************************************
347 PROBE - Look for an adapter, this routine's visible to the outside
348 ***************************************************************************/
349 struct nic
*ni5010_probe(struct nic
*nic
, unsigned short *probe_addrs
)
351 static unsigned short io_addrs
[] = {
352 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 };
355 /* if probe_addrs is 0, then use list above */
356 if (probe_addrs
== 0 || *probe_addrs
== 0)
357 probe_addrs
= io_addrs
;
358 for (p
= probe_addrs
; (ioaddr
= *p
) != 0; p
++) {
359 if (ni5010_probe1(nic
))
365 /* point to NIC specific routines */
366 nic
->reset
= ni5010_reset
;
367 nic
->poll
= ni5010_poll
;
368 nic
->transmit
= ni5010_transmit
;
369 nic
->disable
= ni5010_disable
;