nb/intel/*/gma.c: remove spaces at the fake vbt generation
[coreboot.git] / src / drivers / net / ne2k.c
blobed56006ec4dec4f6b1cc35085e75cad2dc6c7c45
1 /*
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
4 Author: Martin Renters
5 Date: May/94
7 This code is based heavily on David Greenman's if_ed.c driver
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.
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 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
19 SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
20 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
21 RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
22 parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
23 SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
24 based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
26 (C) Rudolf Marek <r.marek@assembler.cz> Simplify for RTL8029, Add coreboot glue logic
30 #include <arch/io.h>
31 #include <console/console.h>
32 #include <console/ne2k.h>
33 #include <delay.h>
34 #include <device/device.h>
35 #include <device/pci.h>
36 #include <device/pci_ids.h>
37 #include <device/pci_ops.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ip_checksum.h>
42 #include "ns8390.h"
45 #define ETH_ALEN 6 /* Size of Ethernet address */
46 #define ETH_HLEN 14 /* Size of ethernet header */
47 #define ETH_ZLEN 60 /* Minimum packet */
48 #define ETH_FRAME_LEN 1514 /* Maximum packet */
49 #define ETH_DATA_ALIGN 2 /* Amount needed to align the data after an ethernet header */
50 #define ETH_MAX_MTU (ETH_FRAME_LEN-ETH_HLEN)
52 #define MEM_SIZE MEM_32768
53 #define TX_START 64
54 #define RX_START (64 + D8390_TXBUF_SIZE)
57 static unsigned int get_count(unsigned int eth_nic_base)
59 unsigned int ret;
60 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
61 eth_nic_base + D8390_P0_COMMAND);
63 ret = inb(eth_nic_base + 8 + 0) | (inb(eth_nic_base + 8 + 1) << 8);
65 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
66 eth_nic_base + D8390_P0_COMMAND);
67 return ret;
70 static void set_count(unsigned int eth_nic_base, unsigned int what)
72 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
73 eth_nic_base + D8390_P0_COMMAND);
75 outb(what & 0xff,eth_nic_base + 8);
76 outb((what >> 8) & 0xff,eth_nic_base + 8 + 1);
78 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
79 eth_nic_base + D8390_P0_COMMAND);
82 static void eth_pio_write(unsigned char *src, unsigned int dst, unsigned int cnt,
83 unsigned int eth_nic_base)
85 outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
86 outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
87 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
88 outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
89 outb(dst, eth_nic_base + D8390_P0_RSAR0);
90 outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
91 outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
93 while (cnt--) {
94 outb(*(src++), eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
97 #warning "Add timeout"
99 /* wait for operation finish */
100 while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) != D8390_ISR_RDC)
104 void ne2k_append_data(unsigned char *d, int len, unsigned int base)
106 eth_pio_write(d, (TX_START << 8) + 42 + get_count(base), len, base);
107 set_count(base, get_count(base)+len);
110 #ifdef __ROMCC__
112 void eth_pio_write_byte(int data, unsigned short dst, unsigned int eth_nic_base)
114 outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
115 outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
116 outb(1, eth_nic_base + D8390_P0_RBCR0);
117 outb(0, eth_nic_base + D8390_P0_RBCR1);
118 outb(dst, eth_nic_base + D8390_P0_RSAR0);
119 outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
120 outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
121 outb(data, eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
123 while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) != D8390_ISR_RDC)
127 void ne2k_append_data_byte(int d, unsigned int base)
129 eth_pio_write_byte(d, (TX_START << 8) + 42 + get_count(base), base);
130 set_count(base, get_count(base)+1);
133 static unsigned char eth_pio_read_byte(unsigned int src,
134 unsigned int eth_nic_base)
136 outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
137 outb(0, eth_nic_base + D8390_P0_RBCR0);
138 outb(1, eth_nic_base + D8390_P0_RBCR1);
139 outb(src, eth_nic_base + D8390_P0_RSAR0);
140 outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
141 outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
142 return inb(eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
146 /* Variation of compute_ip_checksum which works on SRAM */
147 unsigned long compute_ip_checksum_from_sram(unsigned short offset, unsigned short length,
148 unsigned int eth_nic_base)
150 unsigned long sum;
151 unsigned long i;
152 /* In the most straight forward way possible,
153 * compute an ip style checksum.
155 sum = 0;
156 for (i = 0; i < length; i++) {
157 unsigned long v;
158 v = eth_pio_read_byte((TX_START << 8)+i+offset, eth_nic_base);
159 if (i & 1) {
160 v <<= 8;
162 /* Add the new value */
163 sum += v;
164 /* Wrap around the carry */
165 if (sum > 0xFFFF) {
166 sum = (sum + (sum >> 16)) & 0xFFFF;
169 return (~((sum & 0xff) | (((sum >> 8) & 0xff) << 8) )) & 0xffff;
173 static void str2ip_load(const char *str, unsigned short offset, unsigned int eth_nic_base)
174 #else
175 static void str2ip(const char *str, unsigned char *ip)
176 #endif
178 unsigned char c, i = 0;
179 int acc = 0;
181 do {
182 c = str[i];
183 if ((c >= '0') && (c <= '9')) {
184 acc *= 10;
185 acc += (c - '0');
186 } else {
187 #ifdef __ROMCC__
188 eth_pio_write_byte(acc, (TX_START << 8)+offset, eth_nic_base);
189 offset++;
190 #else
191 *ip++ = acc;
192 #endif
193 acc = 0;
195 i++;
196 } while (c != '\0');
199 #ifdef __ROMCC__
200 static void str2mac_load(const char *str, unsigned short offset, unsigned int eth_nic_base)
201 #else
202 static void str2mac(const char *str, unsigned char *mac)
203 #endif
205 unsigned char c, i = 0;
206 int acc = 0;
208 do {
210 c = str[i];
211 if ((c >= '0') && (c <= '9')) {
212 acc *= 16;
213 acc += (c - '0');
214 } else if ((c >= 'a') && (c <= 'f')) {
215 acc *= 16;
216 acc += ((c - 'a') + 10) ;
217 } else if ((c >= 'A') && (c <= 'F')) {
218 acc *= 16;
219 acc += ((c - 'A') + 10) ;
220 } else {
221 #ifdef __ROMCC__
222 eth_pio_write_byte(acc, ((TX_START << 8)+offset), eth_nic_base);
223 offset++;
224 #else
225 *mac++ = acc;
226 #endif
227 acc = 0;
230 i++;
231 } while (c != '\0');
235 #ifndef __ROMCC__
236 static void ns8390_tx_header(unsigned int eth_nic_base, int pktlen) {
237 unsigned short chksum;
238 unsigned char hdr[] = {
239 #else
240 static const unsigned char hdr[] = {
241 #endif
243 * ETHERNET HDR
246 // destination macaddr
247 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
248 /* source mac */
249 0x02, 0x00, 0x00, 0xC0, 0xFF, 0xEE,
250 /* ethtype (IP) */
251 0x08, 0x00,
253 * IP HDR
255 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
256 /* TTL, proto (UDP), chksum_hi, chksum_lo, IP0, IP1, IP2, IP3, */
257 0x40, 0x11, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x1,
258 /* IP0, IP1, IP2, IP3 */
259 0xff, 0xff, 0xff, 0xff,
261 * UDP HDR
263 /* SRC PORT DST PORT (2bytes each), ulen, uchksum (must be zero or correct */
264 0x1a, 0x0b, 0x1a, 0x0a, 0x00, 0x9, 0x00, 0x00,
267 #ifndef __ROMCC__
268 str2mac(CONFIG_CONSOLE_NE2K_DST_MAC, &hdr[0]);
269 str2ip(CONFIG_CONSOLE_NE2K_DST_IP, &hdr[30]);
270 str2ip(CONFIG_CONSOLE_NE2K_SRC_IP, &hdr[26]);
272 /* zero checksum */
273 hdr[24] = 0;
274 hdr[25] = 0;
276 /* update IP packet len */
277 hdr[16] = ((28 + pktlen) >> 8) & 0xff;
278 hdr[17] = (28 + pktlen) & 0xff;
280 /* update UDP len */
281 hdr[38] = (8 + pktlen) >> 8;
282 hdr[39] = 8 + pktlen;
284 chksum = compute_ip_checksum(&hdr[14], 20);
286 hdr[25] = chksum >> 8;
287 hdr[24] = chksum;
288 eth_pio_write(hdr, (TX_START << 8), sizeof(hdr), eth_nic_base);
292 #else
294 /* ROMCC madness */
295 static void ns8390_tx_header(unsigned int eth_nic_base, int pktlen)
297 unsigned short chksum;
299 eth_pio_write(hdr, (TX_START << 8), sizeof(hdr), eth_nic_base);
301 str2mac_load(CONFIG_CONSOLE_NE2K_DST_MAC, 0, eth_nic_base);
303 str2ip_load(CONFIG_CONSOLE_NE2K_DST_IP, 30, eth_nic_base);
304 str2ip_load(CONFIG_CONSOLE_NE2K_SRC_IP, 26, eth_nic_base);
305 /* zero checksum */
306 eth_pio_write_byte(0, (TX_START << 8)+24, eth_nic_base);
307 eth_pio_write_byte(0, (TX_START << 8)+25, eth_nic_base);
309 /* update IP packet len */
310 eth_pio_write_byte(((28 + pktlen) >> 8) & 0xff, (TX_START << 8)+16, eth_nic_base);
311 eth_pio_write_byte( (28 + pktlen) & 0xff, (TX_START << 8)+17, eth_nic_base);
313 /* update UDP len */
314 eth_pio_write_byte((8 + pktlen) >> 8, (TX_START << 8)+38, eth_nic_base);
315 eth_pio_write_byte( 8 + pktlen, (TX_START << 8)+39, eth_nic_base);
317 chksum = compute_ip_checksum_from_sram(14, 20, eth_nic_base);
319 eth_pio_write_byte(chksum, (TX_START << 8)+24, eth_nic_base);
320 eth_pio_write_byte(chksum >> 8, (TX_START << 8)+25, eth_nic_base);
323 #endif
325 void ne2k_transmit(unsigned int eth_nic_base) {
326 unsigned int pktsize;
327 unsigned int len = get_count(eth_nic_base);
329 // so place whole header inside chip buffer
330 ns8390_tx_header(eth_nic_base, len);
332 // commit sending now
333 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
335 outb(TX_START, eth_nic_base + D8390_P0_TPSR);
337 pktsize = 42 + len;
338 if (pktsize < 64)
339 pktsize = 64;
341 outb(pktsize, eth_nic_base + D8390_P0_TBCR0);
342 outb(pktsize >> 8, eth_nic_base + D8390_P0_TBCR1);
344 outb(D8390_ISR_PTX, eth_nic_base + D8390_P0_ISR);
346 outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
348 /* wait for operation finish */
349 while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_PTX) != D8390_ISR_PTX) ;
351 set_count(eth_nic_base, 0);
354 #ifdef __PRE_RAM__
356 static void ns8390_reset(unsigned int eth_nic_base)
358 int i;
360 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
361 D8390_COMMAND_STP, eth_nic_base + D8390_P0_COMMAND);
363 outb(0x48, eth_nic_base + D8390_P0_DCR);
364 outb(0, eth_nic_base + D8390_P0_RBCR0);
365 outb(0, eth_nic_base + D8390_P0_RBCR1);
366 outb(0x20, eth_nic_base + D8390_P0_RCR);
367 outb(2, eth_nic_base + D8390_P0_TCR);
368 outb(TX_START, eth_nic_base + D8390_P0_TPSR);
369 outb(RX_START, eth_nic_base + D8390_P0_PSTART);
370 outb(MEM_SIZE, eth_nic_base + D8390_P0_PSTOP);
371 outb(MEM_SIZE - 1, eth_nic_base + D8390_P0_BOUND);
372 outb(0xFF, eth_nic_base + D8390_P0_ISR);
373 outb(0, eth_nic_base + D8390_P0_IMR);
375 outb(D8390_COMMAND_PS1 |
376 D8390_COMMAND_RD2 | D8390_COMMAND_STP,
377 eth_nic_base + D8390_P0_COMMAND);
379 for (i = 0; i < ETH_ALEN; i++)
380 outb(0x0C, eth_nic_base + D8390_P1_PAR0 + i);
382 for (i = 0; i < ETH_ALEN; i++)
383 outb(0xFF, eth_nic_base + D8390_P1_MAR0 + i);
385 outb(RX_START, eth_nic_base + D8390_P1_CURR);
386 outb(D8390_COMMAND_PS0 |
387 D8390_COMMAND_RD2 | D8390_COMMAND_STA,
388 eth_nic_base + D8390_P0_COMMAND);
389 outb(0xFF, eth_nic_base + D8390_P0_ISR);
390 outb(0, eth_nic_base + D8390_P0_TCR);
391 outb(4, eth_nic_base + D8390_P0_RCR);
392 set_count(eth_nic_base, 0);
395 int ne2k_init(unsigned int eth_nic_base) {
397 device_t dev;
398 unsigned char c;
400 /* Power management controller */
401 dev = pci_locate_device(PCI_ID(0x10ec,
402 0x8029), 0);
404 if (dev == PCI_DEV_INVALID)
405 return 0;
407 pci_write_config32(dev, 0x10, eth_nic_base | 1 );
408 pci_write_config8(dev, 0x4, 0x1);
410 c = inb(eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
411 outb(c, eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
413 (void) inb(0x84);
415 outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
416 outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
418 outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
419 outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
420 outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
422 ns8390_reset(eth_nic_base);
423 return 1;
426 #else
427 int ne2k_init(unsigned int eth_nic_base) { return 0; } // dummy symbol for ramstage
429 static void read_resources(struct device *dev)
431 struct resource *res;
433 res = new_resource(dev, PCI_BASE_ADDRESS_0);
434 res->base = CONFIG_CONSOLE_NE2K_IO_PORT;
435 res->size = 32;
436 res->align = 5;
437 res->gran = 5;
438 res->limit = res->base + res->size - 1;
439 res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_STORED |
440 IORESOURCE_ASSIGNED;
441 return;
444 static struct device_operations ne2k_ops = {
445 .read_resources = read_resources,
446 .set_resources = pci_dev_set_resources,
447 .enable_resources = pci_dev_enable_resources,
448 .init = 0,
449 .scan_bus = 0,
452 static const struct pci_driver ne2k_driver __pci_driver = {
453 .ops = &ne2k_ops,
454 .vendor = 0x10ec,
455 .device = 0x8029,
458 #endif /* __PRE_RAM__ */