1 /* $NetBSD: if_le_ebus.c,v 1.1 2011/01/26 01:18:50 pooka 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.1 2011/01/26 01:18:50 pooka 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 u_int8_t sc_enaddr[ETHER_ADDR_LEN]; 116 u_int8_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 *ifp, int suspend); 125 void enic_start(struct ifnet *ifp); 126 void enic_shutdown(void *); 127 void enic_watchdog(struct ifnet *ifp); 128 int enic_mediachange(struct ifnet *ifp); 129 void enic_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr); 130 int enic_ioctl(struct ifnet *ifp, u_long cmd, void *data); 131 int enic_intr(void *cookie, void *f); 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 *sc); 135 void enic_post_recv(struct enic_softc *sc, struct mbuf *m); 136 void enic_refill(struct enic_softc *sc); 137 static int enic_gethwinfo(struct enic_softc *sc); 138 int enic_put(struct enic_softc *sc, struct mbuf **pm); 139 140 static int enic_match(struct device *, struct cfdata *, void *); 141 static void enic_attach(struct device *, struct device *, 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(struct device *parent, struct cfdata *match, 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(struct device *parent, struct device *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 // sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; 218 219 /* Attach the interface. */ 220 if_attach(ifp); 221 ether_ifattach(ifp, sc->sc_enaddr); 222 223 sc->sc_sh = shutdownhook_establish(enic_shutdown, ifp); 224 if (sc->sc_sh == NULL) 225 panic("enic_attach: cannot establish shutdown hook"); 226 227 #if NRND > 0 228 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 229 RND_TYPE_NET, 0); 230 #endif 231 232 ebus_intr_establish(parent, (void*)ia->ia_cookie, IPL_NET, 233 enic_intr, sc); 234 } 235 236 /* Beware: does not work while the nic is running 237 */ 238 static int enic_gethwinfo(struct enic_softc *sc) 239 { 240 uint8_t buffer[8];/* 64bits max */ 241 PENIC_INFO hw = (PENIC_INFO)buffer; 242 paddr_t phys = kvtophys((vaddr_t)&buffer[0]), phys2; 243 int i; 244 245 /* First thing first, get the MAC address 246 */ 247 memset(buffer,0,sizeof buffer); 248 buffer[0] = ENIC_CMD_GET_ADDRESS; 249 buffer[3] = ENIC_CMD_GET_ADDRESS;/* bswap bug */ 250 sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD; 251 sc->sc_regs->BufferAddressHi32 = 0; 252 sc->sc_regs->BufferAddressLo32 = phys; /* go! */ 253 254 for (i = 0; i < 100; i++) { 255 DELAY(100); 256 if (0 == (sc->sc_regs->Control & EC_OF_EMPTY)) 257 break; 258 } 259 if (i == 100) 260 return 0; 261 262 phys2 = sc->sc_regs->BufferAddressLo32; 263 if (phys2 != phys) { 264 printf("enic uhu? %llx != %llx?\n",(long long)phys,(long long)phys2); 265 return 0; 266 } 267 memcpy(sc->sc_enaddr,buffer,ETHER_ADDR_LEN); 268 269 /* Next get the HW parameters 270 */ 271 memset(buffer,0,sizeof buffer); 272 buffer[0] = ENIC_CMD_GET_INFO; 273 buffer[3] = ENIC_CMD_GET_INFO;/* bswap bug */ 274 sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD; 275 sc->sc_regs->BufferAddressHi32 = 0; 276 sc->sc_regs->BufferAddressLo32 = phys; /* go! */ 277 278 for (i = 0; i < 100; i++) { 279 DELAY(100); 280 if (0 == (sc->sc_regs->Control & EC_OF_EMPTY)) 281 break; 282 } 283 if (i == 100) 284 return 0; 285 286 phys2 = sc->sc_regs->BufferAddressLo32; 287 if (phys2 != phys) { 288 printf("enic uhu2? %llx != %llx?\n",(long long)phys,(long long)phys2); 289 return 0; 290 } 291 //printf("enic: hwinfo: %x %x %x %x %x %x \n", hw->InputFifoSize, hw->OutputFifoSize, hw->CompletionFifoSize, 292 // hw->ErrorCount, hw->FramesDropped, hw->Reserved); 293 294 /* Get FIFO depths and cap them 295 */ 296 sc->sc_n_recv = hw->InputFifoSize; 297 if (sc->sc_n_recv > SC_MAX_N_RECV) 298 sc->sc_n_recv = SC_MAX_N_RECV; 299 if (sc->sc_n_recv == 0) { /* sanity and compat with old hw/simulator */ 300 sc->sc_n_recv = 8; 301 sc->sc_n_xmit = 4; 302 } else { 303 sc->sc_n_xmit = hw->OutputFifoSize; 304 if (sc->sc_n_xmit > SC_MAX_N_XMIT) 305 sc->sc_n_xmit = SC_MAX_N_XMIT; 306 } 307 308 return 1; 309 } 310 311 void 312 enic_reset(struct ifnet *ifp) 313 { 314 int s; 315 316 s = splnet(); 317 enic_stop(ifp,0); 318 enic_init(ifp); 319 splx(s); 320 } 321 322 void 323 enic_stop(struct ifnet *ifp, int suspend) 324 { 325 struct enic_softc *sc = ifp->if_softc; 326 327 //printf("enic_stop %x\n", sc->sc_regs->Control); 328 329 /* NB: only "ifconfig down" says suspend=1 (then "up" calls init) 330 * Could simply set RXDIS in this case 331 */ 332 sc->inited = 2; 333 sc->sc_regs->Control = EC_RESET; 334 sc->sc_no_rd = 0; /* they are gone */ 335 sc->sc_no_td = 0; /* they are gone */ 336 } 337 338 void 339 enic_shutdown(void *arg) 340 { 341 struct ifnet *ifp = arg; 342 343 enic_stop(ifp, 0); 344 } 345 346 void 347 enic_kill_xmit(struct enic_softc *sc) 348 { 349 int i; 350 struct mbuf *m; 351 352 for (i = 0; i < sc->sc_n_xmit; i++) 353 if ((m = sc->sc_xmit[i].mbuf) != NULL) { 354 sc->sc_xmit[i].mbuf = NULL; 355 sc->sc_xmit[i].phys = ~0; 356 m_freem(m); 357 } 358 sc->sc_no_td = 0; 359 sc->sc_xmit_h = 0; 360 } 361 362 void 363 enic_post_recv(struct enic_softc *sc, struct mbuf *m) 364 { 365 int i, waitmode = M_DONTWAIT; 366 paddr_t phys; 367 368 #define rpostone(_p_) \ 369 sc->sc_regs->SizeAndFlags = ES_F_RECV | MCLBYTES; \ 370 sc->sc_regs->BufferAddressHi32 = 0; \ 371 sc->sc_regs->BufferAddressLo32 = _p_; 372 #define tpostone(_p_,_s_) \ 373 sc->sc_regs->SizeAndFlags = ES_F_XMIT | (_s_); \ 374 sc->sc_regs->BufferAddressHi32 = 0; \ 375 sc->sc_regs->BufferAddressLo32 = _p_; 376 377 /* Operational reload? */ 378 if (m != NULL) { 379 /* But is the hw ready for it */ 380 if (sc->sc_regs->Control & EC_IF_FULL) 381 goto no_room; 382 /* Yes, find a spot. Include empty q case. */ 383 for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++) 384 if (sc->sc_recv[i].mbuf == NULL) 385 goto found; 386 for (i = 0; i < sc->sc_recv_h; i++) 387 if (sc->sc_recv[i].mbuf == NULL) 388 goto found; 389 /* no spot, drop it (sigh) */ 390 no_room: 391 #if DEBUG 392 sc->rf++; 393 #endif 394 m_freem(m); 395 return; 396 found: 397 phys = kvtophys((vaddr_t)m->m_data); 398 sc->sc_recv[i].mbuf = m; 399 sc->sc_recv[i].phys = phys; 400 rpostone(phys); 401 sc->sc_no_rd++; 402 return; 403 } 404 405 /* Repost after reset? */ 406 if (sc->inited) { 407 /* order doesnt matter, might as well keep it clean */ 408 int j = 0; 409 sc->sc_recv_h = 0; 410 for (i = 0; i < sc->sc_n_recv; i++) 411 if ((m = sc->sc_recv[i].mbuf) != NULL) { 412 phys = sc->sc_recv[i].phys; 413 sc->sc_recv[i].mbuf = NULL; 414 sc->sc_recv[i].phys = ~0; 415 sc->sc_recv[j].mbuf = m; 416 sc->sc_recv[j].phys = phys; 417 #if DEBUG 418 if (sc->sc_regs->Control & EC_IF_FULL) 419 printf("?uhu? postrecv full? %d\n", sc->sc_no_rd); 420 #endif 421 sc->sc_no_rd++; 422 rpostone(phys); 423 j++; 424 } 425 /* Any holes left? */ 426 sc->inited = 1; 427 if (j >= sc->sc_n_recv) 428 return;/* no, we are done */ 429 /* continue on with the loop below */ 430 i = j; m = NULL; 431 goto fillem; 432 } 433 434 /* Initial refill, we can wait */ 435 waitmode = M_WAIT; 436 sc->sc_recv_h = 0; 437 memset(sc->sc_recv, 0, sizeof(sc->sc_recv[0]) * sc->sc_n_recv); 438 i = 0; 439 fillem: 440 for (; i < sc->sc_n_recv; i++) { 441 MGETHDR(m, waitmode, MT_DATA); 442 if (m == 0) 443 break; 444 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 445 m->m_pkthdr.len = 0; 446 447 MCLGET(m, waitmode); 448 if ((m->m_flags & M_EXT) == 0) 449 break; 450 451 /* This offset aligns IP/TCP headers and helps performance 452 */ 453 #if 1 454 #define ADJUST_MBUF_OFFSET(_m_) { \ 455 (_m_)->m_data += 2; \ 456 (_m_)->m_len -= 2; \ 457 } 458 #else 459 #define ADJUST_MBUF_OFFSET(_m_) 460 #endif 461 462 m->m_len = MCLBYTES; 463 464 ADJUST_MBUF_OFFSET(m); 465 phys = kvtophys((vaddr_t)m->m_data); 466 sc->sc_recv[i].mbuf = m; 467 sc->sc_recv[i].phys = phys; 468 #if DEBUG 469 if (sc->sc_regs->Control & EC_IF_FULL) 470 printf("?uhu? postrecv2 full? %d\n", sc->sc_no_rd); 471 #endif 472 sc->sc_no_rd++; 473 rpostone(phys); 474 m = NULL; 475 } 476 477 if (m) m_freem(m); 478 sc->inited = 1; 479 } 480 481 void enic_refill(struct enic_softc *sc) 482 { 483 struct mbuf *m; 484 int waitmode = M_DONTWAIT; 485 486 MGETHDR(m, waitmode, MT_DATA); 487 if (m == 0) 488 return; 489 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 490 m->m_pkthdr.len = 0; 491 492 MCLGET(m, waitmode); 493 if ((m->m_flags & M_EXT) == 0) { 494 m_freem(m); 495 return; 496 } 497 498 m->m_len = MCLBYTES; 499 ADJUST_MBUF_OFFSET(m); 500 501 enic_post_recv(sc,m); 502 } 503 504 int 505 enic_init(struct ifnet *ifp) 506 { 507 struct enic_softc *sc = ifp->if_softc; 508 uint32_t ctl; 509 510 /* no need to init many times unless we are in reset */ 511 if (sc->inited != 1) { 512 513 /* Cancel all xmit buffers */ 514 enic_kill_xmit(sc); 515 516 /* Re-post all recv buffers */ 517 enic_post_recv(sc,NULL); 518 } 519 520 /* Start the eNIC */ 521 ifp->if_flags |= IFF_RUNNING; 522 ifp->if_flags &= ~IFF_OACTIVE; 523 ifp->if_timer = 0; 524 ctl = sc->sc_regs->Control | EC_INTEN; 525 ctl &= ~EC_RXDIS; 526 sc->sc_regs->Control = ctl; 527 //printf("enic_init <- %x\n",ctl); 528 529 enic_start(ifp); 530 531 return (0); 532 } 533 534 535 void 536 enic_watchdog(struct ifnet *ifp) 537 { 538 struct enic_softc *sc = ifp->if_softc; 539 540 //printf("enic_watch ctl=%x\n", sc->sc_regs->Control); 541 log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 542 ++ifp->if_oerrors; 543 544 enic_reset(ifp); 545 } 546 547 int 548 enic_mediachange(struct ifnet *ifp) 549 { 550 // struct enic_softc *sc = ifp->if_softc; 551 /* more code here.. */ 552 553 return (0); 554 } 555 556 void 557 enic_mediastatus( 558 struct ifnet *ifp, 559 struct ifmediareq *ifmr) 560 { 561 struct enic_softc *sc = ifp->if_softc; 562 563 if ((ifp->if_flags & IFF_UP) == 0) 564 return; 565 566 ifmr->ifm_status = IFM_AVALID; 567 if (sc->sc_havecarrier) 568 ifmr->ifm_status |= IFM_ACTIVE; 569 570 /* more code here someday.. */ 571 } 572 573 /* 574 * Process an ioctl request. 575 */ 576 int 577 enic_ioctl(struct ifnet *ifp, u_long cmd, void *data) 578 { 579 struct enic_softc *sc = ifp->if_softc; 580 struct ifreq *ifr = (struct ifreq *)data; 581 int s, error = 0; 582 583 s = splnet(); 584 585 switch (cmd) { 586 case SIOCGIFMEDIA: 587 case SIOCSIFMEDIA: 588 #if 0 /*DEBUG*/ 589 { 590 extern int ei_drops[]; 591 static int flip = 0; 592 if (flip++ == 2) { 593 int i; 594 flip = 0; 595 printf("enic_ioctl(%x) %qd/%qd %qd/%qd %d/%d %d:%d " 596 "%d+%d %d/%d/%d\n", ifp->if_flags, 597 ifp->if_ierrors, ifp->if_oerrors, 598 ifp->if_ipackets, ifp->if_opackets, 599 sc->sc_no_rd, sc->sc_no_td, 600 sc->xhit, sc->xmiss, 601 sc->tfull, sc->tfull2, 602 sc->brh, sc->rf, sc->bxh); 603 printf(" Ctl %x lt %x tim %d\n", 604 sc->sc_regs->Control, sc->it, ifp->if_timer); 605 606 for (i = 0; i < 64; i++) 607 if (ei_drops[i]) 608 printf(" %d.%d",i,ei_drops[i]); 609 printf("\n"); 610 } 611 } 612 #endif 613 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 614 break; 615 616 default: 617 error = ether_ioctl(ifp, cmd, data); 618 if (cmd == SIOCSIFADDR) { 619 /* 620 * hackattack: NFS does not turn us back 621 * on after a stop. So. 622 */ 623 //printf("enic_ioctl(%lx)\n",cmd); 624 enic_init(ifp); 625 } 626 if (error != ENETRESET) 627 break; 628 error = 0; 629 if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) 630 break; 631 if (ifp->if_flags & IFF_RUNNING) { 632 enic_reset(ifp); 633 } 634 break; 635 } 636 splx(s); 637 638 return (error); 639 } 640 641 int 642 enic_intr(void *cookie, void *f) 643 { 644 struct enic_softc *sc = cookie; 645 u_int32_t isr, saf, hi, lo, fl; 646 647 isr = sc->sc_regs->Control; 648 649 /* Make sure there is one and that we should take it */ 650 if ((isr & (EC_INTEN|EC_DONE)) != (EC_INTEN|EC_DONE)) 651 return (0); 652 653 if (isr & EC_ERROR) { 654 printf("%s: internal error\n", device_xname(sc->sc_dev)); 655 enic_reset(&sc->sc_ethercom.ec_if); 656 return (1); 657 } 658 659 /* pull out all completed buffers 660 */ 661 while ((isr & EC_OF_EMPTY) == 0) { 662 663 /* beware, order matters */ 664 saf = sc->sc_regs->SizeAndFlags; 665 hi = sc->sc_regs->BufferAddressHi32; /* BUGBUG 64bit */ 666 lo = sc->sc_regs->BufferAddressLo32; /* this pops the fifo */ 667 668 fl = saf & (ES_F_MASK &~ ES_F_DONE); 669 if (fl == ES_F_RECV) 670 enic_rint(sc,saf,lo); 671 else 672 if (fl == ES_F_XMIT) 673 enic_tint(sc,saf,lo); 674 else 675 /* we do not currently expect or care for command completions? */ 676 if (fl != ES_F_CMD) 677 printf("%s: invalid saf=x%x (lo=%x)\n", device_xname(sc->sc_dev), saf, lo); 678 679 isr = sc->sc_regs->Control; 680 } 681 682 #if NRND > 0 683 rnd_add_uint32(&sc->rnd_source, isr); 684 #endif 685 686 return (1); 687 } 688 689 void 690 enic_rint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 691 { 692 struct mbuf *m; 693 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 694 int len = saf & ES_S_MASK, i; 695 696 /* Find what buffer it is. Should be the first. */ 697 for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++) 698 if (sc->sc_recv[i].phys == phys) 699 goto found; 700 for (i = 0; i < sc->sc_recv_h; i++) 701 if (sc->sc_recv[i].phys == phys) 702 goto found; 703 704 /* uhu?? */ 705 printf("%s: bad recv phys %llx\n", device_xname(sc->sc_dev), (long long)phys); 706 ifp->if_ierrors++; 707 return; 708 709 /* got it, pop it */ 710 found: 711 sc->sc_no_rd--; 712 m = sc->sc_recv[i].mbuf; 713 sc->sc_recv[i].mbuf = NULL; 714 sc->sc_recv[i].phys = ~0; 715 if (i == sc->sc_recv_h) { /* should be */ 716 sc->sc_recv_h = (++i == sc->sc_n_recv) ? 0 : i; 717 } 718 #if DEBUG 719 else sc->brh++; 720 #endif 721 722 if (len <= sizeof(struct ether_header) || 723 len > ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ? 724 ETHER_VLAN_ENCAP_LEN + ETHERMTU + sizeof(struct ether_header) : 725 ETHERMTU + sizeof(struct ether_header))) { 726 ifp->if_ierrors++; 727 728 /* reuse it */ 729 enic_post_recv(sc,m); 730 return; 731 } 732 733 /* Adjust size */ 734 m->m_pkthdr.len = len; 735 m->m_len = len; /* recheck */ 736 737 ifp->if_ipackets++; 738 739 /* 740 * Check if there's a BPF listener on this interface. 741 * If so, hand off the raw packet to BPF. 742 */ 743 if (ifp->if_bpf) 744 bpf_mtap(ifp, m); 745 746 /* Pass the packet up. */ 747 (*ifp->if_input)(ifp, m); 748 749 /* Need to refill now */ 750 enic_refill(sc); 751 } 752 753 void enic_tint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 754 { 755 struct mbuf *m; 756 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 757 int i; 758 759 #if DEBUG 760 sc->it = 1; 761 #endif 762 763 /* BUGBUG should there be a per-buffer error bit in SAF? */ 764 765 /* Find what buffer it is. Should be the first. */ 766 for (i = sc->sc_xmit_h; i < sc->sc_n_xmit; i++) 767 if (sc->sc_xmit[i].phys == phys) 768 goto found; 769 for (i = 0; i < sc->sc_xmit_h; i++) 770 if (sc->sc_xmit[i].phys == phys) 771 goto found; 772 773 /* uhu?? */ 774 printf("%s: bad xmit phys %llx\n", device_xname(sc->sc_dev), (long long)phys); 775 ifp->if_oerrors++; 776 return; 777 778 /* got it, pop it */ 779 found: 780 m = sc->sc_xmit[i].mbuf; 781 sc->sc_xmit[i].mbuf = NULL; 782 sc->sc_xmit[i].phys = ~0; 783 if (i == sc->sc_xmit_h) { /* should be */ 784 sc->sc_xmit_h = (++i == sc->sc_n_xmit) ? 0 : i; 785 } 786 #if DEBUG 787 else sc->bxh++; 788 #endif 789 m_freem(m); 790 ifp->if_opackets++; 791 792 if (--sc->sc_no_td == 0) 793 ifp->if_timer = 0; 794 795 ifp->if_flags &= ~IFF_OACTIVE; 796 enic_start(ifp); 797 #if DEBUG 798 sc->it = 1; 799 #endif 800 } 801 802 /* 803 * Setup output on interface. 804 * Get another datagram to send off of the interface queue, and map it to the 805 * interface before starting the output. 806 * Called only at splnet or interrupt level. 807 */ 808 void 809 enic_start(struct ifnet *ifp) 810 { 811 struct enic_softc *sc = ifp->if_softc; 812 struct mbuf *m; 813 int len, ix, s; 814 paddr_t phys; 815 816 #if DEBUG 817 sc->it = 0; 818 #endif 819 820 //printf("enic_start(%x)\n", ifp->if_flags); 821 822 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 823 return; 824 825 s = splnet(); /* I know, I dont trust people.. */ 826 827 ix = sc->sc_xmit_h; 828 for (;;) { 829 830 /* Anything to do? */ 831 IFQ_POLL(&ifp->if_snd, m); 832 if (m == 0) 833 break; 834 835 /* find a spot, if any */ 836 for (;ix < sc->sc_n_xmit; ix++) 837 if (sc->sc_xmit[ix].mbuf == NULL) 838 goto found; 839 for (ix = 0; ix < sc->sc_xmit_h; ix++) 840 if (sc->sc_xmit[ix].mbuf == NULL) 841 goto found; 842 /* oh well */ 843 ifp->if_flags |= IFF_OACTIVE; 844 #if DEBUG 845 sc->tfull++; 846 #endif 847 break; 848 849 found: 850 IFQ_DEQUEUE(&ifp->if_snd, m); 851 if (m == 0) 852 break; 853 854 /* 855 * If BPF is listening on this interface, let it see the packet 856 * before we commit it to the wire. 857 */ 858 if (ifp->if_bpf) 859 bpf_mtap(ifp, m); 860 861 /* 862 * Copy the mbuf chain into a contiguous transmit buffer. 863 */ 864 len = enic_put(sc, &m); 865 if (len == 0) 866 break; /* sanity */ 867 if (len > (ETHERMTU + sizeof(struct ether_header))) { 868 printf("enic? tlen %d > %d\n", len, ETHERMTU + sizeof(struct ether_header)); 869 len = ETHERMTU + sizeof(struct ether_header); 870 } 871 872 ifp->if_timer = 5; 873 874 /* 875 * Remember and post the buffer 876 */ 877 phys = kvtophys((vaddr_t)m->m_data); 878 sc->sc_xmit[ix].mbuf = m; 879 sc->sc_xmit[ix].phys = phys; 880 881 sc->sc_no_td++; 882 883 tpostone(phys,len); 884 885 if (sc->sc_regs->Control & EC_IF_FULL) { 886 ifp->if_flags |= IFF_OACTIVE; 887 #if DEBUG 888 sc->tfull2++; 889 #endif 890 break; 891 } 892 893 ix++; 894 } 895 896 splx(s); 897 } 898 899 int enic_put(struct enic_softc *sc, struct mbuf **pm) 900 { 901 struct mbuf *n, *m = *pm, *mm; 902 int len, tlen = 0, xlen = m->m_pkthdr.len; 903 uint8_t *cp; 904 905 #if 0 906 /* drop garbage */ 907 tlen = xlen; 908 for (; m; m = n) { 909 len = m->m_len; 910 if (len == 0) { 911 MFREE(m, n); 912 if (m == *pm) *pm = n; 913 continue; 914 } 915 tlen -= len; 916 KASSERT(m != m->m_next); 917 n = m->m_next; 918 if (tlen <= 0) break; 919 } 920 921 /* We might be done: (a) empty chain (b) only one segment (c) bad chain */ 922 if (((m = *pm) == NULL) || (tlen > 0)) 923 xlen = 0; 924 #endif 925 926 if ((xlen == 0) || (xlen <= m->m_len)) { 927 #if DEBUG 928 sc->xhit++; 929 #endif 930 return xlen; 931 } 932 933 /* Nope, true chain. Copy to contig :-(( */ 934 tlen = xlen; 935 MGETHDR(n, M_NOWAIT, MT_DATA); 936 if (n == 0) 937 goto Bad; 938 n->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 939 n->m_pkthdr.len = tlen; 940 941 MCLGET(n, M_NOWAIT); 942 if ((n->m_flags & M_EXT) == 0) { 943 m_freem(n); 944 goto Bad; 945 } 946 947 n->m_len = tlen; 948 cp = mtod(n, uint8_t *); 949 for (; m && tlen; m = mm) { 950 951 len = m->m_len; 952 if (len > tlen) len = tlen; 953 if (len) 954 memcpy(cp, mtod(m, void *), len); 955 956 cp += len; 957 tlen -= len; 958 MFREE(m, mm); 959 960 } 961 962 *pm = n; 963 #if DEBUG 964 sc->xmiss++; 965 #endif 966 return (xlen); 967 968 Bad: 969 printf("enic_put: no mem?\n"); 970 m_freem(m); 971 return 0; 972 } 973