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