1 /* $NetBSD: if_le_ebus.c,v 1.2 2011/06/12 14:31:31 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code was written by Alessandro Forin and Neil Pittman 8 * at Microsoft Research and contributed to The NetBSD Foundation 9 * by Microsoft Corporation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: if_le_ebus.c,v 1.2 2011/06/12 14:31:31 tsutsui Exp $"); 35 36 #include "opt_inet.h" 37 38 #include "rnd.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/mbuf.h> 43 #include <sys/syslog.h> 44 #include <sys/socket.h> 45 #include <sys/device.h> 46 #include <sys/malloc.h> 47 #include <sys/ioctl.h> 48 #include <sys/errno.h> 49 50 #include <net/if.h> 51 #include <net/if_dl.h> 52 #include <net/if_ether.h> 53 #include <net/if_media.h> 54 55 #ifdef INET 56 #include <netinet/in.h> 57 #include <netinet/if_inarp.h> 58 #endif 59 60 #include <net/bpf.h> 61 #include <net/bpfdesc.h> 62 63 #if NRND > 0 64 #include <sys/rnd.h> 65 #endif 66 67 #include <emips/ebus/ebusvar.h> 68 #include <emips/emips/machdep.h> 69 #include <machine/emipsreg.h> 70 71 extern paddr_t kvtophys(vaddr_t); 72 73 struct bufmap { 74 struct mbuf *mbuf; 75 paddr_t phys; 76 }; 77 78 struct enic_softc { 79 device_t sc_dev; /* base device glue */ 80 struct ethercom sc_ethercom; /* Ethernet common part */ 81 struct ifmedia sc_media; /* our supported media */ 82 83 struct _Enic *sc_regs; /* hw registers */ 84 85 int sc_havecarrier; /* carrier status */ 86 void *sc_sh; /* shutdownhook cookie */ 87 int inited; 88 89 int sc_no_rd; 90 int sc_n_recv; 91 int sc_recv_h; 92 /* BUGBUG really should be malloc-ed */ 93 #define SC_MAX_N_RECV 64 94 struct bufmap sc_recv[SC_MAX_N_RECV]; 95 96 int sc_no_td; 97 int sc_n_xmit; 98 int sc_xmit_h; 99 /* BUGBUG really should be malloc-ed */ 100 #define SC_MAX_N_XMIT 16 101 struct bufmap sc_xmit[SC_MAX_N_XMIT]; 102 103 #if DEBUG 104 int xhit; 105 int xmiss; 106 int tfull; 107 int tfull2; 108 int brh; 109 int rf; 110 int bxh; 111 112 int it; 113 #endif 114 115 uint8_t sc_enaddr[ETHER_ADDR_LEN]; 116 uint8_t sc_pad[2]; 117 #if NRND > 0 118 rndsource_element_t rnd_source; 119 #endif 120 }; 121 122 void enic_reset(struct ifnet *); 123 int enic_init(struct ifnet *); 124 void enic_stop(struct ifnet *, int); 125 void enic_start(struct ifnet *); 126 void enic_shutdown(void *); 127 void enic_watchdog(struct ifnet *); 128 int enic_mediachange(struct ifnet *); 129 void enic_mediastatus(struct ifnet *, struct ifmediareq *); 130 int enic_ioctl(struct ifnet *, u_long, void *); 131 int enic_intr(void *, void *); 132 void enic_rint(struct enic_softc *, uint32_t, paddr_t); 133 void enic_tint(struct enic_softc *, uint32_t, paddr_t); 134 void enic_kill_xmit(struct enic_softc *); 135 void enic_post_recv(struct enic_softc *, struct mbuf *); 136 void enic_refill(struct enic_softc *); 137 static int enic_gethwinfo(struct enic_softc *); 138 int enic_put(struct enic_softc *, struct mbuf **); 139 140 static int enic_match(device_t, cfdata_t, void *); 141 static void enic_attach(device_t, device_t, void *); 142 143 CFATTACH_DECL_NEW(enic_emips, sizeof(struct enic_softc), 144 enic_match, enic_attach, NULL, NULL); 145 146 int 147 enic_match(device_t parent, cfdata_t cf, void *aux) 148 { 149 struct ebus_attach_args *d = aux; 150 /* donno yet */ 151 struct _Enic *et = (struct _Enic *)d->ia_vaddr; 152 153 if (strcmp("enic", d->ia_name) != 0) 154 return 0; 155 if ((et == NULL) || (et->Tag != PMTTAG_ETHERNET)) 156 return 0; 157 return 1; 158 } 159 160 void 161 enic_attach(device_t parent, device_t self, void *aux) 162 { 163 struct enic_softc *sc = device_private(self); 164 struct ebus_attach_args *ia = aux; 165 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 166 167 sc->sc_regs = (struct _Enic *)(ia->ia_vaddr); 168 #if DEBUG 169 printf(" virt=%p ", (void *)sc->sc_regs); 170 #endif 171 172 /* Get the MAC and the depth of the FIFOs */ 173 if (!enic_gethwinfo(sc)) { 174 printf(" <cannot get hw info> DISABLED.\n"); 175 /* 176 * NB: caveat maintainer: make sure what we 177 * did NOT do below does not hurt the system 178 */ 179 return; 180 } 181 182 sc->sc_dev = self; 183 sc->sc_no_td = 0; 184 sc->sc_havecarrier = 1; /* BUGBUG */ 185 sc->sc_recv_h = 0; 186 sc->sc_xmit_h = 0; 187 /* uhmm do I need to do this? */ 188 memset(sc->sc_recv, 0, sizeof sc->sc_recv); 189 memset(sc->sc_xmit, 0, sizeof sc->sc_xmit); 190 191 /* Initialize ifnet structure. */ 192 strcpy(ifp->if_xname, device_xname(sc->sc_dev)); 193 ifp->if_softc = sc; 194 ifp->if_start = enic_start; 195 ifp->if_ioctl = enic_ioctl; 196 ifp->if_watchdog = enic_watchdog; 197 ifp->if_init = enic_init; 198 ifp->if_stop = enic_stop; 199 ifp->if_flags = 200 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 201 IFQ_SET_READY(&ifp->if_snd); 202 203 /* Initialize ifmedia structures. */ 204 ifmedia_init(&sc->sc_media, 0, enic_mediachange, enic_mediastatus); 205 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 206 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); 207 208 /* Make sure the chip is stopped. */ 209 enic_stop(ifp, 0); 210 sc->inited = 0; 211 212 /* Get the mac address and print it */ 213 printf(": eNIC [%d %d], address %s\n", 214 sc->sc_n_recv, sc->sc_n_xmit, ether_sprintf(sc->sc_enaddr)); 215 216 /* claim 802.1q capability */ 217 #if 0 218 sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; 219 #endif 220 221 /* Attach the interface. */ 222 if_attach(ifp); 223 ether_ifattach(ifp, sc->sc_enaddr); 224 225 sc->sc_sh = shutdownhook_establish(enic_shutdown, ifp); 226 if (sc->sc_sh == NULL) 227 panic("enic_attach: cannot establish shutdown hook"); 228 229 #if NRND > 0 230 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 231 RND_TYPE_NET, 0); 232 #endif 233 234 ebus_intr_establish(parent, (void *)ia->ia_cookie, IPL_NET, 235 enic_intr, sc); 236 } 237 238 /* 239 * Beware: does not work while the nic is running 240 */ 241 static int enic_gethwinfo(struct enic_softc *sc) 242 { 243 uint8_t buffer[8]; /* 64bits max */ 244 PENIC_INFO hw = (PENIC_INFO)buffer; 245 paddr_t phys = kvtophys((vaddr_t)&buffer[0]), phys2; 246 int i; 247 248 /* 249 * First thing first, get the MAC address 250 */ 251 memset(buffer,0,sizeof buffer); 252 buffer[0] = ENIC_CMD_GET_ADDRESS; 253 buffer[3] = ENIC_CMD_GET_ADDRESS; /* bswap bug */ 254 sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD; 255 sc->sc_regs->BufferAddressHi32 = 0; 256 sc->sc_regs->BufferAddressLo32 = phys; /* go! */ 257 258 for (i = 0; i < 100; i++) { 259 DELAY(100); 260 if ((sc->sc_regs->Control & EC_OF_EMPTY) == 0) 261 break; 262 } 263 if (i == 100) 264 return 0; 265 266 phys2 = sc->sc_regs->BufferAddressLo32; 267 if (phys2 != phys) { 268 printf("enic uhu? %llx != %llx?\n", 269 (long long)phys, (long long)phys2); 270 return 0; 271 } 272 memcpy(sc->sc_enaddr, buffer, ETHER_ADDR_LEN); 273 274 /* 275 * Next get the HW parameters 276 */ 277 memset(buffer,0,sizeof buffer); 278 buffer[0] = ENIC_CMD_GET_INFO; 279 buffer[3] = ENIC_CMD_GET_INFO; /* bswap bug */ 280 sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD; 281 sc->sc_regs->BufferAddressHi32 = 0; 282 sc->sc_regs->BufferAddressLo32 = phys; /* go! */ 283 284 for (i = 0; i < 100; i++) { 285 DELAY(100); 286 if ((sc->sc_regs->Control & EC_OF_EMPTY) == 0) 287 break; 288 } 289 if (i == 100) 290 return 0; 291 292 phys2 = sc->sc_regs->BufferAddressLo32; 293 if (phys2 != phys) { 294 printf("enic uhu2? %llx != %llx?\n", 295 (long long)phys, (long long)phys2); 296 return 0; 297 } 298 #if 0 299 printf("enic: hwinfo: %x %x %x %x %x %x \n", 300 hw->InputFifoSize, hw->OutputFifoSize, hw->CompletionFifoSize, 301 hw->ErrorCount, hw->FramesDropped, hw->Reserved); 302 #endif 303 304 /* 305 * Get FIFO depths and cap them 306 */ 307 sc->sc_n_recv = hw->InputFifoSize; 308 if (sc->sc_n_recv > SC_MAX_N_RECV) 309 sc->sc_n_recv = SC_MAX_N_RECV; 310 if (sc->sc_n_recv == 0) { /* sanity and compat with old hw/simulator */ 311 sc->sc_n_recv = 8; 312 sc->sc_n_xmit = 4; 313 } else { 314 sc->sc_n_xmit = hw->OutputFifoSize; 315 if (sc->sc_n_xmit > SC_MAX_N_XMIT) 316 sc->sc_n_xmit = SC_MAX_N_XMIT; 317 } 318 319 return 1; 320 } 321 322 void 323 enic_reset(struct ifnet *ifp) 324 { 325 int s; 326 327 s = splnet(); 328 enic_stop(ifp,0); 329 enic_init(ifp); 330 splx(s); 331 } 332 333 void 334 enic_stop(struct ifnet *ifp, int suspend) 335 { 336 struct enic_softc *sc = ifp->if_softc; 337 338 #if 0 339 printf("enic_stop %x\n", sc->sc_regs->Control); 340 #endif 341 342 /* 343 * NB: only "ifconfig down" says suspend=1 (then "up" calls init) 344 * Could simply set RXDIS in this case 345 */ 346 sc->inited = 2; 347 sc->sc_regs->Control = EC_RESET; 348 sc->sc_no_rd = 0; /* they are gone */ 349 sc->sc_no_td = 0; /* they are gone */ 350 } 351 352 void 353 enic_shutdown(void *arg) 354 { 355 struct ifnet *ifp = arg; 356 357 enic_stop(ifp, 0); 358 } 359 360 void 361 enic_kill_xmit(struct enic_softc *sc) 362 { 363 int i; 364 struct mbuf *m; 365 366 for (i = 0; i < sc->sc_n_xmit; i++) { 367 if ((m = sc->sc_xmit[i].mbuf) != NULL) { 368 sc->sc_xmit[i].mbuf = NULL; 369 sc->sc_xmit[i].phys = ~0; 370 m_freem(m); 371 } 372 } 373 sc->sc_no_td = 0; 374 sc->sc_xmit_h = 0; 375 } 376 377 void 378 enic_post_recv(struct enic_softc *sc, struct mbuf *m) 379 { 380 int i, waitmode = M_DONTWAIT; 381 paddr_t phys; 382 383 #define rpostone(_p_) \ 384 sc->sc_regs->SizeAndFlags = ES_F_RECV | MCLBYTES; \ 385 sc->sc_regs->BufferAddressHi32 = 0; \ 386 sc->sc_regs->BufferAddressLo32 = _p_; 387 #define tpostone(_p_,_s_) \ 388 sc->sc_regs->SizeAndFlags = ES_F_XMIT | (_s_); \ 389 sc->sc_regs->BufferAddressHi32 = 0; \ 390 sc->sc_regs->BufferAddressLo32 = _p_; 391 392 /* Operational reload? */ 393 if (m != NULL) { 394 /* But is the hw ready for it */ 395 if (sc->sc_regs->Control & EC_IF_FULL) 396 goto no_room; 397 /* Yes, find a spot. Include empty q case. */ 398 for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++) 399 if (sc->sc_recv[i].mbuf == NULL) 400 goto found; 401 for (i = 0; i < sc->sc_recv_h; i++) 402 if (sc->sc_recv[i].mbuf == NULL) 403 goto found; 404 /* no spot, drop it (sigh) */ 405 no_room: 406 #if DEBUG 407 sc->rf++; 408 #endif 409 m_freem(m); 410 return; 411 found: 412 phys = kvtophys((vaddr_t)m->m_data); 413 sc->sc_recv[i].mbuf = m; 414 sc->sc_recv[i].phys = phys; 415 rpostone(phys); 416 sc->sc_no_rd++; 417 return; 418 } 419 420 /* Repost after reset? */ 421 if (sc->inited) { 422 /* order doesnt matter, might as well keep it clean */ 423 int j = 0; 424 sc->sc_recv_h = 0; 425 for (i = 0; i < sc->sc_n_recv; i++) 426 if ((m = sc->sc_recv[i].mbuf) != NULL) { 427 phys = sc->sc_recv[i].phys; 428 sc->sc_recv[i].mbuf = NULL; 429 sc->sc_recv[i].phys = ~0; 430 sc->sc_recv[j].mbuf = m; 431 sc->sc_recv[j].phys = phys; 432 #if DEBUG 433 if (sc->sc_regs->Control & EC_IF_FULL) 434 printf("?uhu? postrecv full? %d\n", 435 sc->sc_no_rd); 436 #endif 437 sc->sc_no_rd++; 438 rpostone(phys); 439 j++; 440 } 441 /* Any holes left? */ 442 sc->inited = 1; 443 if (j >= sc->sc_n_recv) 444 return; /* no, we are done */ 445 /* continue on with the loop below */ 446 i = j; m = NULL; 447 goto fillem; 448 } 449 450 /* Initial refill, we can wait */ 451 waitmode = M_WAIT; 452 sc->sc_recv_h = 0; 453 memset(sc->sc_recv, 0, sizeof(sc->sc_recv[0]) * sc->sc_n_recv); 454 i = 0; 455 fillem: 456 for (; i < sc->sc_n_recv; i++) { 457 MGETHDR(m, waitmode, MT_DATA); 458 if (m == 0) 459 break; 460 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 461 m->m_pkthdr.len = 0; 462 463 MCLGET(m, waitmode); 464 if ((m->m_flags & M_EXT) == 0) 465 break; 466 467 /* 468 * This offset aligns IP/TCP headers and helps performance 469 */ 470 #if 1 471 #define ADJUST_MBUF_OFFSET(_m_) { \ 472 (_m_)->m_data += 2; \ 473 (_m_)->m_len -= 2; \ 474 } 475 #else 476 #define ADJUST_MBUF_OFFSET(_m_) 477 #endif 478 479 m->m_len = MCLBYTES; 480 481 ADJUST_MBUF_OFFSET(m); 482 phys = kvtophys((vaddr_t)m->m_data); 483 sc->sc_recv[i].mbuf = m; 484 sc->sc_recv[i].phys = phys; 485 #if DEBUG 486 if (sc->sc_regs->Control & EC_IF_FULL) 487 printf("?uhu? postrecv2 full? %d\n", sc->sc_no_rd); 488 #endif 489 sc->sc_no_rd++; 490 rpostone(phys); 491 m = NULL; 492 } 493 494 if (m) 495 m_freem(m); 496 sc->inited = 1; 497 } 498 499 void enic_refill(struct enic_softc *sc) 500 { 501 struct mbuf *m; 502 int waitmode = M_DONTWAIT; 503 504 MGETHDR(m, waitmode, MT_DATA); 505 if (m == NULL) 506 return; 507 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 508 m->m_pkthdr.len = 0; 509 510 MCLGET(m, waitmode); 511 if ((m->m_flags & M_EXT) == 0) { 512 m_freem(m); 513 return; 514 } 515 516 m->m_len = MCLBYTES; 517 ADJUST_MBUF_OFFSET(m); 518 519 enic_post_recv(sc,m); 520 } 521 522 int 523 enic_init(struct ifnet *ifp) 524 { 525 struct enic_softc *sc = ifp->if_softc; 526 uint32_t ctl; 527 528 /* no need to init many times unless we are in reset */ 529 if (sc->inited != 1) { 530 531 /* Cancel all xmit buffers */ 532 enic_kill_xmit(sc); 533 534 /* Re-post all recv buffers */ 535 enic_post_recv(sc,NULL); 536 } 537 538 /* Start the eNIC */ 539 ifp->if_flags |= IFF_RUNNING; 540 ifp->if_flags &= ~IFF_OACTIVE; 541 ifp->if_timer = 0; 542 ctl = sc->sc_regs->Control | EC_INTEN; 543 ctl &= ~EC_RXDIS; 544 sc->sc_regs->Control = ctl; 545 #if 0 546 printf("enic_init <- %x\n",ctl); 547 #endif 548 549 enic_start(ifp); 550 551 return 0; 552 } 553 554 555 void 556 enic_watchdog(struct ifnet *ifp) 557 { 558 struct enic_softc *sc = ifp->if_softc; 559 560 #if 0 561 printf("enic_watch ctl=%x\n", sc->sc_regs->Control); 562 #endif 563 log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 564 ++ifp->if_oerrors; 565 566 enic_reset(ifp); 567 } 568 569 int 570 enic_mediachange(struct ifnet *ifp) 571 { 572 #if 0 573 struct enic_softc *sc = ifp->if_softc; 574 #endif 575 /* more code here.. */ 576 577 return 0; 578 } 579 580 void 581 enic_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 582 { 583 struct enic_softc *sc = ifp->if_softc; 584 585 if ((ifp->if_flags & IFF_UP) == 0) 586 return; 587 588 ifmr->ifm_status = IFM_AVALID; 589 if (sc->sc_havecarrier) 590 ifmr->ifm_status |= IFM_ACTIVE; 591 592 /* more code here someday.. */ 593 } 594 595 /* 596 * Process an ioctl request. 597 */ 598 int 599 enic_ioctl(struct ifnet *ifp, u_long cmd, void *data) 600 { 601 struct enic_softc *sc = ifp->if_softc; 602 struct ifreq *ifr = (struct ifreq *)data; 603 int s, error = 0; 604 605 s = splnet(); 606 607 switch (cmd) { 608 case SIOCGIFMEDIA: 609 case SIOCSIFMEDIA: 610 #if 0 /*DEBUG*/ 611 { 612 extern int ei_drops[]; 613 static int flip = 0; 614 if (flip++ == 2) { 615 int i; 616 flip = 0; 617 printf("enic_ioctl(%x) %qd/%qd %qd/%qd %d/%d %d:%d " 618 "%d+%d %d/%d/%d\n", ifp->if_flags, 619 ifp->if_ierrors, ifp->if_oerrors, 620 ifp->if_ipackets, ifp->if_opackets, 621 sc->sc_no_rd, sc->sc_no_td, 622 sc->xhit, sc->xmiss, 623 sc->tfull, sc->tfull2, 624 sc->brh, sc->rf, sc->bxh); 625 printf(" Ctl %x lt %x tim %d\n", 626 sc->sc_regs->Control, sc->it, ifp->if_timer); 627 628 for (i = 0; i < 64; i++) 629 if (ei_drops[i]) 630 printf(" %d.%d",i,ei_drops[i]); 631 printf("\n"); 632 } 633 } 634 #endif 635 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 636 break; 637 638 default: 639 error = ether_ioctl(ifp, cmd, data); 640 if (cmd == SIOCSIFADDR) { 641 /* 642 * hackattack: NFS does not turn us back 643 * on after a stop. So. 644 */ 645 #if 0 646 printf("enic_ioctl(%lx)\n",cmd); 647 #endif 648 enic_init(ifp); 649 } 650 if (error != ENETRESET) 651 break; 652 error = 0; 653 if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) 654 break; 655 if (ifp->if_flags & IFF_RUNNING) { 656 enic_reset(ifp); 657 } 658 break; 659 } 660 splx(s); 661 662 return error; 663 } 664 665 int 666 enic_intr(void *cookie, void *f) 667 { 668 struct enic_softc *sc = cookie; 669 uint32_t isr, saf, hi, lo, fl; 670 671 isr = sc->sc_regs->Control; 672 673 /* Make sure there is one and that we should take it */ 674 if ((isr & (EC_INTEN|EC_DONE)) != (EC_INTEN|EC_DONE)) 675 return 0; 676 677 if (isr & EC_ERROR) { 678 printf("%s: internal error\n", device_xname(sc->sc_dev)); 679 enic_reset(&sc->sc_ethercom.ec_if); 680 return 1; 681 } 682 683 /* 684 * pull out all completed buffers 685 */ 686 while ((isr & EC_OF_EMPTY) == 0) { 687 688 /* beware, order matters */ 689 saf = sc->sc_regs->SizeAndFlags; 690 hi = sc->sc_regs->BufferAddressHi32; /* BUGBUG 64bit */ 691 lo = sc->sc_regs->BufferAddressLo32; /* this pops the fifo */ 692 693 fl = saf & (ES_F_MASK &~ ES_F_DONE); 694 if (fl == ES_F_RECV) 695 enic_rint(sc,saf,lo); 696 else if (fl == ES_F_XMIT) 697 enic_tint(sc,saf,lo); 698 else { 699 /* 700 * we do not currently expect or care for 701 * command completions? 702 */ 703 if (fl != ES_F_CMD) 704 printf("%s: invalid saf=x%x (lo=%x)\n", 705 device_xname(sc->sc_dev), saf, lo); 706 } 707 708 isr = sc->sc_regs->Control; 709 } 710 711 #if NRND > 0 712 rnd_add_uint32(&sc->rnd_source, isr); 713 #endif 714 715 return 1; 716 } 717 718 void 719 enic_rint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 720 { 721 struct mbuf *m; 722 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 723 int len = saf & ES_S_MASK, i; 724 725 /* Find what buffer it is. Should be the first. */ 726 for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++) 727 if (sc->sc_recv[i].phys == phys) 728 goto found; 729 for (i = 0; i < sc->sc_recv_h; i++) 730 if (sc->sc_recv[i].phys == phys) 731 goto found; 732 733 /* uhu?? */ 734 printf("%s: bad recv phys %llx\n", device_xname(sc->sc_dev), 735 (long long)phys); 736 ifp->if_ierrors++; 737 return; 738 739 /* got it, pop it */ 740 found: 741 sc->sc_no_rd--; 742 m = sc->sc_recv[i].mbuf; 743 sc->sc_recv[i].mbuf = NULL; 744 sc->sc_recv[i].phys = ~0; 745 if (i == sc->sc_recv_h) { /* should be */ 746 sc->sc_recv_h = (++i == sc->sc_n_recv) ? 0 : i; 747 } 748 #if DEBUG 749 else 750 sc->brh++; 751 #endif 752 753 if (len <= sizeof(struct ether_header) || 754 len > ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ? 755 ETHER_VLAN_ENCAP_LEN + ETHERMTU + sizeof(struct ether_header) : 756 ETHERMTU + sizeof(struct ether_header))) { 757 ifp->if_ierrors++; 758 759 /* reuse it */ 760 enic_post_recv(sc,m); 761 return; 762 } 763 764 /* Adjust size */ 765 m->m_pkthdr.len = len; 766 m->m_len = len; /* recheck */ 767 768 ifp->if_ipackets++; 769 770 /* 771 * Check if there's a BPF listener on this interface. 772 * If so, hand off the raw packet to BPF. 773 */ 774 if (ifp->if_bpf) 775 bpf_mtap(ifp, m); 776 777 /* Pass the packet up. */ 778 (*ifp->if_input)(ifp, m); 779 780 /* Need to refill now */ 781 enic_refill(sc); 782 } 783 784 void enic_tint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 785 { 786 struct mbuf *m; 787 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 788 int i; 789 790 #if DEBUG 791 sc->it = 1; 792 #endif 793 794 /* BUGBUG should there be a per-buffer error bit in SAF? */ 795 796 /* Find what buffer it is. Should be the first. */ 797 for (i = sc->sc_xmit_h; i < sc->sc_n_xmit; i++) 798 if (sc->sc_xmit[i].phys == phys) 799 goto found; 800 for (i = 0; i < sc->sc_xmit_h; i++) 801 if (sc->sc_xmit[i].phys == phys) 802 goto found; 803 804 /* uhu?? */ 805 printf("%s: bad xmit phys %llx\n", device_xname(sc->sc_dev), 806 (long long)phys); 807 ifp->if_oerrors++; 808 return; 809 810 /* got it, pop it */ 811 found: 812 m = sc->sc_xmit[i].mbuf; 813 sc->sc_xmit[i].mbuf = NULL; 814 sc->sc_xmit[i].phys = ~0; 815 if (i == sc->sc_xmit_h) { /* should be */ 816 sc->sc_xmit_h = (++i == sc->sc_n_xmit) ? 0 : i; 817 } 818 #if DEBUG 819 else 820 sc->bxh++; 821 #endif 822 m_freem(m); 823 ifp->if_opackets++; 824 825 if (--sc->sc_no_td == 0) 826 ifp->if_timer = 0; 827 828 ifp->if_flags &= ~IFF_OACTIVE; 829 enic_start(ifp); 830 #if DEBUG 831 sc->it = 1; 832 #endif 833 } 834 835 /* 836 * Setup output on interface. 837 * Get another datagram to send off of the interface queue, and map it to the 838 * interface before starting the output. 839 * Called only at splnet or interrupt level. 840 */ 841 void 842 enic_start(struct ifnet *ifp) 843 { 844 struct enic_softc *sc = ifp->if_softc; 845 struct mbuf *m; 846 int len, ix, s; 847 paddr_t phys; 848 849 #if DEBUG 850 sc->it = 0; 851 #endif 852 853 #if 0 854 printf("enic_start(%x)\n", ifp->if_flags); 855 #endif 856 857 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 858 return; 859 860 s = splnet(); /* I know, I dont trust people.. */ 861 862 ix = sc->sc_xmit_h; 863 for (;;) { 864 865 /* Anything to do? */ 866 IFQ_POLL(&ifp->if_snd, m); 867 if (m == NULL) 868 break; 869 870 /* find a spot, if any */ 871 for (; ix < sc->sc_n_xmit; ix++) 872 if (sc->sc_xmit[ix].mbuf == NULL) 873 goto found; 874 for (ix = 0; ix < sc->sc_xmit_h; ix++) 875 if (sc->sc_xmit[ix].mbuf == NULL) 876 goto found; 877 /* oh well */ 878 ifp->if_flags |= IFF_OACTIVE; 879 #if DEBUG 880 sc->tfull++; 881 #endif 882 break; 883 884 found: 885 IFQ_DEQUEUE(&ifp->if_snd, m); 886 if (m == NULL) 887 break; 888 889 /* 890 * If BPF is listening on this interface, let it see the packet 891 * before we commit it to the wire. 892 */ 893 if (ifp->if_bpf) 894 bpf_mtap(ifp, m); 895 896 /* 897 * Copy the mbuf chain into a contiguous transmit buffer. 898 */ 899 len = enic_put(sc, &m); 900 if (len == 0) 901 break; /* sanity */ 902 if (len > (ETHERMTU + sizeof(struct ether_header))) { 903 printf("enic? tlen %d > %d\n", 904 len, ETHERMTU + sizeof(struct ether_header)); 905 len = ETHERMTU + sizeof(struct ether_header); 906 } 907 908 ifp->if_timer = 5; 909 910 /* 911 * Remember and post the buffer 912 */ 913 phys = kvtophys((vaddr_t)m->m_data); 914 sc->sc_xmit[ix].mbuf = m; 915 sc->sc_xmit[ix].phys = phys; 916 917 sc->sc_no_td++; 918 919 tpostone(phys,len); 920 921 if (sc->sc_regs->Control & EC_IF_FULL) { 922 ifp->if_flags |= IFF_OACTIVE; 923 #if DEBUG 924 sc->tfull2++; 925 #endif 926 break; 927 } 928 929 ix++; 930 } 931 932 splx(s); 933 } 934 935 int enic_put(struct enic_softc *sc, struct mbuf **pm) 936 { 937 struct mbuf *n, *m = *pm, *mm; 938 int len, tlen = 0, xlen = m->m_pkthdr.len; 939 uint8_t *cp; 940 941 #if 0 942 /* drop garbage */ 943 tlen = xlen; 944 for (; m; m = n) { 945 len = m->m_len; 946 if (len == 0) { 947 MFREE(m, n); 948 if (m == *pm) 949 *pm = n; 950 continue; 951 } 952 tlen -= len; 953 KASSERT(m != m->m_next); 954 n = m->m_next; 955 if (tlen <= 0) 956 break; 957 } 958 959 /* 960 * We might be done: 961 * (a) empty chain (b) only one segment (c) bad chain 962 */ 963 if (((m = *pm) == NULL) || (tlen > 0)) 964 xlen = 0; 965 #endif 966 967 if ((xlen == 0) || (xlen <= m->m_len)) { 968 #if DEBUG 969 sc->xhit++; 970 #endif 971 return xlen; 972 } 973 974 /* Nope, true chain. Copy to contig :-(( */ 975 tlen = xlen; 976 MGETHDR(n, M_NOWAIT, MT_DATA); 977 if (n == NULL) 978 goto Bad; 979 n->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 980 n->m_pkthdr.len = tlen; 981 982 MCLGET(n, M_NOWAIT); 983 if ((n->m_flags & M_EXT) == 0) { 984 m_freem(n); 985 goto Bad; 986 } 987 988 n->m_len = tlen; 989 cp = mtod(n, uint8_t *); 990 for (; m && tlen; m = mm) { 991 992 len = m->m_len; 993 if (len > tlen) 994 len = tlen; 995 if (len) 996 memcpy(cp, mtod(m, void *), len); 997 998 cp += len; 999 tlen -= len; 1000 MFREE(m, mm); 1001 1002 } 1003 1004 *pm = n; 1005 #if DEBUG 1006 sc->xmiss++; 1007 #endif 1008 return (xlen); 1009 1010 Bad: 1011 printf("enic_put: no mem?\n"); 1012 m_freem(m); 1013 return 0; 1014 } 1015