[e16e8f2] | 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 | 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) |
---|
| 25 | |
---|
| 26 | **************************************************************************/ |
---|
| 27 | |
---|
| 28 | FILE_LICENCE ( BSD2 ); |
---|
| 29 | |
---|
| 30 | /* #warning "ns8390.c: FIXME: split ISA and PCI, clean up" */ |
---|
| 31 | |
---|
| 32 | #if 1 |
---|
| 33 | |
---|
| 34 | #if !defined(INCLUDE_NS8390) && !defined(INCLUDE_WD) && \ |
---|
| 35 | !defined(INCLUDE_NE) && !defined(INCLUDE_3C503) |
---|
| 36 | /* The driver named ns8390 is the PCI driver, often called |
---|
| 37 | "PCI ne2000 clones". */ |
---|
| 38 | # define INCLUDE_NS8390 1 |
---|
| 39 | #endif |
---|
| 40 | |
---|
| 41 | #include "etherboot.h" |
---|
| 42 | #include "nic.h" |
---|
| 43 | #include "ns8390.h" |
---|
| 44 | #include <gpxe/ethernet.h> |
---|
| 45 | #ifdef INCLUDE_NS8390 |
---|
| 46 | #include <gpxe/pci.h> |
---|
| 47 | #else |
---|
| 48 | #include <gpxe/isa.h> |
---|
| 49 | #endif |
---|
| 50 | |
---|
| 51 | static unsigned char eth_vendor, eth_flags; |
---|
| 52 | #ifdef INCLUDE_WD |
---|
| 53 | static unsigned char eth_laar; |
---|
| 54 | #endif |
---|
| 55 | static unsigned short eth_nic_base, eth_asic_base; |
---|
| 56 | static unsigned char eth_memsize, eth_rx_start, eth_tx_start; |
---|
| 57 | static Address eth_bmem, eth_rmem; |
---|
| 58 | static unsigned char eth_drain_receiver; |
---|
| 59 | |
---|
| 60 | #ifdef INCLUDE_WD |
---|
| 61 | static struct wd_board { |
---|
| 62 | const char *name; |
---|
| 63 | char id; |
---|
| 64 | char flags; |
---|
| 65 | char memsize; |
---|
| 66 | } wd_boards[] = { |
---|
| 67 | {"WD8003S", TYPE_WD8003S, 0, MEM_8192}, |
---|
| 68 | {"WD8003E", TYPE_WD8003E, 0, MEM_8192}, |
---|
| 69 | {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384}, |
---|
| 70 | {"WD8003W", TYPE_WD8003W, 0, MEM_8192}, |
---|
| 71 | {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192}, |
---|
| 72 | {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384}, |
---|
| 73 | {"WD8003EP/WD8013EP", |
---|
| 74 | TYPE_WD8013EP, 0, MEM_8192}, |
---|
| 75 | {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384}, |
---|
| 76 | {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384}, |
---|
| 77 | {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384}, |
---|
| 78 | {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384}, |
---|
| 79 | {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192}, |
---|
| 80 | {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192}, |
---|
| 81 | {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384}, |
---|
| 82 | {NULL, 0, 0, 0} |
---|
| 83 | }; |
---|
| 84 | #endif |
---|
| 85 | |
---|
| 86 | #ifdef INCLUDE_3C503 |
---|
| 87 | static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */ |
---|
| 88 | #endif |
---|
| 89 | |
---|
| 90 | #if defined(INCLUDE_WD) |
---|
| 91 | #define ASIC_PIO WD_IAR |
---|
| 92 | #define eth_probe wd_probe |
---|
| 93 | #if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390) |
---|
| 94 | Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390 |
---|
| 95 | #endif |
---|
| 96 | #endif |
---|
| 97 | |
---|
| 98 | #if defined(INCLUDE_3C503) |
---|
| 99 | #define eth_probe t503_probe |
---|
| 100 | #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD) |
---|
| 101 | Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390 |
---|
| 102 | #endif |
---|
| 103 | #endif |
---|
| 104 | |
---|
| 105 | #if defined(INCLUDE_NE) |
---|
| 106 | #define eth_probe ne_probe |
---|
| 107 | #if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD) |
---|
| 108 | Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390 |
---|
| 109 | #endif |
---|
| 110 | #endif |
---|
| 111 | |
---|
| 112 | #if defined(INCLUDE_NS8390) |
---|
| 113 | #define eth_probe nepci_probe |
---|
| 114 | #if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD) |
---|
| 115 | Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390 |
---|
| 116 | #endif |
---|
| 117 | #endif |
---|
| 118 | |
---|
| 119 | #if defined(INCLUDE_3C503) |
---|
| 120 | #define ASIC_PIO _3COM_RFMSB |
---|
| 121 | #else |
---|
| 122 | #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) |
---|
| 123 | #define ASIC_PIO NE_DATA |
---|
| 124 | #endif |
---|
| 125 | #endif |
---|
| 126 | |
---|
| 127 | #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO)) |
---|
| 128 | /************************************************************************** |
---|
| 129 | ETH_PIO_READ - Read a frame via Programmed I/O |
---|
| 130 | **************************************************************************/ |
---|
| 131 | static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) |
---|
| 132 | { |
---|
| 133 | #ifdef INCLUDE_WD |
---|
| 134 | outb(src & 0xff, eth_asic_base + WD_GP2); |
---|
| 135 | outb(src >> 8, eth_asic_base + WD_GP2); |
---|
| 136 | #else |
---|
| 137 | outb(D8390_COMMAND_RD2 | |
---|
| 138 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); |
---|
| 139 | outb(cnt, eth_nic_base + D8390_P0_RBCR0); |
---|
| 140 | outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1); |
---|
| 141 | outb(src, eth_nic_base + D8390_P0_RSAR0); |
---|
| 142 | outb(src>>8, eth_nic_base + D8390_P0_RSAR1); |
---|
| 143 | outb(D8390_COMMAND_RD0 | |
---|
| 144 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); |
---|
| 145 | |
---|
| 146 | #ifdef INCLUDE_3C503 |
---|
| 147 | outb(src & 0xff, eth_asic_base + _3COM_DALSB); |
---|
| 148 | outb(src >> 8, eth_asic_base + _3COM_DAMSB); |
---|
| 149 | outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR); |
---|
| 150 | #endif |
---|
| 151 | #endif |
---|
| 152 | |
---|
| 153 | if (eth_flags & FLAG_16BIT) |
---|
| 154 | cnt = (cnt + 1) >> 1; |
---|
| 155 | |
---|
| 156 | while(cnt--) { |
---|
| 157 | #ifdef INCLUDE_3C503 |
---|
| 158 | while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0) |
---|
| 159 | ; |
---|
| 160 | #endif |
---|
| 161 | |
---|
| 162 | if (eth_flags & FLAG_16BIT) { |
---|
| 163 | *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO); |
---|
| 164 | dst += 2; |
---|
| 165 | } |
---|
| 166 | else |
---|
| 167 | *(dst++) = inb(eth_asic_base + ASIC_PIO); |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | #ifdef INCLUDE_3C503 |
---|
| 171 | outb(t503_output, eth_asic_base + _3COM_CR); |
---|
| 172 | #endif |
---|
| 173 | } |
---|
| 174 | |
---|
| 175 | /************************************************************************** |
---|
| 176 | ETH_PIO_WRITE - Write a frame via Programmed I/O |
---|
| 177 | **************************************************************************/ |
---|
| 178 | static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt) |
---|
| 179 | { |
---|
| 180 | #ifdef COMPEX_RL2000_FIX |
---|
| 181 | unsigned int x; |
---|
| 182 | #endif /* COMPEX_RL2000_FIX */ |
---|
| 183 | #ifdef INCLUDE_WD |
---|
| 184 | outb(dst & 0xff, eth_asic_base + WD_GP2); |
---|
| 185 | outb(dst >> 8, eth_asic_base + WD_GP2); |
---|
| 186 | #else |
---|
| 187 | outb(D8390_COMMAND_RD2 | |
---|
| 188 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); |
---|
| 189 | outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR); |
---|
| 190 | outb(cnt, eth_nic_base + D8390_P0_RBCR0); |
---|
| 191 | outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1); |
---|
| 192 | outb(dst, eth_nic_base + D8390_P0_RSAR0); |
---|
| 193 | outb(dst>>8, eth_nic_base + D8390_P0_RSAR1); |
---|
| 194 | outb(D8390_COMMAND_RD1 | |
---|
| 195 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); |
---|
| 196 | |
---|
| 197 | #ifdef INCLUDE_3C503 |
---|
| 198 | outb(dst & 0xff, eth_asic_base + _3COM_DALSB); |
---|
| 199 | outb(dst >> 8, eth_asic_base + _3COM_DAMSB); |
---|
| 200 | |
---|
| 201 | outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR); |
---|
| 202 | #endif |
---|
| 203 | #endif |
---|
| 204 | |
---|
| 205 | if (eth_flags & FLAG_16BIT) |
---|
| 206 | cnt = (cnt + 1) >> 1; |
---|
| 207 | |
---|
| 208 | while(cnt--) |
---|
| 209 | { |
---|
| 210 | #ifdef INCLUDE_3C503 |
---|
| 211 | while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0) |
---|
| 212 | ; |
---|
| 213 | #endif |
---|
| 214 | |
---|
| 215 | if (eth_flags & FLAG_16BIT) { |
---|
| 216 | outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO); |
---|
| 217 | src += 2; |
---|
| 218 | } |
---|
| 219 | else |
---|
| 220 | outb(*(src++), eth_asic_base + ASIC_PIO); |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | #ifdef INCLUDE_3C503 |
---|
| 224 | outb(t503_output, eth_asic_base + _3COM_CR); |
---|
| 225 | #else |
---|
| 226 | #ifdef COMPEX_RL2000_FIX |
---|
| 227 | for (x = 0; |
---|
| 228 | x < COMPEX_RL2000_TRIES && |
---|
| 229 | (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) |
---|
| 230 | != D8390_ISR_RDC; |
---|
| 231 | ++x); |
---|
| 232 | if (x >= COMPEX_RL2000_TRIES) |
---|
| 233 | printf("Warning: Compex RL2000 aborted wait!\n"); |
---|
| 234 | #endif /* COMPEX_RL2000_FIX */ |
---|
| 235 | #ifndef INCLUDE_WD |
---|
| 236 | while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) |
---|
| 237 | != D8390_ISR_RDC); |
---|
| 238 | #endif |
---|
| 239 | #endif |
---|
| 240 | } |
---|
| 241 | #else |
---|
| 242 | /************************************************************************** |
---|
| 243 | ETH_PIO_READ - Dummy routine when NE2000 not compiled in |
---|
| 244 | **************************************************************************/ |
---|
| 245 | static void eth_pio_read(unsigned int src __unused, unsigned char *dst __unused, unsigned int cnt __unused) {} |
---|
| 246 | #endif |
---|
| 247 | |
---|
| 248 | |
---|
| 249 | /************************************************************************** |
---|
| 250 | enable_multycast - Enable Multicast |
---|
| 251 | **************************************************************************/ |
---|
| 252 | static void enable_multicast(unsigned short eth_nic_base) |
---|
| 253 | { |
---|
| 254 | unsigned char mcfilter[8]; |
---|
| 255 | int i; |
---|
| 256 | memset(mcfilter, 0xFF, 8); |
---|
| 257 | outb(4, eth_nic_base+D8390_P0_RCR); |
---|
| 258 | outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND); |
---|
| 259 | for(i=0;i<8;i++) |
---|
| 260 | { |
---|
| 261 | outb(mcfilter[i], eth_nic_base + 8 + i); |
---|
| 262 | if(inb(eth_nic_base + 8 + i)!=mcfilter[i]) |
---|
| 263 | printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i); |
---|
| 264 | } |
---|
| 265 | outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND); |
---|
| 266 | outb(4 | 0x08, eth_nic_base+D8390_P0_RCR); |
---|
| 267 | } |
---|
| 268 | |
---|
| 269 | /************************************************************************** |
---|
| 270 | NS8390_RESET - Reset adapter |
---|
| 271 | **************************************************************************/ |
---|
| 272 | static void ns8390_reset(struct nic *nic) |
---|
| 273 | { |
---|
| 274 | int i; |
---|
| 275 | |
---|
| 276 | eth_drain_receiver = 0; |
---|
| 277 | #ifdef INCLUDE_WD |
---|
| 278 | if (eth_flags & FLAG_790) |
---|
| 279 | outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); |
---|
| 280 | else |
---|
| 281 | #endif |
---|
| 282 | outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | |
---|
| 283 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); |
---|
| 284 | if (eth_flags & FLAG_16BIT) |
---|
| 285 | outb(0x49, eth_nic_base+D8390_P0_DCR); |
---|
| 286 | else |
---|
| 287 | outb(0x48, eth_nic_base+D8390_P0_DCR); |
---|
| 288 | outb(0, eth_nic_base+D8390_P0_RBCR0); |
---|
| 289 | outb(0, eth_nic_base+D8390_P0_RBCR1); |
---|
| 290 | outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */ |
---|
| 291 | outb(2, eth_nic_base+D8390_P0_TCR); |
---|
| 292 | outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR); |
---|
| 293 | outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART); |
---|
| 294 | #ifdef INCLUDE_WD |
---|
| 295 | if (eth_flags & FLAG_790) { |
---|
| 296 | #ifdef WD_790_PIO |
---|
| 297 | outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */ |
---|
| 298 | outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */ |
---|
| 299 | #else |
---|
| 300 | outb(0, eth_nic_base + 0x09); |
---|
| 301 | #endif |
---|
| 302 | } |
---|
| 303 | #endif |
---|
| 304 | outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP); |
---|
| 305 | outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND); |
---|
| 306 | outb(0xFF, eth_nic_base+D8390_P0_ISR); |
---|
| 307 | outb(0, eth_nic_base+D8390_P0_IMR); |
---|
| 308 | #ifdef INCLUDE_WD |
---|
| 309 | if (eth_flags & FLAG_790) |
---|
| 310 | outb(D8390_COMMAND_PS1 | |
---|
| 311 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); |
---|
| 312 | else |
---|
| 313 | #endif |
---|
| 314 | outb(D8390_COMMAND_PS1 | |
---|
| 315 | D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); |
---|
| 316 | for (i=0; i<ETH_ALEN; i++) |
---|
| 317 | outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i); |
---|
| 318 | for (i=0; i<ETH_ALEN; i++) |
---|
| 319 | outb(0xFF, eth_nic_base+D8390_P1_MAR0+i); |
---|
| 320 | outb(eth_rx_start, eth_nic_base+D8390_P1_CURR); |
---|
| 321 | #ifdef INCLUDE_WD |
---|
| 322 | if (eth_flags & FLAG_790) |
---|
| 323 | outb(D8390_COMMAND_PS0 | |
---|
| 324 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 325 | else |
---|
| 326 | #endif |
---|
| 327 | outb(D8390_COMMAND_PS0 | |
---|
| 328 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 329 | outb(0xFF, eth_nic_base+D8390_P0_ISR); |
---|
| 330 | outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */ |
---|
| 331 | outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */ |
---|
| 332 | |
---|
| 333 | enable_multicast(eth_nic_base); |
---|
| 334 | |
---|
| 335 | #ifdef INCLUDE_3C503 |
---|
| 336 | /* |
---|
| 337 | * No way to tell whether or not we're supposed to use |
---|
| 338 | * the 3Com's transceiver unless the user tells us. |
---|
| 339 | * 'flags' should have some compile time default value |
---|
| 340 | * which can be changed from the command menu. |
---|
| 341 | */ |
---|
| 342 | t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL; |
---|
| 343 | outb(t503_output, eth_asic_base + _3COM_CR); |
---|
| 344 | #endif |
---|
| 345 | } |
---|
| 346 | |
---|
| 347 | static int ns8390_poll(struct nic *nic, int retrieve); |
---|
| 348 | |
---|
| 349 | #ifndef INCLUDE_3C503 |
---|
| 350 | /************************************************************************** |
---|
| 351 | ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun |
---|
| 352 | **************************************************************************/ |
---|
| 353 | static void eth_rx_overrun(struct nic *nic) |
---|
| 354 | { |
---|
| 355 | int start_time; |
---|
| 356 | |
---|
| 357 | #ifdef INCLUDE_WD |
---|
| 358 | if (eth_flags & FLAG_790) |
---|
| 359 | outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); |
---|
| 360 | else |
---|
| 361 | #endif |
---|
| 362 | outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | |
---|
| 363 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); |
---|
| 364 | |
---|
| 365 | /* wait for at least 1.6ms - we wait one timer tick */ |
---|
| 366 | start_time = currticks(); |
---|
| 367 | while (currticks() - start_time <= 1) |
---|
| 368 | /* Nothing */; |
---|
| 369 | |
---|
| 370 | outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */ |
---|
| 371 | outb(0, eth_nic_base+D8390_P0_RBCR1); |
---|
| 372 | |
---|
| 373 | /* |
---|
| 374 | * Linux driver checks for interrupted TX here. This is not necessary, |
---|
| 375 | * because the transmit routine waits until the frame is sent. |
---|
| 376 | */ |
---|
| 377 | |
---|
| 378 | /* enter loopback mode and restart NIC */ |
---|
| 379 | outb(2, eth_nic_base+D8390_P0_TCR); |
---|
| 380 | #ifdef INCLUDE_WD |
---|
| 381 | if (eth_flags & FLAG_790) |
---|
| 382 | outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 383 | else |
---|
| 384 | #endif |
---|
| 385 | outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | |
---|
| 386 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 387 | |
---|
| 388 | /* clear the RX ring, acknowledge overrun interrupt */ |
---|
| 389 | eth_drain_receiver = 1; |
---|
| 390 | while (ns8390_poll(nic, 1)) |
---|
| 391 | /* Nothing */; |
---|
| 392 | eth_drain_receiver = 0; |
---|
| 393 | outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR); |
---|
| 394 | |
---|
| 395 | /* leave loopback mode - no packets to be resent (see Linux driver) */ |
---|
| 396 | outb(0, eth_nic_base+D8390_P0_TCR); |
---|
| 397 | } |
---|
| 398 | #endif /* INCLUDE_3C503 */ |
---|
| 399 | |
---|
| 400 | /************************************************************************** |
---|
| 401 | NS8390_TRANSMIT - Transmit a frame |
---|
| 402 | **************************************************************************/ |
---|
| 403 | static void ns8390_transmit( |
---|
| 404 | struct nic *nic, |
---|
| 405 | const char *d, /* Destination */ |
---|
| 406 | unsigned int t, /* Type */ |
---|
| 407 | unsigned int s, /* size */ |
---|
| 408 | const char *p) /* Packet */ |
---|
| 409 | { |
---|
| 410 | #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO)) |
---|
| 411 | Address eth_vmem = bus_to_virt(eth_bmem); |
---|
| 412 | #endif |
---|
| 413 | #ifdef INCLUDE_3C503 |
---|
| 414 | if (!(eth_flags & FLAG_PIO)) { |
---|
| 415 | memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */ |
---|
| 416 | memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ |
---|
| 417 | *((char *)eth_vmem+12) = t>>8; /* type */ |
---|
| 418 | *((char *)eth_vmem+13) = t; |
---|
| 419 | memcpy((char *)eth_vmem+ETH_HLEN, p, s); |
---|
| 420 | s += ETH_HLEN; |
---|
| 421 | while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0; |
---|
| 422 | } |
---|
| 423 | #endif |
---|
| 424 | |
---|
| 425 | #ifdef INCLUDE_WD |
---|
| 426 | if (eth_flags & FLAG_16BIT) { |
---|
| 427 | outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR); |
---|
| 428 | inb(0x84); |
---|
| 429 | } |
---|
| 430 | #ifndef WD_790_PIO |
---|
| 431 | /* Memory interface */ |
---|
| 432 | if (eth_flags & FLAG_790) { |
---|
| 433 | outb(WD_MSR_MENB, eth_asic_base + WD_MSR); |
---|
| 434 | inb(0x84); |
---|
| 435 | } |
---|
| 436 | inb(0x84); |
---|
| 437 | memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */ |
---|
| 438 | memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ |
---|
| 439 | *((char *)eth_vmem+12) = t>>8; /* type */ |
---|
| 440 | *((char *)eth_vmem+13) = t; |
---|
| 441 | memcpy((char *)eth_vmem+ETH_HLEN, p, s); |
---|
| 442 | s += ETH_HLEN; |
---|
| 443 | while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0; |
---|
| 444 | if (eth_flags & FLAG_790) { |
---|
| 445 | outb(0, eth_asic_base + WD_MSR); |
---|
| 446 | inb(0x84); |
---|
| 447 | } |
---|
| 448 | #else |
---|
| 449 | inb(0x84); |
---|
| 450 | #endif |
---|
| 451 | #endif |
---|
| 452 | |
---|
| 453 | #if defined(INCLUDE_3C503) |
---|
| 454 | if (eth_flags & FLAG_PIO) |
---|
| 455 | #endif |
---|
| 456 | #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO)) |
---|
| 457 | { |
---|
| 458 | /* Programmed I/O */ |
---|
| 459 | unsigned short type; |
---|
| 460 | type = (t >> 8) | (t << 8); |
---|
| 461 | eth_pio_write( (unsigned char *) d, eth_tx_start<<8, ETH_ALEN); |
---|
| 462 | eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN); |
---|
| 463 | /* bcc generates worse code without (const+const) below */ |
---|
| 464 | eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2); |
---|
| 465 | eth_pio_write( (unsigned char *) p, (eth_tx_start<<8)+ETH_HLEN, s); |
---|
| 466 | s += ETH_HLEN; |
---|
| 467 | if (s < ETH_ZLEN) s = ETH_ZLEN; |
---|
| 468 | } |
---|
| 469 | #endif |
---|
| 470 | #if defined(INCLUDE_3C503) |
---|
| 471 | #endif |
---|
| 472 | |
---|
| 473 | #ifdef INCLUDE_WD |
---|
| 474 | if (eth_flags & FLAG_16BIT) { |
---|
| 475 | outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR); |
---|
| 476 | inb(0x84); |
---|
| 477 | } |
---|
| 478 | if (eth_flags & FLAG_790) |
---|
| 479 | outb(D8390_COMMAND_PS0 | |
---|
| 480 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 481 | else |
---|
| 482 | #endif |
---|
| 483 | outb(D8390_COMMAND_PS0 | |
---|
| 484 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 485 | outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR); |
---|
| 486 | outb(s, eth_nic_base+D8390_P0_TBCR0); |
---|
| 487 | outb(s>>8, eth_nic_base+D8390_P0_TBCR1); |
---|
| 488 | #ifdef INCLUDE_WD |
---|
| 489 | if (eth_flags & FLAG_790) |
---|
| 490 | outb(D8390_COMMAND_PS0 | |
---|
| 491 | D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 492 | else |
---|
| 493 | #endif |
---|
| 494 | outb(D8390_COMMAND_PS0 | |
---|
| 495 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 | |
---|
| 496 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); |
---|
| 497 | } |
---|
| 498 | |
---|
| 499 | /************************************************************************** |
---|
| 500 | NS8390_POLL - Wait for a frame |
---|
| 501 | **************************************************************************/ |
---|
| 502 | static int ns8390_poll(struct nic *nic, int retrieve) |
---|
| 503 | { |
---|
| 504 | int ret = 0; |
---|
| 505 | unsigned char rstat, curr, next; |
---|
| 506 | unsigned short len, frag; |
---|
| 507 | unsigned short pktoff; |
---|
| 508 | unsigned char *p; |
---|
| 509 | struct ringbuffer pkthdr; |
---|
| 510 | |
---|
| 511 | #ifndef INCLUDE_3C503 |
---|
| 512 | /* avoid infinite recursion: see eth_rx_overrun() */ |
---|
| 513 | if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) { |
---|
| 514 | eth_rx_overrun(nic); |
---|
| 515 | return(0); |
---|
| 516 | } |
---|
| 517 | #endif /* INCLUDE_3C503 */ |
---|
| 518 | rstat = inb(eth_nic_base+D8390_P0_RSR); |
---|
| 519 | if (!(rstat & D8390_RSTAT_PRX)) return(0); |
---|
| 520 | next = inb(eth_nic_base+D8390_P0_BOUND)+1; |
---|
| 521 | if (next >= eth_memsize) next = eth_rx_start; |
---|
| 522 | outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND); |
---|
| 523 | curr = inb(eth_nic_base+D8390_P1_CURR); |
---|
| 524 | outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND); |
---|
| 525 | if (curr >= eth_memsize) curr=eth_rx_start; |
---|
| 526 | if (curr == next) return(0); |
---|
| 527 | |
---|
| 528 | if ( ! retrieve ) return 1; |
---|
| 529 | |
---|
| 530 | #ifdef INCLUDE_WD |
---|
| 531 | if (eth_flags & FLAG_16BIT) { |
---|
| 532 | outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR); |
---|
| 533 | inb(0x84); |
---|
| 534 | } |
---|
| 535 | #ifndef WD_790_PIO |
---|
| 536 | if (eth_flags & FLAG_790) { |
---|
| 537 | outb(WD_MSR_MENB, eth_asic_base + WD_MSR); |
---|
| 538 | inb(0x84); |
---|
| 539 | } |
---|
| 540 | #endif |
---|
| 541 | inb(0x84); |
---|
| 542 | #endif |
---|
| 543 | pktoff = next << 8; |
---|
| 544 | if (eth_flags & FLAG_PIO) |
---|
| 545 | eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4); |
---|
| 546 | else |
---|
| 547 | memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4); |
---|
| 548 | pktoff += sizeof(pkthdr); |
---|
| 549 | /* incoming length includes FCS so must sub 4 */ |
---|
| 550 | len = pkthdr.len - 4; |
---|
| 551 | if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN |
---|
| 552 | || len > ETH_FRAME_LEN) { |
---|
| 553 | printf("Bogus packet, ignoring\n"); |
---|
| 554 | return (0); |
---|
| 555 | } |
---|
| 556 | else { |
---|
| 557 | p = nic->packet; |
---|
| 558 | nic->packetlen = len; /* available to caller */ |
---|
| 559 | frag = (eth_memsize << 8) - pktoff; |
---|
| 560 | if (len > frag) { /* We have a wrap-around */ |
---|
| 561 | /* read first part */ |
---|
| 562 | if (eth_flags & FLAG_PIO) |
---|
| 563 | eth_pio_read(pktoff, p, frag); |
---|
| 564 | else |
---|
| 565 | memcpy(p, bus_to_virt(eth_rmem + pktoff), frag); |
---|
| 566 | pktoff = eth_rx_start << 8; |
---|
| 567 | p += frag; |
---|
| 568 | len -= frag; |
---|
| 569 | } |
---|
| 570 | /* read second part */ |
---|
| 571 | if (eth_flags & FLAG_PIO) |
---|
| 572 | eth_pio_read(pktoff, p, len); |
---|
| 573 | else |
---|
| 574 | memcpy(p, bus_to_virt(eth_rmem + pktoff), len); |
---|
| 575 | ret = 1; |
---|
| 576 | } |
---|
| 577 | #ifdef INCLUDE_WD |
---|
| 578 | #ifndef WD_790_PIO |
---|
| 579 | if (eth_flags & FLAG_790) { |
---|
| 580 | outb(0, eth_asic_base + WD_MSR); |
---|
| 581 | inb(0x84); |
---|
| 582 | } |
---|
| 583 | #endif |
---|
| 584 | if (eth_flags & FLAG_16BIT) { |
---|
| 585 | outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR); |
---|
| 586 | inb(0x84); |
---|
| 587 | } |
---|
| 588 | inb(0x84); |
---|
| 589 | #endif |
---|
| 590 | next = pkthdr.next; /* frame number of next packet */ |
---|
| 591 | if (next == eth_rx_start) |
---|
| 592 | next = eth_memsize; |
---|
| 593 | outb(next-1, eth_nic_base+D8390_P0_BOUND); |
---|
| 594 | return(ret); |
---|
| 595 | } |
---|
| 596 | |
---|
| 597 | /************************************************************************** |
---|
| 598 | NS8390_DISABLE - Turn off adapter |
---|
| 599 | **************************************************************************/ |
---|
| 600 | static void ns8390_disable ( struct nic *nic ) { |
---|
| 601 | ns8390_reset(nic); |
---|
| 602 | } |
---|
| 603 | |
---|
| 604 | /************************************************************************** |
---|
| 605 | NS8390_IRQ - Enable, Disable, or Force interrupts |
---|
| 606 | **************************************************************************/ |
---|
| 607 | static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused) |
---|
| 608 | { |
---|
| 609 | switch ( action ) { |
---|
| 610 | case DISABLE : |
---|
| 611 | break; |
---|
| 612 | case ENABLE : |
---|
| 613 | break; |
---|
| 614 | case FORCE : |
---|
| 615 | break; |
---|
| 616 | } |
---|
| 617 | } |
---|
| 618 | |
---|
| 619 | static struct nic_operations ns8390_operations; |
---|
| 620 | static struct nic_operations ns8390_operations = { |
---|
| 621 | .connect = dummy_connect, |
---|
| 622 | .poll = ns8390_poll, |
---|
| 623 | .transmit = ns8390_transmit, |
---|
| 624 | .irq = ns8390_irq, |
---|
| 625 | }; |
---|
| 626 | |
---|
| 627 | /************************************************************************** |
---|
| 628 | ETH_PROBE - Look for an adapter |
---|
| 629 | **************************************************************************/ |
---|
| 630 | #ifdef INCLUDE_NS8390 |
---|
| 631 | static int eth_probe (struct nic *nic, struct pci_device *pci) |
---|
| 632 | #else |
---|
| 633 | static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused) |
---|
| 634 | #endif |
---|
| 635 | { |
---|
| 636 | int i; |
---|
| 637 | #ifdef INCLUDE_NS8390 |
---|
| 638 | unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 }; |
---|
| 639 | unsigned short *probe_addrs = pci_probe_addrs; |
---|
| 640 | #endif |
---|
| 641 | eth_vendor = VENDOR_NONE; |
---|
| 642 | eth_drain_receiver = 0; |
---|
| 643 | |
---|
| 644 | nic->irqno = 0; |
---|
| 645 | |
---|
| 646 | #ifdef INCLUDE_WD |
---|
| 647 | { |
---|
| 648 | /****************************************************************** |
---|
| 649 | Search for WD/SMC cards |
---|
| 650 | ******************************************************************/ |
---|
| 651 | struct wd_board *brd; |
---|
| 652 | unsigned short chksum; |
---|
| 653 | unsigned char c; |
---|
| 654 | for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE; |
---|
| 655 | eth_asic_base += 0x20) { |
---|
| 656 | chksum = 0; |
---|
| 657 | for (i=8; i<16; i++) |
---|
| 658 | chksum += inb(eth_asic_base+i); |
---|
| 659 | /* Extra checks to avoid soundcard */ |
---|
| 660 | if ((chksum & 0xFF) == 0xFF && |
---|
| 661 | inb(eth_asic_base+8) != 0xFF && |
---|
| 662 | inb(eth_asic_base+9) != 0xFF) |
---|
| 663 | break; |
---|
| 664 | } |
---|
| 665 | if (eth_asic_base > WD_HIGH_BASE) |
---|
| 666 | return (0); |
---|
| 667 | /* We've found a board */ |
---|
| 668 | eth_vendor = VENDOR_WD; |
---|
| 669 | eth_nic_base = eth_asic_base + WD_NIC_ADDR; |
---|
| 670 | |
---|
| 671 | nic->ioaddr = eth_nic_base; |
---|
| 672 | |
---|
| 673 | c = inb(eth_asic_base+WD_BID); /* Get board id */ |
---|
| 674 | for (brd = wd_boards; brd->name; brd++) |
---|
| 675 | if (brd->id == c) break; |
---|
| 676 | if (!brd->name) { |
---|
| 677 | printf("Unknown WD/SMC NIC type %hhX\n", c); |
---|
| 678 | return (0); /* Unknown type */ |
---|
| 679 | } |
---|
| 680 | eth_flags = brd->flags; |
---|
| 681 | eth_memsize = brd->memsize; |
---|
| 682 | eth_tx_start = 0; |
---|
| 683 | eth_rx_start = D8390_TXBUF_SIZE; |
---|
| 684 | if ((c == TYPE_WD8013EP) && |
---|
| 685 | (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) { |
---|
| 686 | eth_flags = FLAG_16BIT; |
---|
| 687 | eth_memsize = MEM_16384; |
---|
| 688 | } |
---|
| 689 | if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) { |
---|
| 690 | eth_bmem = (0x80000 | |
---|
| 691 | ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13)); |
---|
| 692 | } else |
---|
| 693 | eth_bmem = WD_DEFAULT_MEM; |
---|
| 694 | if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { |
---|
| 695 | /* from Linux driver, 8416BT detects as 8216 sometimes */ |
---|
| 696 | unsigned int addr = inb(eth_asic_base + 0xb); |
---|
| 697 | if (((addr >> 4) & 3) == 0) { |
---|
| 698 | brd += 2; |
---|
| 699 | eth_memsize = brd->memsize; |
---|
| 700 | } |
---|
| 701 | } |
---|
| 702 | outb(0x80, eth_asic_base + WD_MSR); /* Reset */ |
---|
| 703 | for (i=0; i<ETH_ALEN; i++) { |
---|
| 704 | nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR); |
---|
| 705 | } |
---|
| 706 | DBG ( "\n%s base %4.4x", brd->name, eth_asic_base ); |
---|
| 707 | if (eth_flags & FLAG_790) { |
---|
| 708 | #ifdef WD_790_PIO |
---|
| 709 | DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) ); |
---|
| 710 | eth_bmem = 0; |
---|
| 711 | eth_flags |= FLAG_PIO; /* force PIO mode */ |
---|
| 712 | outb(0, eth_asic_base+WD_MSR); |
---|
| 713 | #else |
---|
| 714 | DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) ); |
---|
| 715 | |
---|
| 716 | outb(WD_MSR_MENB, eth_asic_base+WD_MSR); |
---|
| 717 | outb((inb(eth_asic_base+0x04) | |
---|
| 718 | 0x80), eth_asic_base+0x04); |
---|
| 719 | outb(((unsigned)(eth_bmem >> 13) & 0x0F) | |
---|
| 720 | ((unsigned)(eth_bmem >> 11) & 0x40) | |
---|
| 721 | (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B); |
---|
| 722 | outb((inb(eth_asic_base+0x04) & |
---|
| 723 | ~0x80), eth_asic_base+0x04); |
---|
| 724 | #endif |
---|
| 725 | } else { |
---|
| 726 | |
---|
| 727 | DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) ); |
---|
| 728 | |
---|
| 729 | outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR); |
---|
| 730 | } |
---|
| 731 | if (eth_flags & FLAG_16BIT) { |
---|
| 732 | if (eth_flags & FLAG_790) { |
---|
| 733 | eth_laar = inb(eth_asic_base + WD_LAAR); |
---|
| 734 | outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR); |
---|
| 735 | } else { |
---|
| 736 | outb((eth_laar = |
---|
| 737 | WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR); |
---|
| 738 | /* |
---|
| 739 | The previous line used to be |
---|
| 740 | WD_LAAR_M16EN | WD_LAAR_L16EN | 1)); |
---|
| 741 | jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made |
---|
| 742 | it work for WD8013s. This seems to work for my 8013 boards. I |
---|
| 743 | don't know what is really happening. I wish I had data sheets |
---|
| 744 | or more time to decode the Linux driver. - Ken |
---|
| 745 | */ |
---|
| 746 | } |
---|
| 747 | inb(0x84); |
---|
| 748 | } |
---|
| 749 | } |
---|
| 750 | #endif |
---|
| 751 | #ifdef INCLUDE_3C503 |
---|
| 752 | #ifdef T503_AUI |
---|
| 753 | nic->flags = 1; /* aui */ |
---|
| 754 | #else |
---|
| 755 | nic->flags = 0; /* no aui */ |
---|
| 756 | #endif |
---|
| 757 | /****************************************************************** |
---|
| 758 | Search for 3Com 3c503 if no WD/SMC cards |
---|
| 759 | ******************************************************************/ |
---|
| 760 | if (eth_vendor == VENDOR_NONE) { |
---|
| 761 | int idx; |
---|
| 762 | int iobase_reg, membase_reg; |
---|
| 763 | static unsigned short base[] = { |
---|
| 764 | 0x300, 0x310, 0x330, 0x350, |
---|
| 765 | 0x250, 0x280, 0x2A0, 0x2E0, 0 }; |
---|
| 766 | |
---|
| 767 | /* Loop through possible addresses checking each one */ |
---|
| 768 | |
---|
| 769 | for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) { |
---|
| 770 | |
---|
| 771 | eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET; |
---|
| 772 | /* |
---|
| 773 | * Note that we use the same settings for both 8 and 16 bit cards: |
---|
| 774 | * both have an 8K bank of memory at page 1 while only the 16 bit |
---|
| 775 | * cards have a bank at page 0. |
---|
| 776 | */ |
---|
| 777 | eth_memsize = MEM_16384; |
---|
| 778 | eth_tx_start = 32; |
---|
| 779 | eth_rx_start = 32 + D8390_TXBUF_SIZE; |
---|
| 780 | |
---|
| 781 | /* Check our base address. iobase and membase should */ |
---|
| 782 | /* both have a maximum of 1 bit set or be 0. */ |
---|
| 783 | |
---|
| 784 | iobase_reg = inb(eth_asic_base + _3COM_BCFR); |
---|
| 785 | membase_reg = inb(eth_asic_base + _3COM_PCFR); |
---|
| 786 | |
---|
| 787 | if ((iobase_reg & (iobase_reg - 1)) || |
---|
| 788 | (membase_reg & (membase_reg - 1))) |
---|
| 789 | continue; /* nope */ |
---|
| 790 | |
---|
| 791 | /* Now get the shared memory address */ |
---|
| 792 | |
---|
| 793 | eth_flags = 0; |
---|
| 794 | |
---|
| 795 | switch (membase_reg) { |
---|
| 796 | case _3COM_PCFR_DC000: |
---|
| 797 | eth_bmem = 0xdc000; |
---|
| 798 | break; |
---|
| 799 | case _3COM_PCFR_D8000: |
---|
| 800 | eth_bmem = 0xd8000; |
---|
| 801 | break; |
---|
| 802 | case _3COM_PCFR_CC000: |
---|
| 803 | eth_bmem = 0xcc000; |
---|
| 804 | break; |
---|
| 805 | case _3COM_PCFR_C8000: |
---|
| 806 | eth_bmem = 0xc8000; |
---|
| 807 | break; |
---|
| 808 | case _3COM_PCFR_PIO: |
---|
| 809 | eth_flags |= FLAG_PIO; |
---|
| 810 | eth_bmem = 0; |
---|
| 811 | break; |
---|
| 812 | default: |
---|
| 813 | continue; /* nope */ |
---|
| 814 | } |
---|
| 815 | break; |
---|
| 816 | } |
---|
| 817 | |
---|
| 818 | if (base[idx] == 0) /* not found */ |
---|
| 819 | return (0); |
---|
| 820 | #ifndef T503_SHMEM |
---|
| 821 | eth_flags |= FLAG_PIO; /* force PIO mode */ |
---|
| 822 | eth_bmem = 0; |
---|
| 823 | #endif |
---|
| 824 | eth_vendor = VENDOR_3COM; |
---|
| 825 | |
---|
| 826 | |
---|
| 827 | /* Need this to make ns8390_poll() happy. */ |
---|
| 828 | |
---|
| 829 | eth_rmem = eth_bmem - 0x2000; |
---|
| 830 | |
---|
| 831 | /* Reset NIC and ASIC */ |
---|
| 832 | |
---|
| 833 | outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR ); |
---|
| 834 | outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR ); |
---|
| 835 | |
---|
| 836 | /* Get our ethernet address */ |
---|
| 837 | |
---|
| 838 | outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR); |
---|
| 839 | nic->ioaddr = eth_nic_base; |
---|
| 840 | DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base ); |
---|
| 841 | if (eth_flags & FLAG_PIO) |
---|
| 842 | DBG ( "PIO mode" ); |
---|
| 843 | else |
---|
| 844 | DBG ( "memory %4.4x", eth_bmem ); |
---|
| 845 | for (i=0; i<ETH_ALEN; i++) { |
---|
| 846 | nic->node_addr[i] = inb(eth_nic_base+i); |
---|
| 847 | } |
---|
| 848 | DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr", |
---|
| 849 | eth_ntoa ( nic->node_addr ) ); |
---|
| 850 | |
---|
| 851 | outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR); |
---|
| 852 | /* |
---|
| 853 | * Initialize GA configuration register. Set bank and enable shared |
---|
| 854 | * mem. We always use bank 1. Disable interrupts. |
---|
| 855 | */ |
---|
| 856 | outb(_3COM_GACFR_RSEL | |
---|
| 857 | _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR); |
---|
| 858 | |
---|
| 859 | outb(0xff, eth_asic_base + _3COM_VPTR2); |
---|
| 860 | outb(0xff, eth_asic_base + _3COM_VPTR1); |
---|
| 861 | outb(0x00, eth_asic_base + _3COM_VPTR0); |
---|
| 862 | /* |
---|
| 863 | * Clear memory and verify that it worked (we use only 8K) |
---|
| 864 | */ |
---|
| 865 | |
---|
| 866 | if (!(eth_flags & FLAG_PIO)) { |
---|
| 867 | memset(bus_to_virt(eth_bmem), 0, 0x2000); |
---|
| 868 | for(i = 0; i < 0x2000; ++i) |
---|
| 869 | if (*((char *)(bus_to_virt(eth_bmem+i)))) { |
---|
| 870 | printf ("Failed to clear 3c503 shared mem.\n"); |
---|
| 871 | return (0); |
---|
| 872 | } |
---|
| 873 | } |
---|
| 874 | /* |
---|
| 875 | * Initialize GA page/start/stop registers. |
---|
| 876 | */ |
---|
| 877 | outb(eth_tx_start, eth_asic_base + _3COM_PSTR); |
---|
| 878 | outb(eth_memsize, eth_asic_base + _3COM_PSPR); |
---|
| 879 | } |
---|
| 880 | #endif |
---|
| 881 | #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) |
---|
| 882 | { |
---|
| 883 | /****************************************************************** |
---|
| 884 | Search for NE1000/2000 if no WD/SMC or 3com cards |
---|
| 885 | ******************************************************************/ |
---|
| 886 | unsigned char c; |
---|
| 887 | if (eth_vendor == VENDOR_NONE) { |
---|
| 888 | unsigned char romdata[16]; |
---|
| 889 | unsigned char testbuf[32]; |
---|
| 890 | int idx; |
---|
| 891 | static unsigned char test[] = "NE*000 memory"; |
---|
| 892 | static unsigned short base[] = { |
---|
| 893 | #ifdef NE_SCAN |
---|
| 894 | NE_SCAN, |
---|
| 895 | #endif |
---|
| 896 | 0 }; |
---|
| 897 | /* if no addresses supplied, fall back on defaults */ |
---|
| 898 | if (probe_addrs == 0 || probe_addrs[0] == 0) |
---|
| 899 | probe_addrs = base; |
---|
| 900 | eth_bmem = 0; /* No shared memory */ |
---|
| 901 | for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) { |
---|
| 902 | eth_flags = FLAG_PIO; |
---|
| 903 | eth_asic_base = eth_nic_base + NE_ASIC_OFFSET; |
---|
| 904 | eth_memsize = MEM_16384; |
---|
| 905 | eth_tx_start = 32; |
---|
| 906 | eth_rx_start = 32 + D8390_TXBUF_SIZE; |
---|
| 907 | c = inb(eth_asic_base + NE_RESET); |
---|
| 908 | outb(c, eth_asic_base + NE_RESET); |
---|
| 909 | (void) inb(0x84); |
---|
| 910 | outb(D8390_COMMAND_STP | |
---|
| 911 | D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND); |
---|
| 912 | outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR); |
---|
| 913 | outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); |
---|
| 914 | outb(MEM_8192, eth_nic_base + D8390_P0_PSTART); |
---|
| 915 | outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP); |
---|
| 916 | #ifdef NS8390_FORCE_16BIT |
---|
| 917 | eth_flags |= FLAG_16BIT; /* force 16-bit mode */ |
---|
| 918 | #endif |
---|
| 919 | |
---|
| 920 | eth_pio_write( (unsigned char *) test, 8192, sizeof(test)); |
---|
| 921 | eth_pio_read(8192, testbuf, sizeof(test)); |
---|
| 922 | if (!memcmp(test, testbuf, sizeof(test))) |
---|
| 923 | break; |
---|
| 924 | eth_flags |= FLAG_16BIT; |
---|
| 925 | eth_memsize = MEM_32768; |
---|
| 926 | eth_tx_start = 64; |
---|
| 927 | eth_rx_start = 64 + D8390_TXBUF_SIZE; |
---|
| 928 | outb(D8390_DCR_WTS | |
---|
| 929 | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); |
---|
| 930 | outb(MEM_16384, eth_nic_base + D8390_P0_PSTART); |
---|
| 931 | outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP); |
---|
| 932 | eth_pio_write( (unsigned char *) test, 16384, sizeof(test)); |
---|
| 933 | eth_pio_read(16384, testbuf, sizeof(test)); |
---|
| 934 | if (!memcmp(testbuf, test, sizeof(test))) |
---|
| 935 | break; |
---|
| 936 | } |
---|
| 937 | if (eth_nic_base == 0) |
---|
| 938 | return (0); |
---|
| 939 | if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */ |
---|
| 940 | eth_flags |= FLAG_16BIT; |
---|
| 941 | eth_vendor = VENDOR_NOVELL; |
---|
| 942 | eth_pio_read(0, romdata, sizeof(romdata)); |
---|
| 943 | for (i=0; i<ETH_ALEN; i++) { |
---|
| 944 | nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)]; |
---|
| 945 | } |
---|
| 946 | nic->ioaddr = eth_nic_base; |
---|
| 947 | DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n", |
---|
| 948 | (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, |
---|
| 949 | eth_ntoa ( nic->node_addr ) ); |
---|
| 950 | } |
---|
| 951 | } |
---|
| 952 | #endif |
---|
| 953 | if (eth_vendor == VENDOR_NONE) |
---|
| 954 | return(0); |
---|
| 955 | if (eth_vendor != VENDOR_3COM) |
---|
| 956 | eth_rmem = eth_bmem; |
---|
| 957 | ns8390_reset(nic); |
---|
| 958 | nic->nic_op = &ns8390_operations; |
---|
| 959 | |
---|
| 960 | /* Based on PnP ISA map */ |
---|
| 961 | #ifdef INCLUDE_WD |
---|
| 962 | dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR); |
---|
| 963 | dev->devid.device_id = htons(0x812a); |
---|
| 964 | #endif |
---|
| 965 | #ifdef INCLUDE_3C503 |
---|
| 966 | dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR); |
---|
| 967 | dev->devid.device_id = htons(0x80f3); |
---|
| 968 | #endif |
---|
| 969 | #ifdef INCLUDE_NE |
---|
| 970 | dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR); |
---|
| 971 | dev->devid.device_id = htons(0x80d6); |
---|
| 972 | #endif |
---|
| 973 | return 1; |
---|
| 974 | } |
---|
| 975 | |
---|
| 976 | #ifdef INCLUDE_WD |
---|
| 977 | struct isa_driver wd_driver __isa_driver = { |
---|
| 978 | .type = NIC_DRIVER, |
---|
| 979 | .name = "WD", |
---|
| 980 | .probe = wd_probe, |
---|
| 981 | .ioaddrs = 0, |
---|
| 982 | }; |
---|
| 983 | ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)"); |
---|
| 984 | #endif |
---|
| 985 | |
---|
| 986 | #ifdef INCLUDE_3C503 |
---|
| 987 | struct isa_driver t503_driver __isa_driver = { |
---|
| 988 | .type = NIC_DRIVER, |
---|
| 989 | .name = "3C503", |
---|
| 990 | .probe = t503_probe, |
---|
| 991 | .ioaddrs = 0, |
---|
| 992 | }; |
---|
| 993 | ISA_ROM("3c503","3Com503, Etherlink II[/16]"); |
---|
| 994 | #endif |
---|
| 995 | |
---|
| 996 | #ifdef INCLUDE_NE |
---|
| 997 | struct isa_driver ne_driver __isa_driver = { |
---|
| 998 | .type = NIC_DRIVER, |
---|
| 999 | .name = "NE*000", |
---|
| 1000 | .probe = ne_probe, |
---|
| 1001 | .ioaddrs = 0, |
---|
| 1002 | }; |
---|
| 1003 | ISA_ROM("ne","NE1000/2000 and clones"); |
---|
| 1004 | #endif |
---|
| 1005 | |
---|
| 1006 | #ifdef INCLUDE_NS8390 |
---|
| 1007 | static struct pci_device_id nepci_nics[] = { |
---|
| 1008 | /* A few NE2000 PCI clones, list not exhaustive */ |
---|
| 1009 | PCI_ROM(0x10ec, 0x8029, "rtl8029", "Realtek 8029", 0), |
---|
| 1010 | PCI_ROM(0x1186, 0x0300, "dlink-528", "D-Link DE-528", 0), |
---|
| 1011 | PCI_ROM(0x1050, 0x0940, "winbond940", "Winbond NE2000-PCI", 0), /* Winbond 86C940 / 89C940 */ |
---|
| 1012 | PCI_ROM(0x1050, 0x5a5a, "winbond940f", "Winbond W89c940F", 0), /* Winbond 89C940F */ |
---|
| 1013 | PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0), |
---|
| 1014 | PCI_ROM(0x8e2e, 0x3000, "ktiet32p2", "KTI ET32P2", 0), |
---|
| 1015 | PCI_ROM(0x4a14, 0x5000, "nv5000sc", "NetVin NV5000SC", 0), |
---|
| 1016 | PCI_ROM(0x12c3, 0x0058, "holtek80232", "Holtek HT80232", 0), |
---|
| 1017 | PCI_ROM(0x12c3, 0x5598, "holtek80229", "Holtek HT80229", 0), |
---|
| 1018 | PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0), |
---|
| 1019 | PCI_ROM(0x1106, 0x0926, "via86c926", "Via 86c926", 0), |
---|
| 1020 | }; |
---|
| 1021 | |
---|
| 1022 | PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS ); |
---|
| 1023 | |
---|
| 1024 | DRIVER ( "NE2000/PCI", nic_driver, pci_driver, nepci_driver, |
---|
| 1025 | nepci_probe, ns8390_disable ); |
---|
| 1026 | |
---|
| 1027 | #endif /* INCLUDE_NS8390 */ |
---|
| 1028 | |
---|
| 1029 | #endif |
---|
| 1030 | |
---|
| 1031 | /* |
---|
| 1032 | * Local variables: |
---|
| 1033 | * c-basic-offset: 8 |
---|
| 1034 | * c-indent-level: 8 |
---|
| 1035 | * tab-width: 8 |
---|
| 1036 | * End: |
---|
| 1037 | */ |
---|