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