|
|
1.1 root 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 ([email protected]) 09/28/2003
17: Relocation support added by Ken Yap ([email protected]) 28/12/02
18: Card Detect support adapted from the eCos driver (Christian Plessl <[email protected]>)
19: Extracted from ns8390.c and adapted by Pantelis Koukousoulas <[email protected]>
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");
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.