1 /* 2 * rtl8139.c 3 * 4 * This file contains a ethernet device driver for Realtek rtl8139 based 5 * ethernet cards. 6 * 7 * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl> 8 * Changes: 9 * Aug 15, 2004 sync alarms replace watchdogs timers (Jorrit N. Herder) 10 * May 02, 2004 flag alarms replace micro_elapsed() (Jorrit N. Herder) 11 * 12 */ 13 14 #define VERBOSE 0 /* Verbose debugging output */ 15 #define RTL8139_FKEY 0 /* Use function key to dump RTL8139 status */ 16 17 #include "rtl8139.h" 18 19 static re_t re_state; 20 21 static int re_instance; 22 23 static unsigned my_inb(u16_t port) { 24 u32_t value; 25 int s; 26 if ((s=sys_inb(port, &value)) !=OK) 27 printf("RTL8139: warning, sys_inb failed: %d\n", s); 28 return value; 29 } 30 static unsigned my_inw(u16_t port) { 31 u32_t value; 32 int s; 33 if ((s=sys_inw(port, &value)) !=OK) 34 printf("RTL8139: warning, sys_inw failed: %d\n", s); 35 return value; 36 } 37 static unsigned my_inl(u16_t port) { 38 u32_t value; 39 int s; 40 if ((s=sys_inl(port, &value)) !=OK) 41 printf("RTL8139: warning, sys_inl failed: %d\n", s); 42 return value; 43 } 44 #define rl_inb(port, offset) (my_inb((port) + (offset))) 45 #define rl_inw(port, offset) (my_inw((port) + (offset))) 46 #define rl_inl(port, offset) (my_inl((port) + (offset))) 47 48 static void my_outb(u16_t port, u8_t value) { 49 int s; 50 if ((s=sys_outb(port, value)) !=OK) 51 printf("RTL8139: warning, sys_outb failed: %d\n", s); 52 } 53 static void my_outw(u16_t port, u16_t value) { 54 int s; 55 if ((s=sys_outw(port, value)) !=OK) 56 printf("RTL8139: warning, sys_outw failed: %d\n", s); 57 } 58 static void my_outl(u16_t port, u32_t value) { 59 int s; 60 if ((s=sys_outl(port, value)) !=OK) 61 printf("RTL8139: warning, sys_outl failed: %d\n", s); 62 } 63 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value))) 64 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value))) 65 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value))) 66 67 static int rl_init(unsigned int instance, ether_addr_t *addr); 68 static int rl_probe(re_t *rep, unsigned int skip); 69 static void rl_init_buf(re_t *rep); 70 static void rl_init_hw(re_t *rep, ether_addr_t *addr); 71 static void rl_reset_hw(re_t *rep); 72 static void rl_confaddr(re_t *rep, ether_addr_t *addr); 73 static void rl_stop(void); 74 static void rl_rec_mode(re_t *rep); 75 static void rl_mode(unsigned int mode); 76 static ssize_t rl_recv(struct netdriver_data *data, size_t max); 77 static int rl_send(struct netdriver_data *data, size_t size); 78 static void rl_intr(unsigned int mask); 79 static void rl_check_ints(re_t *rep); 80 static void rl_report_link(re_t *rep); 81 #if VERBOSE 82 static void mii_print_techab(u16_t techab); 83 static void mii_print_stat_speed(u16_t stat, u16_t extstat); 84 #endif 85 static void rl_clear_rx(re_t *rep); 86 static void rl_do_reset(re_t *rep); 87 static void rl_stat(eth_stat_t *stat); 88 static void rl_other(const message *m_ptr, int ipc_status); 89 static void rl_dump(void); 90 #if 0 91 static void dump_phy(re_t *rep); 92 #endif 93 static int rl_handler(re_t *rep); 94 static void rl_alarm(clock_t stamp); 95 static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int 96 pci_dev, int pci_func); 97 98 static const struct netdriver rl_table = { 99 .ndr_init = rl_init, 100 .ndr_stop = rl_stop, 101 .ndr_mode = rl_mode, 102 .ndr_recv = rl_recv, 103 .ndr_send = rl_send, 104 .ndr_stat = rl_stat, 105 .ndr_intr = rl_intr, 106 .ndr_alarm = rl_alarm, 107 .ndr_other = rl_other, 108 }; 109 110 /*===========================================================================* 111 * main * 112 *===========================================================================*/ 113 int main(int argc, char *argv[]) 114 { 115 116 env_setargs(argc, argv); 117 118 netdriver_task(&rl_table); 119 120 return 0; 121 } 122 123 /*===========================================================================* 124 * rl_intr * 125 *===========================================================================*/ 126 static void rl_intr(unsigned int __unused mask) 127 { 128 re_t *rep; 129 int s; 130 131 rep = &re_state; 132 133 /* Run interrupt handler at driver level. */ 134 rl_handler(rep); 135 136 /* Reenable interrupts for this hook. */ 137 if ((s = sys_irqenable(&rep->re_hook_id)) != OK) 138 printf("RTL8139: error, couldn't enable interrupts: %d\n", s); 139 140 /* Perform tasks based on the flagged conditions. */ 141 rl_check_ints(rep); 142 } 143 144 /*===========================================================================* 145 * rl_other * 146 *===========================================================================*/ 147 static void rl_other(const message *m_ptr, int ipc_status) 148 { 149 if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) 150 rl_dump(); 151 } 152 153 /*===========================================================================* 154 * rl_stop * 155 *===========================================================================*/ 156 static void rl_stop(void) 157 { 158 re_t *rep; 159 160 rep = &re_state; 161 162 rl_outb(rep->re_base_port, RL_CR, 0); 163 } 164 165 /*===========================================================================* 166 * rl_dump * 167 *===========================================================================*/ 168 static void rl_dump(void) 169 { 170 re_t *rep; 171 172 rep= &re_state; 173 174 printf("\n"); 175 printf("Realtek RTL 8139 statistics of instance %d:\n", re_instance); 176 177 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr); 178 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr); 179 printf("OVW :%8ld\n", rep->re_stat.ets_OVW); 180 181 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr); 182 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll); 183 printf("missedP :%8ld\n", rep->re_stat.ets_missedP); 184 185 printf("packetR :%8ld\t", rep->re_stat.ets_packetR); 186 printf("packetT :%8ld\t", rep->re_stat.ets_packetT); 187 printf("transDef :%8ld\n", rep->re_stat.ets_transDef); 188 189 printf("collision :%8ld\t", rep->re_stat.ets_collision); 190 printf("transAb :%8ld\t", rep->re_stat.ets_transAb); 191 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense); 192 193 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder); 194 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver); 195 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat); 196 197 printf("OWC :%8ld\t", rep->re_stat.ets_OWC); 198 199 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", 200 rl_inw(rep->re_base_port, RL_TSAD), 201 rl_inl(rep->re_base_port, RL_TSD0+0*4), 202 rl_inl(rep->re_base_port, RL_TSD0+1*4), 203 rl_inl(rep->re_base_port, RL_TSD0+2*4), 204 rl_inl(rep->re_base_port, RL_TSD0+3*4)); 205 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n", 206 rep->re_tx_head, rep->re_tx_tail, 207 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, 208 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); 209 } 210 211 /*===========================================================================* 212 * rl_mode * 213 *===========================================================================*/ 214 static void rl_mode(unsigned int mode) 215 { 216 re_t *rep; 217 218 rep= &re_state; 219 220 rep->re_mode = mode; 221 222 rl_rec_mode(rep); 223 } 224 225 /*===========================================================================* 226 * rl_init * 227 *===========================================================================*/ 228 static int rl_init(unsigned int instance, ether_addr_t *addr) 229 { 230 /* Initialize the rtl8139 driver. */ 231 re_t *rep; 232 #if RTL8139_FKEY 233 int r, fkeys, sfkeys; 234 #endif 235 236 /* Initialize driver state. */ 237 rep= &re_state; 238 memset(rep, 0, sizeof(*rep)); 239 240 rep->re_link_up= -1; /* Unknown */ 241 rep->re_ertxth= RL_TSD_ERTXTH_8; 242 strlcpy(rep->re_name, "rtl8139#0", sizeof(rep->re_name)); 243 rep->re_name[8] += instance; 244 245 re_instance = instance; 246 247 /* Try to find a matching device. */ 248 if (!rl_probe(rep, instance)) 249 return ENXIO; 250 251 /* Claim buffer memory. */ 252 rl_init_buf(rep); 253 254 /* Initialize the device we found. */ 255 rl_init_hw(rep, addr); 256 257 #if VERBOSE 258 /* Report initial link status. */ 259 rl_report_link(rep); 260 #endif 261 262 /* Use a synchronous alarm instead of a watchdog timer. */ 263 sys_setalarm(sys_hz(), 0); 264 265 #if RTL8139_FKEY 266 /* Observe some function key for debug dumps. */ 267 fkeys = sfkeys = 0; bit_set(sfkeys, 9); 268 if ((r = fkey_map(&fkeys, &sfkeys)) != OK) 269 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r); 270 #endif 271 272 return OK; 273 } 274 275 /*===========================================================================* 276 * rl_probe * 277 *===========================================================================*/ 278 static int rl_probe(re_t *rep, unsigned int skip) 279 { 280 int r, devind; 281 u16_t cr, vid, did; 282 u32_t bar; 283 u8_t ilr; 284 #if VERBOSE 285 char *dname; 286 #endif 287 288 pci_init(); 289 290 r= pci_first_dev(&devind, &vid, &did); 291 if (r == 0) 292 return 0; 293 294 while (skip--) 295 { 296 r= pci_next_dev(&devind, &vid, &did); 297 if (!r) 298 return 0; 299 } 300 301 #if VERBOSE /* stay silent at startup, can always get status later */ 302 dname= pci_dev_name(vid, did); 303 if (!dname) 304 dname= "unknown device"; 305 printf("%s: ", rep->re_name); 306 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind)); 307 #endif 308 pci_reserve(devind); 309 310 /* Enable bus mastering if necessary. */ 311 cr = pci_attr_r16(devind, PCI_CR); 312 /* printf("cr = 0x%x\n", cr); */ 313 if (!(cr & PCI_CR_MAST_EN)) 314 pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); 315 316 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; 317 if (bar < 0x400) { 318 panic("base address is not properly configured"); 319 } 320 rep->re_base_port= bar; 321 322 ilr= pci_attr_r8(devind, PCI_ILR); 323 rep->re_irq= ilr; 324 #if VERBOSE 325 printf("%s: using I/O address 0x%lx, IRQ %d\n", 326 rep->re_name, (unsigned long)bar, ilr); 327 #endif 328 329 return TRUE; 330 } 331 332 /*===========================================================================* 333 * rl_init_buf * 334 *===========================================================================*/ 335 static void rl_init_buf(re_t *rep) 336 { 337 size_t rx_bufsize, tx_bufsize, tot_bufsize; 338 phys_bytes buf; 339 char *mallocbuf; 340 int i, off; 341 342 /* Allocate receive and transmit buffers */ 343 tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED; 344 if (tx_bufsize % 4) 345 tx_bufsize += 4-(tx_bufsize % 4); /* Align */ 346 rx_bufsize= RX_BUFSIZE; 347 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize; 348 349 if (tot_bufsize % 4096) 350 tot_bufsize += 4096-(tot_bufsize % 4096); 351 352 #define BUF_ALIGNMENT (64*1024) 353 354 if (!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf))) 355 panic("Couldn't allocate kernel buffer"); 356 357 /* click-align mallocced buffer. this is what we used to get 358 * from kmalloc() too. 359 */ 360 if((off = buf % BUF_ALIGNMENT)) { 361 mallocbuf += BUF_ALIGNMENT - off; 362 buf += BUF_ALIGNMENT - off; 363 } 364 365 tell_iommu((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0); 366 367 for (i= 0; i<N_TX_BUF; i++) 368 { 369 rep->re_tx[i].ret_buf= buf; 370 rep->re_tx[i].v_ret_buf= mallocbuf; 371 buf += tx_bufsize; 372 mallocbuf += tx_bufsize; 373 } 374 rep->re_rx_buf= buf; 375 rep->v_re_rx_buf= mallocbuf; 376 } 377 378 /*===========================================================================* 379 * rl_init_hw * 380 *===========================================================================*/ 381 static void rl_init_hw(re_t *rep, ether_addr_t *addr) 382 { 383 #if VERBOSE 384 int i; 385 #endif 386 int s; 387 388 /* Set the interrupt handler. The policy is to only send HARD_INT 389 * notifications. Don't reenable interrupts automatically. The id 390 * that is passed back is the interrupt line number. 391 */ 392 rep->re_hook_id = rep->re_irq; 393 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK) 394 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s); 395 396 rl_reset_hw(rep); 397 398 if ((s=sys_irqenable(&rep->re_hook_id)) != OK) 399 printf("RTL8139: error, couldn't enable interrupts: %d\n", s); 400 401 #if VERBOSE /* stay silent during startup, can always get status later */ 402 if (rep->re_model) { 403 printf("%s: model %s\n", rep->re_name, rep->re_model); 404 } else 405 { 406 printf("%s: unknown model 0x%08x\n", 407 rep->re_name, 408 rl_inl(rep->re_base_port, RL_TCR) & 409 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM)); 410 } 411 #endif 412 413 rl_confaddr(rep, addr); 414 415 #if VERBOSE 416 printf("%s: Ethernet address ", rep->re_name); 417 for (i= 0; i < 6; i++) 418 printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); 419 #endif 420 } 421 422 /*===========================================================================* 423 * rl_reset_hw * 424 *===========================================================================*/ 425 static void rl_reset_hw(re_t *rep) 426 { 427 port_t port; 428 u32_t t; 429 phys_bytes bus_buf; 430 int i; 431 432 port= rep->re_base_port; 433 434 #if 0 435 /* Reset the PHY */ 436 rl_outb(port, RL_BMCR, MII_CTRL_RST); 437 SPIN_UNTIL(!(rl_inb(port, RL_BMCR) & MII_CTRL_RST), 1000000); 438 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST) 439 panic("reset PHY failed to complete"); 440 #endif 441 442 /* Reset the device */ 443 #if VERBOSE 444 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n", 445 port, rl_inb(port, RL_CR)); 446 #endif 447 rl_outb(port, RL_CR, RL_CR_RST); 448 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000); 449 #if VERBOSE 450 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n", 451 port, rl_inb(port, RL_CR)); 452 #endif 453 if (rl_inb(port, RL_CR) & RL_CR_RST) 454 printf("rtl8139: reset failed to complete"); 455 456 t= rl_inl(port, RL_TCR); 457 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM)) 458 { 459 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break; 460 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break; 461 case RL_TCR_HWVER_RTL8139AG: 462 rep->re_model= "RTL8139A-G / RTL8139C"; 463 break; 464 case RL_TCR_HWVER_RTL8139B: 465 rep->re_model= "RTL8139B / RTL8130"; 466 break; 467 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break; 468 case RL_TCR_HWVER_RTL8100B: 469 rep->re_model= "RTL8100B/RTL8139D"; 470 break; 471 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break; 472 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break; 473 default: 474 rep->re_model= NULL; 475 break; 476 } 477 478 #if 0 479 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID)); 480 #endif 481 482 /* Intialize Rx */ 483 484 /* Should init multicast mask */ 485 #if 0 486 08-0f R/W MAR[0-7] multicast 487 #endif 488 bus_buf= vm_1phys2bus(rep->re_rx_buf); 489 rl_outl(port, RL_RBSTART, bus_buf); 490 491 /* Initialize Tx */ 492 for (i= 0; i<N_TX_BUF; i++) 493 { 494 rep->re_tx[i].ret_busy= FALSE; 495 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf); 496 rl_outl(port, RL_TSAD0+i*4, bus_buf); 497 t= rl_inl(port, RL_TSD0+i*4); 498 assert(t & RL_TSD_OWN); 499 } 500 501 rep->re_tx_busy = 0; 502 503 #if 0 504 dump_phy(rep); 505 #endif 506 507 t= rl_inw(port, RL_IMR); 508 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT | 509 RL_IMR_LENCHG)); 510 511 t= rl_inw(port, RL_IMR); 512 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN | 513 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK)); 514 515 t= rl_inw(port, RL_IMR); 516 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK)); 517 518 t= rl_inb(port, RL_CR); 519 rl_outb(port, RL_CR, t | RL_CR_RE); 520 521 t= rl_inb(port, RL_CR); 522 rl_outb(port, RL_CR, t | RL_CR_TE); 523 524 rl_outl(port, RL_RCR, RX_BUFBITS); 525 526 t= rl_inl(port, RL_TCR); 527 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD); 528 } 529 530 /*===========================================================================* 531 * rl_confaddr * 532 *===========================================================================*/ 533 static void rl_confaddr(re_t *rep, ether_addr_t *addr) 534 { 535 static char eakey[]= RL_ENVVAR "#_EA"; 536 static char eafmt[]= "x:x:x:x:x:x"; 537 538 int i; 539 port_t port; 540 u32_t w; 541 long v; 542 543 /* User defined ethernet address? */ 544 eakey[sizeof(RL_ENVVAR)-1]= '0' + re_instance; 545 546 port= rep->re_base_port; 547 548 for (i= 0; i < 6; i++) 549 { 550 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) 551 break; 552 addr->ea_addr[i]= v; 553 } 554 555 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ 556 557 /* Should update ethernet address in hardware */ 558 if (i == 6) 559 { 560 port= rep->re_base_port; 561 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG); 562 w= 0; 563 for (i= 0; i<4; i++) 564 w |= (addr->ea_addr[i] << (i*8)); 565 rl_outl(port, RL_IDR, w); 566 w= 0; 567 for (i= 4; i<6; i++) 568 w |= (addr->ea_addr[i] << ((i-4)*8)); 569 rl_outl(port, RL_IDR+4, w); 570 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL); 571 } 572 573 /* Get ethernet address */ 574 for (i= 0; i<6; i++) 575 addr->ea_addr[i]= rl_inb(port, RL_IDR+i); 576 } 577 578 /*===========================================================================* 579 * rl_rec_mode * 580 *===========================================================================*/ 581 static void rl_rec_mode(re_t *rep) 582 { 583 port_t port; 584 u32_t rcr; 585 586 port= rep->re_base_port; 587 rcr= rl_inl(port, RL_RCR); 588 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP); 589 if (rep->re_mode & NDEV_PROMISC) 590 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP; 591 if (rep->re_mode & NDEV_BROAD) 592 rcr |= RL_RCR_AB; 593 if (rep->re_mode & NDEV_MULTI) 594 rcr |= RL_RCR_AM; 595 rcr |= RL_RCR_APM; 596 597 rl_outl(port, RL_RCR, rcr); 598 } 599 600 /*===========================================================================* 601 * rl_recv * 602 *===========================================================================*/ 603 static ssize_t rl_recv(struct netdriver_data *data, size_t max) 604 { 605 int o, s; 606 port_t port; 607 unsigned amount, totlen, packlen; 608 u16_t d_start, d_end; 609 u32_t l, rxstat; 610 re_t *rep; 611 612 rep= &re_state; 613 614 if (rep->re_clear_rx) 615 return SUSPEND; /* Buffer overflow */ 616 617 port= rep->re_base_port; 618 619 if (rl_inb(port, RL_CR) & RL_CR_BUFE) 620 { 621 /* Receive buffer is empty, suspend */ 622 return SUSPEND; 623 } 624 625 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF; 626 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE; 627 628 #if RX_BUFSIZE <= USHRT_MAX 629 if (d_start >= RX_BUFSIZE) 630 { 631 printf("rl_recv: strange value in RL_CAPR: 0x%x\n", 632 rl_inw(port, RL_CAPR)); 633 d_start %= RX_BUFSIZE; 634 } 635 #endif 636 637 if (d_end > d_start) 638 amount= d_end-d_start; 639 else 640 amount= d_end+RX_BUFSIZE - d_start; 641 642 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start); 643 644 /* Should convert from little endian to host byte order */ 645 646 if (!(rxstat & RL_RXS_ROK)) 647 { 648 printf("rxstat = 0x%08x\n", rxstat); 649 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n", 650 d_start, d_end, rxstat); 651 panic("received packet not OK"); 652 } 653 totlen= (rxstat >> RL_RXS_LEN_S); 654 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE) 655 { 656 /* Someting went wrong */ 657 printf( 658 "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n", 659 totlen, rxstat, d_start); 660 printf( 661 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n", 662 d_start, d_end, totlen, rxstat); 663 panic(NULL); 664 } 665 666 #if 0 667 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n", 668 d_start, d_end, totlen, rxstat); 669 #endif 670 671 if (totlen+4 > amount) 672 { 673 printf("rl_recv: packet not yet ready\n"); 674 return SUSPEND; 675 } 676 677 /* Should subtract the CRC */ 678 packlen = MIN(totlen - ETH_CRC_SIZE, max); 679 680 /* Copy out the data. The packet may wrap in the receive buffer. */ 681 o = (d_start+4) % RX_BUFSIZE; 682 s = MIN(RX_BUFSIZE - o, packlen); 683 684 netdriver_copyout(data, 0, rep->v_re_rx_buf + o, s); 685 if (s < packlen) 686 netdriver_copyout(data, s, rep->v_re_rx_buf, packlen - s); 687 688 rep->re_stat.ets_packetR++; 689 690 /* Avoid overflow in 16-bit computations */ 691 l= d_start; 692 l += totlen+4; 693 l= (l+3) & ~3; /* align */ 694 if (l >= RX_BUFSIZE) 695 { 696 l -= RX_BUFSIZE; 697 assert(l < RX_BUFSIZE); 698 } 699 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF); 700 701 return packlen; 702 } 703 704 /*===========================================================================* 705 * rl_send * 706 *===========================================================================*/ 707 static int rl_send(struct netdriver_data *data, size_t size) 708 { 709 int tx_head; 710 re_t *rep; 711 712 rep= &re_state; 713 714 tx_head= rep->re_tx_head; 715 if (rep->re_tx[tx_head].ret_busy) 716 return SUSPEND; 717 718 netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size); 719 720 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, rep->re_ertxth | size); 721 rep->re_tx[tx_head].ret_busy= TRUE; 722 rep->re_tx_busy++; 723 724 if (++tx_head == N_TX_BUF) 725 tx_head= 0; 726 assert(tx_head < RL_N_TX); 727 rep->re_tx_head= tx_head; 728 729 return OK; 730 } 731 732 /*===========================================================================* 733 * rl_check_ints * 734 *===========================================================================*/ 735 static void rl_check_ints(re_t *rep) 736 { 737 #if 0 738 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3] 739 31 R CRS Carrier Sense Lost 740 30 R TABT Transmit Abort 741 29 R OWC Out of Window Collision 742 27-24 R NCC[3-0] Number of Collision Count 743 23-22 reserved 744 21-16 R/W ERTXH[5-0] Early Tx Threshold 745 15 R TOK Transmit OK 746 14 R TUN Transmit FIFO Underrun 747 13 R/W OWN OWN 748 12-0 R/W SIZE Descriptor Size 749 3e-3f R/W ISR Interrupt Status Register 750 6 R/W FOVW Fx FIFO Overflow Interrupt 751 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt 752 3 R/W TER Transmit Error Interrupt 753 2 R/W TOK Transmit OK Interrupt 754 3e-3f R/W ISR Interrupt Status Register 755 15 R/W SERR System Error Interrupt 756 14 R/W TimeOut Time Out Interrupt 757 13 R/W LenChg Cable Length Change Interrupt 758 3e-3f R/W ISR Interrupt Status Register 759 4 R/W RXOVW Rx Buffer Overflow Interrupt 760 1 R/W RER Receive Error Interrupt 761 0 R/W ROK Receive OK Interrupt 762 4c-4f R/W MPC Missed Packet Counter 763 60-61 R TSAD Transmit Status of All Descriptors 764 15-12 R TOK[3-0] TOK bit of Descriptor [3-0] 765 11-8 R TUN[3-0] TUN bit of Descriptor [3-0] 766 7-4 R TABT[3-0] TABT bit of Descriptor [3-0] 767 3-0 R OWN[3-0] OWN bit of Descriptor [3-0] 768 6c-6d R DIS Disconnect Counter 769 15-0 R DCNT Disconnect Counter 770 6e-6f R FCSC False Carrier Sense Counter 771 15-0 R FCSCNT False Carrier event counter 772 72-73 R REC RX_ER Counter 773 15-0 R RXERCNT Received packet counter 774 #endif 775 776 if (!rep->re_got_int) 777 return; 778 rep->re_got_int = FALSE; 779 780 netdriver_recv(); 781 782 if (rep->re_clear_rx) 783 rl_clear_rx(rep); 784 785 if (rep->re_need_reset) 786 rl_do_reset(rep); 787 788 if (rep->re_send_int) { 789 rep->re_send_int = FALSE; 790 791 netdriver_send(); 792 } 793 794 if (rep->re_report_link) { 795 rep->re_report_link = FALSE; 796 797 rl_report_link(rep); 798 } 799 } 800 801 /*===========================================================================* 802 * rl_report_link * 803 *===========================================================================*/ 804 static void rl_report_link(re_t *rep) 805 { 806 port_t port; 807 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat; 808 u8_t msr; 809 int f, link_up; 810 811 port= rep->re_base_port; 812 msr= rl_inb(port, RL_MSR); 813 link_up= !(msr & RL_MSR_LINKB); 814 rep->re_link_up= link_up; 815 if (!link_up) 816 { 817 printf("%s: link down\n", rep->re_name); 818 return; 819 } 820 821 mii_ctrl= rl_inw(port, RL_BMCR); 822 mii_status= rl_inw(port, RL_BMSR); 823 mii_ana= rl_inw(port, RL_ANAR); 824 mii_anlpa= rl_inw(port, RL_ANLPAR); 825 mii_ane= rl_inw(port, RL_ANER); 826 mii_extstat= 0; 827 828 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO)) 829 { 830 printf("%s: PHY: ", rep->re_name); 831 f= 1; 832 if (mii_ctrl & MII_CTRL_LB) 833 { 834 printf("loopback mode"); 835 f= 0; 836 } 837 if (mii_ctrl & MII_CTRL_PD) 838 { 839 if (!f) printf(", "); 840 f= 0; 841 printf("powered down"); 842 } 843 if (mii_ctrl & MII_CTRL_ISO) 844 { 845 if (!f) printf(", "); 846 f= 0; 847 printf("isolated"); 848 } 849 printf("\n"); 850 return; 851 } 852 if (!(mii_ctrl & MII_CTRL_ANE)) 853 { 854 printf("%s: manual config: ", rep->re_name); 855 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB)) 856 { 857 case MII_CTRL_SP_10: printf("10 Mbps"); break; 858 case MII_CTRL_SP_100: printf("100 Mbps"); break; 859 case MII_CTRL_SP_1000: printf("1000 Mbps"); break; 860 case MII_CTRL_SP_RES: printf("reserved speed"); break; 861 } 862 if (mii_ctrl & MII_CTRL_DM) 863 printf(", full duplex"); 864 else 865 printf(", half duplex"); 866 printf("\n"); 867 return; 868 } 869 870 #if VERBOSE 871 printf("%s: ", rep->re_name); 872 mii_print_stat_speed(mii_status, mii_extstat); 873 printf("\n"); 874 875 if (!(mii_status & MII_STATUS_ANC)) 876 printf("%s: auto-negotiation not complete\n", rep->re_name); 877 if (mii_status & MII_STATUS_RF) 878 printf("%s: remote fault detected\n", rep->re_name); 879 if (!(mii_status & MII_STATUS_ANA)) 880 { 881 printf("%s: local PHY has no auto-negotiation ability\n", 882 rep->re_name); 883 } 884 if (!(mii_status & MII_STATUS_LS)) 885 printf("%s: link down\n", rep->re_name); 886 if (mii_status & MII_STATUS_JD) 887 printf("%s: jabber condition detected\n", rep->re_name); 888 if (!(mii_status & MII_STATUS_EC)) 889 { 890 printf("%s: no extended register set\n", rep->re_name); 891 goto resspeed; 892 } 893 if (!(mii_status & MII_STATUS_ANC)) 894 goto resspeed; 895 896 printf("%s: local cap.: ", rep->re_name); 897 mii_print_techab(mii_ana); 898 printf("\n"); 899 900 if (mii_ane & MII_ANE_PDF) 901 printf("%s: parallel detection fault\n", rep->re_name); 902 if (!(mii_ane & MII_ANE_LPANA)) 903 { 904 printf("%s: link-partner does not support auto-negotiation\n", 905 rep->re_name); 906 goto resspeed; 907 } 908 909 printf("%s: remote cap.: ", rep->re_name); 910 mii_print_techab(mii_anlpa); 911 printf("\n"); 912 resspeed: 913 #endif 914 915 printf("%s: ", rep->re_name); 916 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100); 917 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half")); 918 919 } 920 921 #if VERBOSE 922 static void mii_print_techab(u16_t techab) 923 { 924 int fs, ft; 925 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3) 926 { 927 printf("strange selector 0x%x, value 0x%x", 928 techab & MII_ANA_SEL_M, 929 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S); 930 return; 931 } 932 fs= 1; 933 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD)) 934 { 935 printf("100 Mbps: "); 936 fs= 0; 937 ft= 1; 938 if (techab & MII_ANA_100T4) 939 { 940 printf("T4"); 941 ft= 0; 942 } 943 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD)) 944 { 945 if (!ft) 946 printf(", "); 947 ft= 0; 948 printf("TX-"); 949 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD)) 950 { 951 case MII_ANA_100TXFD: printf("FD"); break; 952 case MII_ANA_100TXHD: printf("HD"); break; 953 default: printf("FD/HD"); break; 954 } 955 } 956 } 957 if (techab & (MII_ANA_10TFD | MII_ANA_10THD)) 958 { 959 if (!fs) 960 printf(", "); 961 printf("10 Mbps: "); 962 fs= 0; 963 printf("T-"); 964 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD)) 965 { 966 case MII_ANA_10TFD: printf("FD"); break; 967 case MII_ANA_10THD: printf("HD"); break; 968 default: printf("FD/HD"); break; 969 } 970 } 971 if (techab & MII_ANA_PAUSE_SYM) 972 { 973 if (!fs) 974 printf(", "); 975 fs= 0; 976 printf("pause(SYM)"); 977 } 978 if (techab & MII_ANA_PAUSE_ASYM) 979 { 980 if (!fs) 981 printf(", "); 982 fs= 0; 983 printf("pause(ASYM)"); 984 } 985 if (techab & MII_ANA_TAF_RES) 986 { 987 if (!fs) 988 printf(", "); 989 fs= 0; 990 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S); 991 } 992 } 993 994 static void mii_print_stat_speed(u16_t stat, u16_t extstat) 995 { 996 int fs, ft; 997 fs= 1; 998 if (stat & MII_STATUS_EXT_STAT) 999 { 1000 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD | 1001 MII_ESTAT_1000TFD | MII_ESTAT_1000THD)) 1002 { 1003 printf("1000 Mbps: "); 1004 fs= 0; 1005 ft= 1; 1006 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD)) 1007 { 1008 ft= 0; 1009 printf("X-"); 1010 switch(extstat & 1011 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD)) 1012 { 1013 case MII_ESTAT_1000XFD: printf("FD"); break; 1014 case MII_ESTAT_1000XHD: printf("HD"); break; 1015 default: printf("FD/HD"); break; 1016 } 1017 } 1018 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD)) 1019 { 1020 if (!ft) 1021 printf(", "); 1022 ft= 0; 1023 printf("T-"); 1024 switch(extstat & 1025 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD)) 1026 { 1027 case MII_ESTAT_1000TFD: printf("FD"); break; 1028 case MII_ESTAT_1000THD: printf("HD"); break; 1029 default: printf("FD/HD"); break; 1030 } 1031 } 1032 } 1033 } 1034 if (stat & (MII_STATUS_100T4 | 1035 MII_STATUS_100XFD | MII_STATUS_100XHD | 1036 MII_STATUS_100T2FD | MII_STATUS_100T2HD)) 1037 { 1038 if (!fs) 1039 printf(", "); 1040 fs= 0; 1041 printf("100 Mbps: "); 1042 ft= 1; 1043 if (stat & MII_STATUS_100T4) 1044 { 1045 printf("T4"); 1046 ft= 0; 1047 } 1048 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD)) 1049 { 1050 if (!ft) 1051 printf(", "); 1052 ft= 0; 1053 printf("TX-"); 1054 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD)) 1055 { 1056 case MII_STATUS_100XFD: printf("FD"); break; 1057 case MII_STATUS_100XHD: printf("HD"); break; 1058 default: printf("FD/HD"); break; 1059 } 1060 } 1061 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD)) 1062 { 1063 if (!ft) 1064 printf(", "); 1065 ft= 0; 1066 printf("T2-"); 1067 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD)) 1068 { 1069 case MII_STATUS_100T2FD: printf("FD"); break; 1070 case MII_STATUS_100T2HD: printf("HD"); break; 1071 default: printf("FD/HD"); break; 1072 } 1073 } 1074 } 1075 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD)) 1076 { 1077 if (!fs) 1078 printf(", "); 1079 printf("10 Mbps: "); 1080 fs= 0; 1081 printf("T-"); 1082 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD)) 1083 { 1084 case MII_STATUS_10FD: printf("FD"); break; 1085 case MII_STATUS_10HD: printf("HD"); break; 1086 default: printf("FD/HD"); break; 1087 } 1088 } 1089 } 1090 #endif /* VERBOSE */ 1091 1092 /*===========================================================================* 1093 * rl_clear_rx * 1094 *===========================================================================*/ 1095 static void rl_clear_rx(re_t *rep) 1096 { 1097 port_t port; 1098 u8_t cr; 1099 1100 rep->re_clear_rx= FALSE; 1101 port= rep->re_base_port; 1102 1103 /* Reset the receiver */ 1104 cr= rl_inb(port, RL_CR); 1105 cr &= ~RL_CR_RE; 1106 rl_outb(port, RL_CR, cr); 1107 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RE), 1000000); 1108 if (rl_inb(port, RL_CR) & RL_CR_RE) 1109 panic("cannot disable receiver"); 1110 1111 #if 0 1112 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART)); 1113 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR)); 1114 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR)); 1115 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR)); 1116 #endif 1117 1118 rl_outb(port, RL_CR, cr | RL_CR_RE); 1119 1120 rl_outl(port, RL_RCR, RX_BUFBITS); 1121 1122 rl_rec_mode(rep); 1123 1124 rep->re_stat.ets_missedP++; 1125 } 1126 1127 /*===========================================================================* 1128 * rl_do_reset * 1129 *===========================================================================*/ 1130 static void rl_do_reset(re_t *rep) 1131 { 1132 rep->re_need_reset= FALSE; 1133 rl_reset_hw(rep); 1134 rl_rec_mode(rep); 1135 1136 rep->re_tx_head= 0; 1137 if (rep->re_tx[rep->re_tx_head].ret_busy) 1138 rep->re_tx_busy--; 1139 rep->re_tx[rep->re_tx_head].ret_busy= FALSE; 1140 rep->re_send_int= TRUE; 1141 } 1142 1143 /*===========================================================================* 1144 * rl_stat * 1145 *===========================================================================*/ 1146 static void rl_stat(eth_stat_t *stat) 1147 { 1148 memcpy(stat, &re_state.re_stat, sizeof(*stat)); 1149 } 1150 1151 #if 0 1152 /*===========================================================================* 1153 * dump_phy * 1154 *===========================================================================*/ 1155 static void dump_phy(re_t *rep) 1156 { 1157 port_t port; 1158 u32_t t; 1159 1160 port= rep->re_base_port; 1161 1162 t= rl_inb(port, RL_MSR); 1163 printf("MSR: 0x%02lx\n", t); 1164 if (t & RL_MSR_SPEED_10) 1165 printf("\t10 Mbps\n"); 1166 if (t & RL_MSR_LINKB) 1167 printf("\tLink failed\n"); 1168 1169 t= rl_inb(port, RL_CONFIG1); 1170 printf("CONFIG1: 0x%02lx\n", t); 1171 1172 t= rl_inb(port, RL_CONFIG3); 1173 printf("CONFIG3: 0x%02lx\n", t); 1174 1175 t= rl_inb(port, RL_CONFIG4); 1176 printf("CONFIG4: 0x%02lx\n", t); 1177 1178 t= rl_inw(port, RL_BMCR); 1179 printf("BMCR (MII_CTRL): 0x%04lx\n", t); 1180 1181 t= rl_inw(port, RL_BMSR); 1182 printf("BMSR:"); 1183 if (t & MII_STATUS_100T4) 1184 printf(" 100Base-T4"); 1185 if (t & MII_STATUS_100XFD) 1186 printf(" 100Base-X-FD"); 1187 if (t & MII_STATUS_100XHD) 1188 printf(" 100Base-X-HD"); 1189 if (t & MII_STATUS_10FD) 1190 printf(" 10Mbps-FD"); 1191 if (t & MII_STATUS_10HD) 1192 printf(" 10Mbps-HD"); 1193 if (t & MII_STATUS_100T2FD) 1194 printf(" 100Base-T2-FD"); 1195 if (t & MII_STATUS_100T2HD) 1196 printf(" 100Base-T2-HD"); 1197 if (t & MII_STATUS_EXT_STAT) 1198 printf(" Ext-stat"); 1199 if (t & MII_STATUS_RES) 1200 printf(" res-0x%lx", t & MII_STATUS_RES); 1201 if (t & MII_STATUS_MFPS) 1202 printf(" MFPS"); 1203 if (t & MII_STATUS_ANC) 1204 printf(" ANC"); 1205 if (t & MII_STATUS_RF) 1206 printf(" remote-fault"); 1207 if (t & MII_STATUS_ANA) 1208 printf(" ANA"); 1209 if (t & MII_STATUS_LS) 1210 printf(" Link"); 1211 if (t & MII_STATUS_JD) 1212 printf(" Jabber"); 1213 if (t & MII_STATUS_EC) 1214 printf(" Extended-capability"); 1215 printf("\n"); 1216 1217 t= rl_inw(port, RL_ANAR); 1218 printf("ANAR (MII_ANA): 0x%04lx\n", t); 1219 1220 t= rl_inw(port, RL_ANLPAR); 1221 printf("ANLPAR: 0x%04lx\n", t); 1222 1223 t= rl_inw(port, RL_ANER); 1224 printf("ANER (MII_ANE): "); 1225 if (t & MII_ANE_RES) 1226 printf(" res-0x%lx", t & MII_ANE_RES); 1227 if (t & MII_ANE_PDF) 1228 printf(" Par-Detect-Fault"); 1229 if (t & MII_ANE_LPNPA) 1230 printf(" LP-Next-Page-Able"); 1231 if (t & MII_ANE_NPA) 1232 printf(" Loc-Next-Page-Able"); 1233 if (t & MII_ANE_PR) 1234 printf(" Page-Received"); 1235 if (t & MII_ANE_LPANA) 1236 printf(" LP-Auto-Neg-Able"); 1237 printf("\n"); 1238 1239 t= rl_inw(port, RL_NWAYTR); 1240 printf("NWAYTR: 0x%04lx\n", t); 1241 t= rl_inw(port, RL_CSCR); 1242 printf("CSCR: 0x%04lx\n", t); 1243 1244 t= rl_inb(port, RL_CONFIG5); 1245 printf("CONFIG5: 0x%02lx\n", t); 1246 } 1247 #endif 1248 1249 /*===========================================================================* 1250 * rl_handler * 1251 *===========================================================================*/ 1252 static int rl_handler(re_t *rep) 1253 { 1254 int i, port, tx_head, tx_tail, link_up; 1255 u16_t isr, tsad; 1256 u32_t tsd, tcr, ertxth; 1257 1258 port= rep->re_base_port; 1259 1260 /* Ack interrupt */ 1261 isr= rl_inw(port, RL_ISR); 1262 rl_outw(port, RL_ISR, isr); 1263 1264 if (isr & RL_IMR_FOVW) 1265 { 1266 isr &= ~RL_IMR_FOVW; 1267 /* Should do anything? */ 1268 1269 rep->re_stat.ets_fifoOver++; 1270 } 1271 if (isr & RL_IMR_PUN) 1272 { 1273 isr &= ~RL_IMR_PUN; 1274 1275 /* Either the link status changed or there was a TX fifo 1276 * underrun. 1277 */ 1278 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB); 1279 if (link_up != rep->re_link_up) 1280 { 1281 rep->re_report_link= TRUE; 1282 rep->re_got_int= TRUE; 1283 } 1284 } 1285 if (isr & RL_IMR_RXOVW) 1286 { 1287 isr &= ~RL_IMR_RXOVW; 1288 1289 /* Clear the receive buffer */ 1290 rep->re_clear_rx= TRUE; 1291 rep->re_got_int= TRUE; 1292 } 1293 1294 if (isr & (RL_ISR_RER | RL_ISR_ROK)) 1295 { 1296 isr &= ~(RL_ISR_RER | RL_ISR_ROK); 1297 1298 rep->re_got_int= TRUE; 1299 } 1300 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1) 1301 { 1302 isr &= ~(RL_ISR_TER | RL_ISR_TOK); 1303 1304 tsad= rl_inw(port, RL_TSAD); 1305 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1| 1306 RL_TSAD_TABT2|RL_TSAD_TABT3)) 1307 { 1308 printf("rl_handler, TABT, tasd = 0x%04x\n", 1309 tsad); 1310 1311 /* Find the aborted transmit request */ 1312 for (i= 0; i< N_TX_BUF; i++) 1313 { 1314 tsd= rl_inl(port, RL_TSD0+i*4); 1315 if (tsd & RL_TSD_TABT) 1316 break; 1317 } 1318 if (i >= N_TX_BUF) 1319 { 1320 printf( 1321 "rl_handler: can't find aborted TX req.\n"); 1322 } 1323 else 1324 { 1325 printf("TSD%d = 0x%04x\n", i, tsd); 1326 1327 /* Set head and tail to this buffer */ 1328 rep->re_tx_head= rep->re_tx_tail= i; 1329 } 1330 1331 /* Aborted transmission, just kick the device 1332 * and be done with it. 1333 */ 1334 rep->re_stat.ets_transAb++; 1335 tcr= rl_inl(port, RL_TCR); 1336 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT); 1337 } 1338 1339 /* Transmit completed */ 1340 tx_head= rep->re_tx_head; 1341 tx_tail= rep->re_tx_tail; 1342 for (i= 0; i< 2*N_TX_BUF; i++) 1343 { 1344 if (!rep->re_tx[tx_tail].ret_busy) 1345 { 1346 /* Strange, this buffer is not in-use. 1347 * Increment tx_tail until tx_head is 1348 * reached (or until we find a buffer that 1349 * is in-use. 1350 */ 1351 if (tx_tail == tx_head) 1352 break; 1353 if (++tx_tail >= N_TX_BUF) 1354 tx_tail= 0; 1355 assert(tx_tail < RL_N_TX); 1356 rep->re_tx_tail= tx_tail; 1357 continue; 1358 } 1359 tsd= rl_inl(port, RL_TSD0+tx_tail*4); 1360 if (!(tsd & RL_TSD_OWN)) 1361 { 1362 /* Buffer is not yet ready */ 1363 break; 1364 } 1365 1366 /* Should collect statistics */ 1367 if (tsd & RL_TSD_CRS) 1368 rep->re_stat.ets_carrSense++; 1369 if (tsd & RL_TSD_TABT) 1370 { 1371 printf("rl_handler, TABT, TSD%d = 0x%04x\n", 1372 tx_tail, tsd); 1373 assert(0); /* CLRABT is not all that 1374 * effective, why not? 1375 */ 1376 rep->re_stat.ets_transAb++; 1377 tcr= rl_inl(port, RL_TCR); 1378 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT); 1379 } 1380 if (tsd & RL_TSD_OWC) 1381 rep->re_stat.ets_OWC++; 1382 if (tsd & RL_TSD_CDH) 1383 rep->re_stat.ets_CDheartbeat++; 1384 1385 /* What about collisions? */ 1386 if (tsd & RL_TSD_TOK) 1387 rep->re_stat.ets_packetT++; 1388 else 1389 rep->re_stat.ets_sendErr++; 1390 if (tsd & RL_TSD_TUN) 1391 { 1392 rep->re_stat.ets_fifoUnder++; 1393 1394 /* Increase ERTXTH */ 1395 ertxth= tsd + (1 << RL_TSD_ERTXTH_S); 1396 ertxth &= RL_TSD_ERTXTH_M; 1397 #if VERBOSE 1398 if (ertxth > rep->re_ertxth) 1399 { 1400 printf("%s: new ertxth: %d bytes\n", 1401 rep->re_name, 1402 (ertxth >> RL_TSD_ERTXTH_S) * 1403 32); 1404 rep->re_ertxth= ertxth; 1405 } 1406 #endif 1407 } 1408 rep->re_tx[tx_tail].ret_busy= FALSE; 1409 rep->re_tx_busy--; 1410 1411 #if 0 1412 printf("TSD%d: %08lx\n", tx_tail, tsd); 1413 printf( 1414 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n", 1415 tx_head, tx_tail, 1416 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, 1417 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); 1418 #endif 1419 1420 if (++tx_tail >= N_TX_BUF) 1421 tx_tail= 0; 1422 assert(tx_tail < RL_N_TX); 1423 rep->re_tx_tail= tx_tail; 1424 1425 rep->re_send_int= TRUE; 1426 rep->re_got_int= TRUE; 1427 rep->re_tx_alive= TRUE; 1428 } 1429 assert(i < 2*N_TX_BUF); 1430 } 1431 if (isr) 1432 { 1433 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n", 1434 isr); 1435 } 1436 1437 return 1; 1438 } 1439 1440 /*===========================================================================* 1441 * rl_alarm * 1442 *===========================================================================*/ 1443 static void rl_alarm(clock_t __unused stamp) 1444 { 1445 re_t *rep; 1446 1447 /* Use a synchronous alarm instead of a watchdog timer. */ 1448 sys_setalarm(sys_hz(), 0); 1449 1450 rep= &re_state; 1451 1452 assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_BUF); 1453 if (rep->re_tx_busy == 0) 1454 { 1455 /* Assume that an idle system is alive */ 1456 rep->re_tx_alive= TRUE; 1457 return; 1458 } 1459 if (rep->re_tx_alive) 1460 { 1461 rep->re_tx_alive= FALSE; 1462 return; 1463 } 1464 printf("rl_alarm: resetting instance %d\n", re_instance); 1465 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", 1466 rl_inw(rep->re_base_port, RL_TSAD), 1467 rl_inl(rep->re_base_port, RL_TSD0+0*4), 1468 rl_inl(rep->re_base_port, RL_TSD0+1*4), 1469 rl_inl(rep->re_base_port, RL_TSD0+2*4), 1470 rl_inl(rep->re_base_port, RL_TSD0+3*4)); 1471 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n", 1472 rep->re_tx_head, rep->re_tx_tail, 1473 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, 1474 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); 1475 rep->re_need_reset= TRUE; 1476 rep->re_got_int= TRUE; 1477 1478 rl_check_ints(rep); 1479 } 1480 1481 /* TODO: obviously this needs a lot of work. */ 1482 static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev, 1483 int pci_func) 1484 { 1485 int r; 1486 endpoint_t dev_e; 1487 message m; 1488 1489 r= ds_retrieve_label_endpt("amddev", &dev_e); 1490 if (r != OK) 1491 { 1492 #if 0 1493 printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed " 1494 "for 'amddev': %d\n", r); 1495 #endif 1496 return; 1497 } 1498 1499 m.m_type= IOMMU_MAP; 1500 m.m2_i1= pci_bus; 1501 m.m2_i2= pci_dev; 1502 m.m2_i3= pci_func; 1503 m.m2_l1= buf; 1504 m.m2_l2= size; 1505 1506 r= ipc_sendrec(dev_e, &m); 1507 if (r != OK) 1508 { 1509 printf("rtl8139`tell_dev: ipc_sendrec to %d failed: %d\n", 1510 dev_e, r); 1511 return; 1512 } 1513 if (m.m_type != OK) 1514 { 1515 printf("rtl8139`tell_dev: dma map request failed: %d\n", 1516 m.m_type); 1517 return; 1518 } 1519 } 1520 1521 /* 1522 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $ 1523 */ 1524