00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 FILE_LICENCE ( BSD2 );
00023
00024 #include "ns8390.h"
00025 #include "etherboot.h"
00026 #include "nic.h"
00027 #include <gpxe/ethernet.h>
00028 #include <gpxe/isa.h>
00029 #include <errno.h>
00030
00031 #define ASIC_PIO NE_DATA
00032
00033 static unsigned char eth_vendor, eth_flags;
00034 static unsigned short eth_nic_base, eth_asic_base;
00035 static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
00036 static Address eth_bmem, eth_rmem;
00037 static unsigned char eth_drain_receiver;
00038
00039 static struct nic_operations ne_operations;
00040 static void ne_reset(struct nic *nic, struct isa_device *isa);
00041
00042 static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
00043
00044
00045
00046
00047 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
00048 outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00049 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
00050 outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
00051 outb(src, eth_nic_base + D8390_P0_RSAR0);
00052 outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
00053 outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00054 if (eth_flags & FLAG_16BIT)
00055 cnt = (cnt + 1) >> 1;
00056
00057 while (cnt--) {
00058 if (eth_flags & FLAG_16BIT) {
00059 *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
00060 dst += 2;
00061 } else
00062 *(dst++) = inb(eth_asic_base + ASIC_PIO);
00063 }
00064 }
00065
00066
00067
00068
00069 static void eth_pio_write(const unsigned char *src, unsigned int dst,
00070 unsigned int cnt) {
00071 outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00072 outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
00073 outb(cnt, eth_nic_base + D8390_P0_RBCR0);
00074 outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
00075 outb(dst, eth_nic_base + D8390_P0_RSAR0);
00076 outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
00077 outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00078 if (eth_flags & FLAG_16BIT)
00079 cnt = (cnt + 1) >> 1;
00080
00081 while (cnt--) {
00082
00083 if (eth_flags & FLAG_16BIT) {
00084 outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
00085 src += 2;
00086 } else
00087 outb(*(src++), eth_asic_base + ASIC_PIO);
00088 }
00089 }
00090
00091
00092
00093
00094 static void enable_multicast(unsigned short eth_nic_base) {
00095 unsigned char mcfilter[8];
00096 int i;
00097
00098 memset(mcfilter, 0xFF, 8);
00099 outb(4, eth_nic_base + D8390_P0_RCR);
00100 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
00101 for (i = 0; i < 8; i++) {
00102 outb(mcfilter[i], eth_nic_base + 8 + i);
00103 if (inb(eth_nic_base + 8 + i) != mcfilter[i])
00104 DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
00105 i);
00106 }
00107 outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
00108 outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
00109 }
00110
00111
00112
00113
00114 static int ne_probe1(isa_probe_addr_t ioaddr) {
00115
00116 unsigned int regd;
00117 unsigned int state;
00118
00119 state = inb(ioaddr);
00120 outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
00121 regd = inb(ioaddr + D8390_P0_TCR);
00122
00123 if (inb(ioaddr + D8390_P0_TCR)) {
00124 outb(ioaddr, state);
00125 outb(ioaddr + 0x0d, regd);
00126 return 0;
00127 }
00128
00129 return 1;
00130 }
00131
00132
00133
00134
00135 static int ne_probe(struct nic *nic, struct isa_device *isa) {
00136 int i;
00137 unsigned char c;
00138 unsigned char romdata[16];
00139 unsigned char testbuf[32];
00140
00141 eth_vendor = VENDOR_NONE;
00142 eth_drain_receiver = 0;
00143
00144 nic->irqno = 0;
00145 nic->ioaddr = isa->ioaddr;
00146 eth_nic_base = isa->ioaddr;
00147
00148
00149
00150
00151 if (eth_vendor == VENDOR_NONE) {
00152
00153 static unsigned char test[] = "NE*000 memory";
00154
00155 eth_bmem = 0;
00156
00157 eth_flags = FLAG_PIO;
00158 eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
00159 eth_memsize = MEM_16384;
00160 eth_tx_start = 32;
00161 eth_rx_start = 32 + D8390_TXBUF_SIZE;
00162 c = inb(eth_asic_base + NE_RESET);
00163 outb(c, eth_asic_base + NE_RESET);
00164 (void) inb(0x84);
00165 outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
00166 + D8390_P0_COMMAND);
00167 outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
00168 outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
00169 outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
00170 outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
00171 eth_pio_write((unsigned char *) test, 8192, sizeof(test));
00172 eth_pio_read(8192, testbuf, sizeof(test));
00173 if (!memcmp(test, testbuf, sizeof(test)))
00174 goto out;
00175 eth_flags |= FLAG_16BIT;
00176 eth_memsize = MEM_32768;
00177 eth_tx_start = 64;
00178 eth_rx_start = 64 + D8390_TXBUF_SIZE;
00179 outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
00180 + D8390_P0_DCR);
00181 outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
00182 outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
00183 eth_pio_write((unsigned char *) test, 16384, sizeof(test));
00184 eth_pio_read(16384, testbuf, sizeof(test));
00185 if (!memcmp(testbuf, test, sizeof(test)))
00186 goto out;
00187
00188
00189 out:
00190 if (eth_nic_base == 0)
00191 return (0);
00192 if (eth_nic_base > ISA_MAX_ADDR)
00193 eth_flags |= FLAG_16BIT;
00194 eth_vendor = VENDOR_NOVELL;
00195 eth_pio_read(0, romdata, sizeof(romdata));
00196 for (i = 0; i < ETH_ALEN; i++) {
00197 nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
00198 }
00199 nic->ioaddr = eth_nic_base;
00200 DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
00201 (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
00202 nic->node_addr));
00203 }
00204
00205 if (eth_vendor == VENDOR_NONE)
00206 return (0);
00207
00208 if (eth_vendor != VENDOR_3COM)
00209 eth_rmem = eth_bmem;
00210
00211 ne_reset(nic, isa);
00212 nic->nic_op = &ne_operations;
00213 return 1;
00214 }
00215
00216
00217
00218
00219
00220 static void ne_disable(struct nic *nic, struct isa_device *isa) {
00221 ne_reset(nic, isa);
00222 }
00223
00224
00225
00226
00227
00228 static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
00229 {
00230 int i;
00231
00232 eth_drain_receiver = 0;
00233 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
00234 D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
00235 if (eth_flags & FLAG_16BIT)
00236 outb(0x49, eth_nic_base+D8390_P0_DCR);
00237 else
00238 outb(0x48, eth_nic_base+D8390_P0_DCR);
00239 outb(0, eth_nic_base+D8390_P0_RBCR0);
00240 outb(0, eth_nic_base+D8390_P0_RBCR1);
00241 outb(0x20, eth_nic_base+D8390_P0_RCR);
00242 outb(2, eth_nic_base+D8390_P0_TCR);
00243 outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
00244 outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
00245
00246 outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
00247 outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
00248 outb(0xFF, eth_nic_base+D8390_P0_ISR);
00249 outb(0, eth_nic_base+D8390_P0_IMR);
00250 outb(D8390_COMMAND_PS1 |
00251 D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
00252
00253 for (i=0; i<ETH_ALEN; i++)
00254 outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
00255 for (i=0; i<ETH_ALEN; i++)
00256 outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
00257 outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
00258 outb(D8390_COMMAND_PS0 |
00259 D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
00260 outb(0xFF, eth_nic_base+D8390_P0_ISR);
00261 outb(0, eth_nic_base+D8390_P0_TCR);
00262 outb(4, eth_nic_base+D8390_P0_RCR);
00263
00264 enable_multicast(eth_nic_base);
00265 }
00266
00267
00268
00269
00270
00271 static int ne_poll(struct nic *nic __unused, int retrieve __unused)
00272 {
00273 int ret = 0;
00274 unsigned char rstat, curr, next;
00275 unsigned short len, frag;
00276 unsigned short pktoff;
00277 unsigned char *p;
00278 struct ringbuffer pkthdr;
00279
00280 rstat = inb(eth_nic_base+D8390_P0_RSR);
00281 if (!(rstat & D8390_RSTAT_PRX)) return(0);
00282 next = inb(eth_nic_base+D8390_P0_BOUND)+1;
00283 if (next >= eth_memsize) next = eth_rx_start;
00284 outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
00285 curr = inb(eth_nic_base+D8390_P1_CURR);
00286 outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
00287 if (curr >= eth_memsize) curr=eth_rx_start;
00288 if (curr == next) return(0);
00289
00290 if ( ! retrieve ) return 1;
00291
00292 pktoff = next << 8;
00293 if (eth_flags & FLAG_PIO)
00294 eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
00295 else
00296 memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
00297 pktoff += sizeof(pkthdr);
00298
00299 len = pkthdr.len - 4;
00300 if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
00301 || len> ETH_FRAME_LEN) {
00302 DBG("Bogus packet, ignoring\n");
00303 return (0);
00304 }
00305 else {
00306 p = nic->packet;
00307 nic->packetlen = len;
00308 frag = (eth_memsize << 8) - pktoff;
00309 if (len> frag) {
00310
00311 if (eth_flags & FLAG_PIO)
00312 eth_pio_read(pktoff, p, frag);
00313 else
00314 memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
00315 pktoff = eth_rx_start << 8;
00316 p += frag;
00317 len -= frag;
00318 }
00319
00320 if (eth_flags & FLAG_PIO)
00321 eth_pio_read(pktoff, p, len);
00322 else
00323 memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
00324 ret = 1;
00325 }
00326 next = pkthdr.next;
00327 if (next == eth_rx_start)
00328 next = eth_memsize;
00329 outb(next-1, eth_nic_base+D8390_P0_BOUND);
00330 return(ret);
00331 }
00332
00333
00334
00335
00336
00337 static void ne_transmit(struct nic *nic, const char *d,
00338 unsigned int t,
00339 unsigned int s,
00340 const char *p) {
00341
00342
00343 unsigned short type;
00344 type = (t >> 8) | (t << 8);
00345 eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
00346 eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
00347
00348 eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
00349 + ETH_ALEN), 2);
00350 eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
00351 s += ETH_HLEN;
00352 if (s < ETH_ZLEN)
00353 s = ETH_ZLEN;
00354
00355 outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
00356 eth_nic_base + D8390_P0_COMMAND);
00357 outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
00358 outb(s, eth_nic_base + D8390_P0_TBCR0);
00359 outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
00360
00361 outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
00362 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00363 }
00364
00365 static struct nic_operations ne_operations = { .connect = dummy_connect,
00366 .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
00367 };
00368
00369 ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
00370 GENERIC_ISAPNP_VENDOR, 0x0600 );
00371
00372 DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
00373 ne_probe, ne_disable );
00374
00375 ISA_ROM("ne","NE1000/2000 and clones");