1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
3
4 Author: Martin Renters
5 Date: May/94
6
7 This code is based heavily on David Greenman's if_ed.c driver
8
9 Copyright (C) 1993-1994, David Greenman, Martin Renters.
10 This software may be used, modified, copied, distributed, and sold, in
11 both source and binary form provided that the above copyright and these
12 terms are retained. Under no circumstances are the authors responsible for
13 the proper functioning of this software, nor do the authors assume any
14 responsibility for damages incurred with its use.
15
16 Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
17 Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
18 Card Detect support adapted from the eCos driver (Christian Plessl <cplessl@ee.ethz.ch>)
19 Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss@gmail.com>
20 **************************************************************************/
21
22 FILE_LICENCE ( BSD2 );
23
24 #include "ns8390.h"
25 #include "etherboot.h"
26 #include "nic.h"
27 #include <gpxe/ethernet.h>
28 #include <gpxe/isa.h>
29 #include <errno.h>
30
31 #define ASIC_PIO NE_DATA
32
33 static unsigned char eth_vendor, eth_flags;
34 static unsigned short eth_nic_base, eth_asic_base;
35 static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
36 static Address eth_bmem, eth_rmem;
37 static unsigned char eth_drain_receiver;
38
39 static struct nic_operations ne_operations;
40 static void ne_reset(struct nic *nic, struct isa_device *isa);
41
42 static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
43
44 /**************************************************************************
45 ETH_PIO_READ - Read a frame via Programmed I/O
46 **************************************************************************/
eth_pio_read(unsigned int src,unsigned char * dst,unsigned int cnt)47 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
48 outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
49 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
50 outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
51 outb(src, eth_nic_base + D8390_P0_RSAR0);
52 outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
53 outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
54 if (eth_flags & FLAG_16BIT)
55 cnt = (cnt + 1) >> 1;
56
57 while (cnt--) {
58 if (eth_flags & FLAG_16BIT) {
59 *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
60 dst += 2;
61 } else
62 *(dst++) = inb(eth_asic_base + ASIC_PIO);
63 }
64 }
65
66 /**************************************************************************
67 ETH_PIO_WRITE - Write a frame via Programmed I/O
68 **************************************************************************/
eth_pio_write(const unsigned char * src,unsigned int dst,unsigned int cnt)69 static void eth_pio_write(const unsigned char *src, unsigned int dst,
70 unsigned int cnt) {
71 outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
72 outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
73 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
74 outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
75 outb(dst, eth_nic_base + D8390_P0_RSAR0);
76 outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
77 outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
78 if (eth_flags & FLAG_16BIT)
79 cnt = (cnt + 1) >> 1;
80
81 while (cnt--) {
82
83 if (eth_flags & FLAG_16BIT) {
84 outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
85 src += 2;
86 } else
87 outb(*(src++), eth_asic_base + ASIC_PIO);
88 }
89 }
90
91 /**************************************************************************
92 enable_multicast - Enable Multicast
93 **************************************************************************/
enable_multicast(unsigned short eth_nic_base)94 static void enable_multicast(unsigned short eth_nic_base) {
95 unsigned char mcfilter[8];
96 int i;
97
98 memset(mcfilter, 0xFF, 8);
99 outb(4, eth_nic_base + D8390_P0_RCR);
100 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
101 for (i = 0; i < 8; i++) {
102 outb(mcfilter[i], eth_nic_base + 8 + i);
103 if (inb(eth_nic_base + 8 + i) != mcfilter[i])
104 DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
105 i);
106 }
107 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
108 outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
109 }
110
111 /**************************************************************************
112 NE_PROBE1 - Look for an adapter on the ISA bus
113 **************************************************************************/
ne_probe1(isa_probe_addr_t ioaddr)114 static int ne_probe1(isa_probe_addr_t ioaddr) {
115 //From the eCos driver
116 unsigned int regd;
117 unsigned int state;
118
119 state = inb(ioaddr);
120 outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
121 regd = inb(ioaddr + D8390_P0_TCR);
122
123 if (inb(ioaddr + D8390_P0_TCR)) {
124 outb(ioaddr, state);
125 outb(ioaddr + 0x0d, regd);
126 return 0;
127 }
128
129 return 1;
130 }
131
132 /**************************************************************************
133 NE_PROBE - Initialize an adapter ???
134 **************************************************************************/
ne_probe(struct nic * nic,struct isa_device * isa)135 static int ne_probe(struct nic *nic, struct isa_device *isa) {
136 int i;
137 unsigned char c;
138 unsigned char romdata[16];
139 unsigned char testbuf[32];
140
141 eth_vendor = VENDOR_NONE;
142 eth_drain_receiver = 0;
143
144 nic->irqno = 0;
145 nic->ioaddr = isa->ioaddr;
146 eth_nic_base = isa->ioaddr;
147
148 /******************************************************************
149 Search for NE1000/2000 if no WD/SMC or 3com cards
150 ******************************************************************/
151 if (eth_vendor == VENDOR_NONE) {
152
153 static unsigned char test[] = "NE*000 memory";
154
155 eth_bmem = 0; /* No shared memory */
156
157 eth_flags = FLAG_PIO;
158 eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
159 eth_memsize = MEM_16384;
160 eth_tx_start = 32;
161 eth_rx_start = 32 + D8390_TXBUF_SIZE;
162 c = inb(eth_asic_base + NE_RESET);
163 outb(c, eth_asic_base + NE_RESET);
164 (void) inb(0x84);
165 outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
166 + D8390_P0_COMMAND);
167 outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
168 outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
169 outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
170 outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
171 eth_pio_write((unsigned char *) test, 8192, sizeof(test));
172 eth_pio_read(8192, testbuf, sizeof(test));
173 if (!memcmp(test, testbuf, sizeof(test)))
174 goto out;
175 eth_flags |= FLAG_16BIT;
176 eth_memsize = MEM_32768;
177 eth_tx_start = 64;
178 eth_rx_start = 64 + D8390_TXBUF_SIZE;
179 outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
180 + D8390_P0_DCR);
181 outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
182 outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
183 eth_pio_write((unsigned char *) test, 16384, sizeof(test));
184 eth_pio_read(16384, testbuf, sizeof(test));
185 if (!memcmp(testbuf, test, sizeof(test)))
186 goto out;
187
188
189 out:
190 if (eth_nic_base == 0)
191 return (0);
192 if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
193 eth_flags |= FLAG_16BIT;
194 eth_vendor = VENDOR_NOVELL;
195 eth_pio_read(0, romdata, sizeof(romdata));
196 for (i = 0; i < ETH_ALEN; i++) {
197 nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
198 }
199 nic->ioaddr = eth_nic_base;
200 DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
201 (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
202 nic->node_addr));
203 }
204
205 if (eth_vendor == VENDOR_NONE)
206 return (0);
207
208 if (eth_vendor != VENDOR_3COM)
209 eth_rmem = eth_bmem;
210
211 ne_reset(nic, isa);
212 nic->nic_op = &ne_operations;
213 return 1;
214 }
215
216
217 /**************************************************************************
218 NE_DISABLE - Turn off adapter
219 **************************************************************************/
ne_disable(struct nic * nic,struct isa_device * isa)220 static void ne_disable(struct nic *nic, struct isa_device *isa) {
221 ne_reset(nic, isa);
222 }
223
224
225 /**************************************************************************
226 NE_RESET - Reset adapter
227 **************************************************************************/
ne_reset(struct nic * nic,struct isa_device * isa __unused)228 static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
229 {
230 int i;
231
232 eth_drain_receiver = 0;
233 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
234 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
235 if (eth_flags & FLAG_16BIT)
236 outb(0x49, eth_nic_base+D8390_P0_DCR);
237 else
238 outb(0x48, eth_nic_base+D8390_P0_DCR);
239 outb(0, eth_nic_base+D8390_P0_RBCR0);
240 outb(0, eth_nic_base+D8390_P0_RBCR1);
241 outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
242 outb(2, eth_nic_base+D8390_P0_TCR);
243 outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
244 outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
245
246 outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
247 outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
248 outb(0xFF, eth_nic_base+D8390_P0_ISR);
249 outb(0, eth_nic_base+D8390_P0_IMR);
250 outb(D8390_COMMAND_PS1 |
251 D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
252
253 for (i=0; i<ETH_ALEN; i++)
254 outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
255 for (i=0; i<ETH_ALEN; i++)
256 outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
257 outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
258 outb(D8390_COMMAND_PS0 |
259 D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
260 outb(0xFF, eth_nic_base+D8390_P0_ISR);
261 outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
262 outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
263
264 enable_multicast(eth_nic_base);
265 }
266
267
268 /**************************************************************************
269 NE_POLL - Wait for a frame
270 **************************************************************************/
ne_poll(struct nic * nic __unused,int retrieve __unused)271 static int ne_poll(struct nic *nic __unused, int retrieve __unused)
272 {
273 int ret = 0;
274 unsigned char rstat, curr, next;
275 unsigned short len, frag;
276 unsigned short pktoff;
277 unsigned char *p;
278 struct ringbuffer pkthdr;
279
280 rstat = inb(eth_nic_base+D8390_P0_RSR);
281 if (!(rstat & D8390_RSTAT_PRX)) return(0);
282 next = inb(eth_nic_base+D8390_P0_BOUND)+1;
283 if (next >= eth_memsize) next = eth_rx_start;
284 outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
285 curr = inb(eth_nic_base+D8390_P1_CURR);
286 outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
287 if (curr >= eth_memsize) curr=eth_rx_start;
288 if (curr == next) return(0);
289
290 if ( ! retrieve ) return 1;
291
292 pktoff = next << 8;
293 if (eth_flags & FLAG_PIO)
294 eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
295 else
296 memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
297 pktoff += sizeof(pkthdr);
298 /* incoming length includes FCS so must sub 4 */
299 len = pkthdr.len - 4;
300 if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
301 || len> ETH_FRAME_LEN) {
302 DBG("Bogus packet, ignoring\n");
303 return (0);
304 }
305 else {
306 p = nic->packet;
307 nic->packetlen = len; /* available to caller */
308 frag = (eth_memsize << 8) - pktoff;
309 if (len> frag) { /* We have a wrap-around */
310 /* read first part */
311 if (eth_flags & FLAG_PIO)
312 eth_pio_read(pktoff, p, frag);
313 else
314 memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
315 pktoff = eth_rx_start << 8;
316 p += frag;
317 len -= frag;
318 }
319 /* read second part */
320 if (eth_flags & FLAG_PIO)
321 eth_pio_read(pktoff, p, len);
322 else
323 memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
324 ret = 1;
325 }
326 next = pkthdr.next; /* frame number of next packet */
327 if (next == eth_rx_start)
328 next = eth_memsize;
329 outb(next-1, eth_nic_base+D8390_P0_BOUND);
330 return(ret);
331 }
332
333
334 /**************************************************************************
335 NE_TRANSMIT - Transmit a frame
336 **************************************************************************/
ne_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)337 static void ne_transmit(struct nic *nic, const char *d, /* Destination */
338 unsigned int t, /* Type */
339 unsigned int s, /* size */
340 const char *p) { /* Packet */
341
342 /* Programmed I/O */
343 unsigned short type;
344 type = (t >> 8) | (t << 8);
345 eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
346 eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
347 /* bcc generates worse code without (const+const) below */
348 eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
349 + ETH_ALEN), 2);
350 eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
351 s += ETH_HLEN;
352 if (s < ETH_ZLEN)
353 s = ETH_ZLEN;
354
355 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
356 eth_nic_base + D8390_P0_COMMAND);
357 outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
358 outb(s, eth_nic_base + D8390_P0_TBCR0);
359 outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
360
361 outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
362 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
363 }
364
365 static struct nic_operations ne_operations = { .connect = dummy_connect,
366 .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
367 };
368
369 ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
370 GENERIC_ISAPNP_VENDOR, 0x0600 );
371
372 DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
373 ne_probe, ne_disable );
374
375 ISA_ROM("ne","NE1000/2000 and clones");
376