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