iPXE - Open Source Boot Firmware

[build] Rename gPXE to iPXE
[ipxe.git] / src / drivers / net / ne2k_isa.c
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 <ipxe/ethernet.h>
28 #include <ipxe/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  **************************************************************************/
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  **************************************************************************/
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  **************************************************************************/
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  **************************************************************************/
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  **************************************************************************/
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  **************************************************************************/
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  **************************************************************************/
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  **************************************************************************/
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  **************************************************************************/
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");