Home | History | Annotate | Download | only in net
      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 (at) users.sourceforge.net) 09/28/2003
     17  Relocation support added by Ken Yap (ken_yap (at) users.sourceforge.net) 28/12/02
     18  Card Detect support adapted from the eCos driver (Christian Plessl <cplessl (at) ee.ethz.ch>)
     19  Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss (at) 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  **************************************************************************/
     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");
    376