ne2000.c (29981B)
1 /* $Id: //depot/blt/srv/network/device/ne/ne2000.c#1 $ 2 ** 3 ** Copyright 1998 Brian J. Swetland 4 ** All rights reserved. 5 ** 6 ** Redistribution and use in source and binary forms, with or without 7 ** modification, are permitted provided that the following conditions 8 ** are met: 9 ** 1. Redistributions of source code must retain the above copyright 10 ** notice, this list of conditions, and the following disclaimer. 11 ** 2. Redistributions in binary form must reproduce the above copyright 12 ** notice, this list of conditions, and the following disclaimer in the 13 ** documentation and/or other materials provided with the distribution. 14 ** 3. The name of the author may not be used to endorse or promote products 15 ** derived from this software without specific prior written permission. 16 ** 17 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /* This file contains a network driver core for the NE2000 card. 29 // Use at your own risk! (C) Copyright 1997, 30 // Douglas Armstrong site@xnet.com drarmstr@uiuc.edu 10/11/97 31 // ... 32 // derived from National Semiconductor datasheets and application notes 33 // as well as the Linux driver by Donald Becker */ 34 35 /* History Log: 36 10-25-97 Setup under CVS drarmstr 37 10-27-97 Added alloc_buffer() and free_buffer() drarmstr 38 12-08-97 Finished scatter gather drarmstr 39 03-03-98 Minor bug / Output cleanup drarmstr 40 03-04-98 snic->tx_buf[] packet_buf -> packet_buf* drarmstr 41 03-04-98 added passback pointer to notify and snic drarmstr 42 */ 43 44 #ifndef NULL 45 #define NULL 0 46 #endif /* NULL */ 47 #include <i386/io.h> 48 #include "defs.h" 49 #include "ne2000.h" 50 #include "err.h" 51 //extern void kprintf(char *, ...); /* Make sure your OS has these...*/ 52 #define kprintf(f, a...) 53 //#define kprintf printf 54 extern void idle(); 55 extern unsigned long ticks; 56 /* replace with a better timeout method, like wait() */ 57 58 #ifdef XXX 59 static char *BLARGH = 0xB8000 + 160*23 + 152; 60 #define t(a) { BLARGH[0] = #a[0]; } 61 #define T(a) { BLARGH[2] = #a[0]; } 62 #else 63 #define t(a) {} 64 #define T(a) {} 65 #endif 66 67 /* we may have to change inb and outb to inb_p and outb_p. 68 // Note, none of this code is gauranteed to be reentrant. 69 70 // Note, don't create two nics to the same card and then try to use both 71 // of them. The results will be unpredictable. 72 73 // This violates IO resource manegment if your OS handles that, but it 74 // works for now. Make sure that the driver has privlige access to the 75 // mapped I/O space and the IRQ.*/ 76 static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 }; 77 78 /* internal procedure, don't call this directly.*/ 79 int nic_probe(int addr) { 80 uint regd; 81 uint state=inb(addr); /* save command state */ 82 83 if(inb(addr==0xff)) return ERRNOTFOUND; 84 85 outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); 86 regd=inb(addr + 0x0d); 87 outb(0xff, addr + 0x0d); 88 outb(NIC_DMA_DISABLE | NIC_PAGE0, addr); 89 inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/ 90 if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/ 91 outb(state,addr); /* restore command state*/ 92 outb(regd,addr + 0x0d); 93 return ERRNOTFOUND; } 94 95 return addr; /* network card detected at io addr;*/ 96 } 97 98 /* Detects for presence of NE2000 card. Will check given io addr that 99 // is passed to it as well as the default_ports array. Returns ERRNOTFOUND 100 // if no card is found, i/o address otherwise. This does conduct an ISA 101 // probe, so it's not always a good idea to run it. If you already have 102 // the information, then you can just use that with nic_init().*/ 103 int nic_detect(int given) { 104 int found; int f; 105 kprintf("NE2000: detecting card..."); 106 if(given) if((found=nic_probe(given))!=ERRNOTFOUND) { 107 kprintf("found at given:0x%x\n",given); 108 return found; } 109 110 /* probe for PCI clones here.... or not...*/ 111 112 for(f=0;default_ports[f]!='\0';f++) { 113 // perform resource manegment here 114 if((found=nic_probe(default_ports[f]))!=ERRNOTFOUND) { 115 kprintf("found at default:0x%x\n",default_ports[f]); 116 return found; } 117 } 118 kprintf("none found.\n"); 119 return ERRNOTFOUND; 120 } 121 122 /* This initializes the NE2000 card. If it turns out the card is not 123 // really a NE2000 after all then it will return ERRNOTFOUND, else NOERR 124 // It also dumps the prom into buffer prom for the upper layers.. 125 // Pass it a nic with a null iobase and it will initialize the structure for 126 // you, otherwise it will just reinitialize it. */ 127 int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) { 128 uint f; 129 kprintf("NE2000: reseting NIC card..."); 130 if(!nic->iobase) { 131 nic->iobase=addr; 132 nic_stat_clear(&nic->stat); 133 nic->pstart=0; nic->pstop=0; nic->wordlength=0; 134 nic->current_page=0; 135 nic->notify=NULL; 136 for(f=0;f<MAX_TX;f++) { 137 nic->tx_packet[f]= NULL; 138 /* nic->tx_packet[f].count=0; 139 nic->tx_packet[f].buf=NULL; 140 nic->tx_packet[f].page=0; */ 141 } 142 nic->last_tx=NULL; 143 nic->busy=0; 144 nic->sending=0; 145 } else { 146 if(!nic->iobase || nic->iobase!=addr) return ERR; 147 } 148 149 150 outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/ 151 while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) { 152 /* TODO insert timeout code here.*/ 153 } 154 kprintf("done.\n"); 155 outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/ 156 157 // Initialize registers 158 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/ 159 outb_p(DCR_DEFAULT, addr + DATACONFIGURATION); 160 outb_p(0x00, addr + REMOTEBYTECOUNT0); 161 outb_p(0x00, addr + REMOTEBYTECOUNT1); 162 outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ 163 outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ 164 outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/ 165 outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/ 166 167 nic->wordlength=nic_dump_prom(nic,prom); 168 if(prom[14]!=0x57 || prom[15]!=0x57) { 169 kprintf("NE2000: PROM signature does not match NE2000 0x57.\n"); 170 return ERRNOTFOUND; 171 } 172 kprintf("NE2000: PROM signature matches NE2000 0x57.\n"); 173 174 /* if the wordlength for the NE2000 card is 2 bytes, then 175 // we have to setup the DP8390 chipset to be the same or 176 // else all hell will break loose.*/ 177 if(nic->wordlength==2) { 178 outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION); 179 } 180 nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART; 181 nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP; 182 183 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); 184 outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/ 185 outb_p(nic->pstart + TXPAGES, addr + PAGESTART); 186 outb_p(nic->pstop - 1, addr + BOUNDARY); 187 outb_p(nic->pstop, addr + PAGESTOP); 188 outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ 189 outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ 190 nic->current_page=nic->pstart + TXPAGES; 191 192 /* put physical address in the registers */ 193 outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */ 194 if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f); 195 else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f); 196 kprintf("NE2000: Physical Address- "); 197 kprintf("%X:%X:%X:%X:%X:%X\n", 198 inb(addr+PAR0),inb(addr+PAR1),inb(addr+PAR2), 199 inb(addr+PAR3),inb(addr+PAR4),inb(addr+PAR5)); 200 201 /* setup multicast filter to accept all packets*/ 202 for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f); 203 204 outb_p(nic->pstart+TXPAGES, addr + CURRENT); 205 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */ 206 207 return NOERR; 208 } 209 210 /* This registers the function that will be called when a new packet 211 // comes in. */ 212 void nic_register_notify(snic *nic, 213 void (*newnotify)(void*,packet_data*), void *passback){ 214 nic->kore= passback; 215 nic->notify= newnotify; 216 } 217 218 /* start the NIC so it can actually recieve or transmit packets */ 219 void nic_start(snic *nic, int promiscuous) { 220 int iobase; 221 kprintf("NE2000: Starting NIC.\n"); 222 if(!nic || !nic->iobase) { 223 kprintf("NE2000: can't start a non-initialized card.\n"); 224 return; } 225 iobase=nic->iobase; 226 outb(0xff, iobase + INTERRUPTSTATUS); 227 outb(IMR_DEFAULT, iobase + INTERRUPTMASK); 228 outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 229 outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); 230 if(promiscuous) 231 outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION); 232 else 233 outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION); 234 235 /* The following is debugging code! */ 236 #ifdef SHIT 237 kprintf("NE2000: Trying to fire off an IRQ.\n"); 238 outb_p(0x50,iobase+INTERRUPTMASK); 239 outb_p(0x00,iobase+REMOTEBYTECOUNT0); 240 outb_p(0x00,iobase+REMOTEBYTECOUNT1); 241 outb_p(NIC_REM_READ | NIC_START,iobase); /* this should fire off */ 242 outb_p(IMR_DEFAULT,iobase+INTERRUPTMASK); /* an interrupt... */ 243 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 244 outb_p(0xff,iobase+INTERRUPTSTATUS); 245 #endif 246 /* End debugging code */ 247 } 248 249 /* stops the NIC */ 250 void nic_stop(snic *nic) { 251 unsigned char tmp_buffer[16]; 252 if(!nic || !nic->iobase) return; /* make sure card was initialized */ 253 nic_init(nic,nic->iobase,tmp_buffer,NULL); 254 } 255 256 void nic_isr(snic *nic) { 257 uint isr; /* Illinois Sreet Residence Hall */ 258 uint overload; 259 if(!nic || !nic->iobase) return; /* make sure card was initialized */ 260 outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); 261 overload=MAX_LOAD+1; 262 while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) { 263 if((--overload)<=0) break; 264 if(isr & ISR_OVW) nic_overrun(nic); 265 else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic); 266 if(isr & ISR_PTX) nic_tx(nic); 267 else if(isr & ISR_TXE) nic_tx_err(nic); 268 if(isr & ISR_CNT) nic_counters(nic); 269 if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS); 270 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); 271 } 272 if(isr) { 273 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); 274 if(!overload) { 275 kprintf("NE2000: Too many requests in ISR. ISR:%X MaxLoad:%X\n", 276 isr, MAX_LOAD); 277 outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear 278 } else { 279 kprintf("NE2000: Unhandeled interrupt, ISR:%X\n",isr); 280 outb_p(0xff, nic->iobase + INTERRUPTSTATUS); 281 // Ack it anyway 282 } 283 } 284 } 285 286 /* You should call this before you just read the stats directlly from the 287 // snic struct. This procedure updates the counters */ 288 nic_stat nic_get_stats(snic *nic) { 289 nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY); 290 nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY); 291 nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY); 292 return nic->stat; 293 } 294 295 void nic_stat_clear(nic_stat *that) { 296 that->rx_packets=0; 297 that->tx_buffered=0; that->tx_packets=0; 298 that->errors.frame_alignment=0; that->errors.crc=0; 299 that->errors.missed_packets=0; that->errors.rx=0; 300 that->errors.rx_size=0; that->errors.rx_dropped=0; 301 that->errors.rx_fifo=0; that->errors.rx_overruns=0; 302 that->errors.tx_collisions=0; 303 } 304 305 /* Since this could be called by more than one other device, it should 306 // be properly protected for reentrancy. We should put in a proper 307 // semaphore or something, look into this. 308 // NOTE: It is your responsibility to clean up the packet_buffer when you 309 // are done calling this. */ 310 /* TODO- Have it check how lonk a transmission is taking and attempt to 311 restart the card if it's too long. */ 312 int nic_send_packet(snic *nic, packet_buffer *buffer) { 313 uint timeout; uint f; int iobase; 314 /* kprintf("nic_send_packet()\n"); */ 315 if(!buffer) return ERRARG; 316 if(!buffer->count || !buffer->buf) return ERRARG; 317 if(!nic || !nic->iobase) return ERR; 318 iobase=nic->iobase; 319 320 t(A); 321 322 buffer->len=0; 323 for(f=0;f<buffer->count;f++) buffer->len+=buffer->buf[f].len; 324 if(buffer->len>MAX_LENGTH) return ERRTOOBIG; 325 326 t(B); 327 328 /* the following wait for anyother tasks that are calling 329 // nic_send_packet() right now. Note that this doesn't use 330 // an atomic semaphore, so something MAY leak through. */ 331 /* timeout=ticks+10; wait 10 ticks */ 332 timeout=ticks+100; 333 while(nic->busy && ticks<=timeout) idle(); 334 /* Replace this with a proper timeout thing that doesn't use the 335 // ticks method which will be diffrent on each OS. */ 336 t(C); 337 if(nic->busy) { 338 kprintf("NE2000: ERROR: Card stalled, timeout.\n"); 339 return ERRTIMEOUT; 340 } 341 nic->busy=1; /* mark as busy, replace with semaphore */ 342 343 t(D); 344 345 outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */ 346 t(E); 347 348 timeout=ticks+TIMEOUT_TX; 349 while(idle(), ticks<=timeout) for(f=0;f<MAX_TX;f++) { 350 if(!nic->tx_packet[f]) { 351 t(F); 352 353 /* nic->tx_packet[f]=*buffer;*/ 354 nic->tx_packet[f]=buffer; 355 nic->tx_packet[f]->page=nic->pstart + (f * MAX_PAGESPERPACKET); 356 /*output page */ 357 358 /* kprintf("NE2000: sending packet with count:%x on page:%X with buffer:%x\n", 359 buffer->count,buffer->page,buffer->buf); */ 360 t(>); 361 362 nic_block_output(nic,nic->tx_packet[f]); 363 364 t(<); 365 366 if(!nic->sending) { 367 nic->send=f; nic->sending=1; 368 /* now let's actually trigger the transmitter */ 369 t(I); 370 371 if(nic_send(nic,f)<0) { 372 nic->sending=0; 373 break; } 374 375 /* note, the nic_tx() interrupt will mark this 376 // tx_packet buffer as free again once it 377 // confirms that the packet was sent. */ 378 } 379 t(J); 380 381 nic->stat.tx_buffered++; 382 outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ 383 nic->busy=0; /* V() */ 384 t(K); 385 386 return NOERR; 387 } 388 } 389 390 t(L); 391 392 outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ 393 nic->busy=0; /* V() */ 394 kprintf("NE2000: ERROR: Transmitter stalled, card timeout.\n"); 395 if(f==MAX_TX) { 396 kprintf("NE2000: ERROR: There are no transmit buffers available. TX stalled.\n"); 397 return ERRTIMEOUT; 398 } 399 return ERR; 400 } 401 402 /* dumps the prom into a 16 byte buffer and returns the wordlength of 403 // the card. 404 // You should be able to make this procedure a wrapper of nic_block_input(). */ 405 int nic_dump_prom(snic *nic, unsigned char *prom) { 406 uint f; 407 int iobase=nic->iobase; 408 char wordlength=2; /* default wordlength of 2 */ 409 unsigned char dump[32]; 410 outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */ 411 outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */ 412 outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */ 413 outb_p(0x00, iobase + REMOTESTARTADDRESS1); 414 outb_p(NIC_REM_READ | NIC_START, iobase); 415 for(f=0;f<32;f+=2) { 416 dump[f]=inb_p(iobase + NE_DATA); 417 dump[f+1]=inb_p(iobase + NE_DATA); 418 if(dump[f]!=dump[f+1]) wordlength=1; 419 } 420 /* if wordlength is 2 bytes, then collapse prom to 16 bytes */ 421 for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)]; 422 /* kprintf("NE2000: prom dump - "); 423 for(f=0;f<LEN_PROM;f++) kprintf("%X",prom[f]); 424 kprintf("\n"); */ 425 426 return wordlength; 427 } 428 429 void nic_overrun(snic *nic) { 430 uint tx_status; int iobase=nic->iobase; 431 long starttime; uint resend=0; 432 kprintf("NE2000: Receive packet ring overrun!\n"); 433 if(!nic || !nic->iobase) return; 434 tx_status=inb_p(iobase) & NIC_TRANSMIT; 435 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase); 436 nic->stat.errors.rx_overruns++; 437 438 starttime=ticks; 439 kprintf("BEFORE\n"); 440 while(ticks-starttime<=10/*ticks to wait*/) idle(); 441 /* Arrgh! TODO: Replace this whole crappy code with a decent 442 // wait method. We need to wait at least 1.6ms as per National 443 // Semiconductor datasheets, but we should probablly wait a 444 // little more to be safe. */ 445 kprintf("AFTER\n"); 446 447 outb_p(0x00, iobase + REMOTEBYTECOUNT0); 448 outb_p(0x00, iobase + REMOTEBYTECOUNT1); 449 if(tx_status) { 450 uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) & 451 (ISR_PTX | ISR_TXE); 452 if(!tx_completed) resend=1; 453 } 454 455 outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION); 456 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 457 nic_rx(nic); /* cleanup RX ring */ 458 outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */ 459 460 outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); 461 if(resend) 462 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT, 463 iobase); 464 } 465 466 /* This is the procedure that markst the transmit buffer as available again */ 467 void nic_tx(snic *nic) { 468 uint f; int iobase=nic->iobase; 469 uint status; 470 /* kprintf("nic_tx()\n"); */ 471 if(!nic || !nic->iobase) return; 472 status=inb(iobase + TRANSMITSTATUS); 473 474 if(!nic->tx_packet[nic->send]) { 475 kprintf("NE2000: ERROR: Invalid transmison packet buffer.\n"); 476 return; 477 } 478 if(!nic->sending) kprintf("NE2000: ERROR: Invalid nic->sending value.\n"); 479 480 free_buffer(nic->tx_packet[nic->send]); 481 nic->tx_packet[nic->send]= NULL; 482 /* nic->tx_packet[nic->send].count=0; mark buffer as available */ 483 /* nic->tx_packet[nic->send].len=0; 484 nic->tx_packet[nic->send].page=0; */ 485 486 for(f=0;f<MAX_TX;f++) { 487 if(nic->tx_packet[f]) { 488 kprintf("NE2000: DEBUG: transmitting secondary buffer:%X\n",f); 489 nic->stat.tx_buffered++; 490 nic->send=f; nic->sending=1; 491 nic_send(nic,f); /* send a back-to-back buffer */ 492 break; 493 } 494 } 495 if(f==MAX_TX) nic->sending=0; 496 497 if(status & TSR_COL) nic->stat.errors.tx_collisions++; 498 if(status & TSR_PTX) nic->stat.tx_packets++; 499 else { 500 if(status & TSR_ABT) { 501 nic->stat.errors.tx_aborts++; 502 nic->stat.errors.tx_collisions+=16; } 503 if(status & TSR_CRS) nic->stat.errors.tx_carrier++; 504 if(status & TSR_FU) nic->stat.errors.tx_fifo++; 505 if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++; 506 if(status & TSR_OWC) nic->stat.errors.tx_window++; 507 } 508 509 outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */ 510 } 511 512 void nic_tx_err(snic *nic) { 513 unsigned char tsr; int iobase=nic->iobase; 514 if(!nic || !nic->iobase) return; 515 tsr=inb_p(nic->iobase); 516 kprintf("NE2000: ERROR: TX error: "); 517 if(tsr & TSR_ABT) kprintf("Too many collisions.\n"); 518 if(tsr & TSR_ND) kprintf("Not deffered.\n"); 519 if(tsr & TSR_CRS) kprintf("Carrier lost.\n"); 520 if(tsr & TSR_FU) kprintf("FIFO underrun.\n"); 521 if(tsr & TSR_CDH) kprintf("Heart attack!\n"); 522 523 outb_p(ISR_TXE, iobase + INTERRUPTSTATUS); 524 if(tsr & (TSR_ABT | TSR_FU)) { 525 kprintf("NE2000: DEBUG: Attempting to retransmit packet.\n"); 526 nic_tx(nic); 527 } 528 } 529 530 void nic_rx(snic *nic) { 531 uint packets=0; uint frame; uint rx_page; uint rx_offset; 532 uint len; uint next_pkt; uint numpages; 533 int iobase=nic->iobase; 534 buffer_header header; 535 if(!nic || !nic->iobase) return; 536 while(packets<MAX_RX) { 537 outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */ 538 rx_page=inb_p(iobase + CURRENT); /* get current page */ 539 outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase); 540 frame=inb(iobase + BOUNDARY)+1; 541 /* we add one becuase boundary is a page behind 542 // as pre NS notes to help in overflow problems */ 543 if(frame>=nic->pstop) frame=nic->pstart+TXPAGES; 544 /* circual buffer */ 545 546 if(frame != nic->current_page) { 547 kprintf("NE2000: ERROR: mismatched read page pointers!\n"); 548 kprintf("NE2000: NIC-Boundary:%x dev-current_page:%x\n", 549 frame, nic->current_page); } 550 551 /* kprintf("Boundary-%x Current-%x\n",frame-1,rx_page); */ 552 if(frame==rx_page) break; /* all frames read */ 553 554 rx_offset=frame << 8; /* current ptr in bytes(not pages) */ 555 556 nic_get_header(nic,frame,&header); 557 len=header.count - sizeof(buffer_header); 558 /* length of packet */ 559 next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */ 560 561 numpages=nic->pstop-(nic->pstart+TXPAGES); 562 if( (header.next!=next_pkt) 563 && (header.next!=next_pkt + 1) 564 && (header.next!=next_pkt - numpages) 565 && (header.next != next_pkt +1 - numpages)){ 566 kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n", 567 header.next,next_pkt,frame); 568 nic->current_page=frame; 569 outb(nic->current_page-1, iobase + BOUNDARY); 570 nic->stat.errors.rx++; 571 continue; 572 } 573 574 if(len<60 || len>1518) { 575 kprintf("NE2000: invalid packet size:%d\n",len); 576 nic->stat.errors.rx_size++; 577 } else if((header.status & 0x0f) == RSR_PRX) { 578 /* We have a good packet, so let's recieve it! */ 579 580 packet_data *newpacket=alloc_buffer_data(len); 581 if(!newpacket) { 582 kprintf("NE2000: ERROR: out of memory!\n"); 583 nic->stat.errors.rx_dropped++; 584 nic_block_input(nic,NULL,len,rx_offset+ 585 sizeof(buffer_header)); 586 } else { 587 nic_block_input(nic,newpacket->ptr,newpacket->len, 588 rx_offset+sizeof(buffer_header)); 589 /* read it */ 590 591 if(nic->notify) nic->notify(nic->kore,newpacket); 592 else free_buffer_data(newpacket); 593 /* NOTE: you are responsible for deleting this buffer. */ 594 595 nic->stat.rx_packets++; 596 } 597 } else { 598 kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n", 599 header.status,header.next,header.count); 600 if(header.status & RSR_FO) nic->stat.errors.rx_fifo++; 601 } 602 /* kprintf("frame:%x header.next:%x next_pkt:%x\n", 603 frame,header.next,next_pkt); */ 604 next_pkt=header.next; 605 606 if(next_pkt >= nic->pstop) { 607 kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n", 608 next_pkt); 609 next_pkt=nic->pstart+TXPAGES; 610 } 611 612 nic->current_page=next_pkt; 613 outb_p(next_pkt-1, iobase + BOUNDARY); 614 } 615 outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */ 616 } 617 618 void nic_counters(snic *nic) { 619 nic->stat.errors.frame_alignment+=inb_p(nic->iobase+FAE_TALLY); 620 nic->stat.errors.crc+=inb_p(nic->iobase+CRC_TALLY); 621 nic->stat.errors.missed_packets+=inb_p(nic->iobase+MISS_PKT_TALLY); 622 /* reading the counters on the DC8390 clears them. */ 623 outb_p(ISR_CNT, nic->iobase + INTERRUPTSTATUS); /* ackkowledge int */ 624 } 625 626 /* You should be able to make this procedure a wrapper of nic_block_input */ 627 void nic_get_header(snic *nic, uint page, buffer_header *header) { 628 int iobase=nic->iobase; uint f; 629 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 630 outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0); 631 outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */ 632 outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */ 633 outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */ 634 outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */ 635 636 if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++) 637 ((unsigned short *)header)[f]=inw(iobase+NE_DATA); 638 else for(f=0;f<sizeof(buffer_header);f++) 639 ((unsigned char *)header)[f]=inb(iobase+NE_DATA); 640 /* Do these need to be *_p variants??? */ 641 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ 642 } 643 644 int nic_send(snic *nic, uint buf) { 645 uint len= (nic->tx_packet[buf]->len<MIN_LENGTH) ? 646 MIN_LENGTH : nic->tx_packet[buf]->len; 647 /* kprintf("nic_send()\n"); */ 648 if(!nic->tx_packet[buf]) return ERR; /* this is bad */ 649 outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); 650 if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) { 651 kprintf("NE2000: ERROR: Transmitor busy.\n"); 652 free_buffer(nic->tx_packet[buf]); 653 nic->tx_packet[buf]= NULL; 654 /* nic->tx_packet[buf].count=0; mark as free again */ 655 return ERRTIMEOUT; } 656 outb_p(len & 0xff,nic->iobase+TRANSMITBYTECOUNT0); 657 outb_p(len >> 8,nic->iobase+TRANSMITBYTECOUNT1); 658 outb_p(nic->tx_packet[buf]->page,nic->iobase+TRANSMITPAGE); 659 outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase); 660 return NOERR; 661 } 662 663 void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) { 664 int iobase=nic->iobase; uint f; 665 uint xfers=len; 666 uint timeout=TIMEOUT_DMAMATCH; uint addr; 667 /* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset); */ 668 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 669 outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0); 670 outb_p(len >> 8, iobase + REMOTEBYTECOUNT1); 671 outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0); 672 outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1); 673 outb_p(NIC_REM_READ | NIC_START, iobase); 674 675 /* allow for no buffer */ 676 if(buf){ 677 if(nic->wordlength==2) { 678 for(f=0;f<(len>>1);f++) 679 ((unsigned short *)buf)[f]=inw(iobase+NE_DATA); 680 if(len&0x01) { 681 ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA); 682 xfers++; 683 } 684 } else { 685 for(f=0;f<len;f++) 686 ((unsigned char *)buf)[f]=inb(iobase+NE_DATA); 687 } 688 } else { 689 if(nic->wordlength==2) { 690 for(f=0;f<(len>>1);f++) 691 inw(iobase+NE_DATA); 692 if(len&0x01) { 693 inb(iobase+NE_DATA); 694 xfers++; 695 } 696 } else { 697 for(f=0;f<len;f++) 698 inb(iobase+NE_DATA); 699 } 700 } 701 /* Do these need to be *_p variants??? */ 702 703 /* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n"); */ 704 /* TODO: make this timeout a constant */ 705 for(f=0;f<timeout;f++) { 706 uint high=inb_p(iobase + REMOTESTARTADDRESS1); 707 uint low=inb_p(iobase + REMOTESTARTADDRESS0); 708 addr=(high<<8)+low; 709 if(((offset+xfers)&0xff)==low) break; 710 } 711 /* 712 if(f>=timeout) 713 kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", 714 offset+xfers, addr); HUH WHAT? BJS*/ 715 716 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ 717 } 718 719 /* Now supports scatter gather */ 720 void nic_block_output(snic *nic, packet_buffer *pkt) { 721 int iobase=nic->iobase; 722 int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int tmplen; 723 int bufidx, buflen; /* current packet_data in packet_buffer */ 724 void *bufptr; 725 char skip=0; /* Ask me about this if you have questions */ 726 uint deleteme=0; /* delete when done debugging */ 727 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 728 729 T(A); 730 731 for(f=0;f<pkt->count;f++) deleteme+=pkt->buf[f].len; 732 T(B); 733 734 if(pkt->len != deleteme) return; 735 736 if(pkt->len > MAX_LENGTH) return; 737 /* we should not have gotten this far... Paranoia check */ 738 739 /* this next part is to supposedly fix a "read-before-write" bug... */ 740 outb_p(0x42, iobase + REMOTEBYTECOUNT0); 741 outb_p(0x00, iobase + REMOTEBYTECOUNT1); 742 outb_p(0x42, iobase + REMOTESTARTADDRESS0); 743 outb_p(0x00, iobase + REMOTESTARTADDRESS1); 744 outb_p(NIC_REM_READ | NIC_START, iobase); 745 SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO; 746 747 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */ 748 T(C); 749 750 tmplen=(pkt->len < MIN_LENGTH) ? MIN_LENGTH : pkt->len; 751 outb_p(tmplen & 0xff, iobase + REMOTEBYTECOUNT0); 752 outb_p(tmplen >> 8, iobase + REMOTEBYTECOUNT1); 753 outb_p(0x00, iobase + REMOTESTARTADDRESS0); 754 outb_p(pkt->page, iobase + REMOTESTARTADDRESS1); 755 outb_p(NIC_REM_WRITE | NIC_START, iobase); 756 757 T(D); 758 759 /* go through each buffer and transfer it's contents */ 760 for(bufidx=pkt->count-1; bufidx >= 0; bufidx--) { 761 char odd; 762 buflen=pkt->buf[bufidx].len; /* only do derefrence once */ 763 bufptr=pkt->buf[bufidx].ptr; /* for performance :) */ 764 765 if(nic->wordlength==2) { 766 767 odd=(buflen & 0x01); 768 buflen>>=1; /* half the transfers */ 769 770 if(skip) ((uint)bufptr)--; /* korewa baka desu */ 771 772 for(f=skip;f<buflen;f++) { /* do we skip? */ 773 outw(((unsigned short *)bufptr)[f],iobase+NE_DATA); 774 tmplen -= 2; 775 } 776 777 /* output 16-bits of the last odd byte */ 778 skip=0; /* assume we don't skip */ 779 780 if(odd) { 781 short tmp=((unsigned char *)bufptr)[buflen<<1]; 782 /* get the byte from the next segment */ 783 if((bufidx-1)>=0) { 784 tmp |= ((unsigned char *) pkt->buf[bufidx-1].ptr)[0] << 8; 785 } 786 outw(tmp,iobase + NE_DATA); 787 tmplen -= 2; 788 skip=1; 789 } 790 } else 791 for(f=0;f<buflen;f++) { 792 outb(((unsigned char *)bufptr)[f],iobase+NE_DATA); 793 tmplen--; 794 } 795 } 796 T(E); 797 798 /* If it's too short, pad with 0s */ 799 if(tmplen > 0) { 800 T(F); 801 /* kprintf("Padding runt\n"); */ 802 if(nic->wordlength==2) { 803 for(f=0;f<tmplen/2;f++){ 804 outw(0x00,iobase + NE_DATA); 805 tmplen -= 2; 806 } 807 } 808 } 809 if (tmplen > 0) { 810 for(f=0;f<tmplen;f++) { 811 outb(0x00,iobase + NE_DATA); 812 tmplen--; 813 } 814 } 815 816 817 T(G); 818 #ifdef SHIT 819 if(nic->wordlength==2) { 820 for(w=0;w<(len>>1);w++) 821 outw(((unsigned short *)buf)[w],iobase+NE_DATA); 822 if(len & 0x01) { 823 short tmp=buf[len-1]; //so we can output a whole 16-bits 824 // if buf were on the end of something, we would die. 825 outw(tmp,iobase+NE_DATA); 826 } 827 } else for(f=0;f<len;f++) 828 outb(((unsigned char *)buf)[f],iobase+NE_DATA); 829 830 #endif 831 for(f=0;f<timeout;f++) { 832 uint high=inb_p(iobase + REMOTESTARTADDRESS1); 833 uint low=inb_p(iobase + REMOTESTARTADDRESS0); 834 addr=(high<<8)+low; 835 if(( (((pkt->page<<8)+(nic->wordlength==2 && (pkt->len&0x01))? 836 /* pkt->len+1:pkt->len+2))&0xff)==low)*/ 837 pkt->len+0:pkt->len+1))&0xff)==low) 838 break; 839 if( (pkt->len < MIN_LENGTH) && ( (((pkt->page<<8)+MIN_LENGTH) 840 & 0xff) == low) ) 841 break; 842 } 843 T(H); 844 #ifdef SHIT 845 if(f>=timeout) 846 kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", 847 ( (pkt->len >= MIN_LENGTH) ? 848 ((pkt->page<<8)+ 849 (nic->wordlength==2&&(pkt->len&0x01))? 850 pkt->len+0:pkt->len+1) 851 /* pkt->len+1:pkt->len+2)*/ 852 : ((pkt->page<<8)+MIN_LENGTH) ), 853 addr); 854 #endif 855 /* TODO Check ISR_RDC */ 856 857 T(I); 858 859 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ 860 }