if_le_ebus.c revision 1.16
1/* $NetBSD: if_le_ebus.c,v 1.16 2018/06/26 06:47:58 msaitoh 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.16 2018/06/26 06:47:58 msaitoh 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#include <net/bpf.h> 55 56#ifdef INET 57#include <netinet/in.h> 58#include <netinet/if_inarp.h> 59#endif 60 61#include <sys/rndsource.h> 62 63#include <emips/ebus/ebusvar.h> 64#include <emips/emips/machdep.h> 65#include <machine/emipsreg.h> 66 67extern paddr_t kvtophys(vaddr_t); 68 69struct bufmap { 70 struct mbuf *mbuf; 71 paddr_t phys; 72}; 73 74struct enic_softc { 75 device_t sc_dev; /* base device glue */ 76 struct ethercom sc_ethercom; /* Ethernet common part */ 77 struct ifmedia sc_media; /* our supported media */ 78 79 struct _Enic *sc_regs; /* hw registers */ 80 81 int sc_havecarrier; /* carrier status */ 82 void *sc_sh; /* shutdownhook cookie */ 83 int inited; 84 85 int sc_no_rd; 86 int sc_n_recv; 87 int sc_recv_h; 88 /* BUGBUG really should be malloc-ed */ 89#define SC_MAX_N_RECV 64 90 struct bufmap sc_recv[SC_MAX_N_RECV]; 91 92 int sc_no_td; 93 int sc_n_xmit; 94 int sc_xmit_h; 95 /* BUGBUG really should be malloc-ed */ 96#define SC_MAX_N_XMIT 16 97 struct bufmap sc_xmit[SC_MAX_N_XMIT]; 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 116void enic_reset(struct ifnet *); 117int enic_init(struct ifnet *); 118void enic_stop(struct ifnet *, int); 119void enic_start(struct ifnet *); 120void enic_shutdown(void *); 121void enic_watchdog(struct ifnet *); 122int enic_mediachange(struct ifnet *); 123void enic_mediastatus(struct ifnet *, struct ifmediareq *); 124int enic_ioctl(struct ifnet *, u_long, void *); 125int enic_intr(void *, void *); 126void enic_rint(struct enic_softc *, uint32_t, paddr_t); 127void enic_tint(struct enic_softc *, uint32_t, paddr_t); 128void enic_kill_xmit(struct enic_softc *); 129void enic_post_recv(struct enic_softc *, struct mbuf *); 130void enic_refill(struct enic_softc *); 131static int enic_gethwinfo(struct enic_softc *); 132int enic_put(struct enic_softc *, struct mbuf **); 133 134static int enic_match(device_t, cfdata_t, void *); 135static void enic_attach(device_t, device_t, void *); 136 137CFATTACH_DECL_NEW(enic_emips, sizeof(struct enic_softc), 138 enic_match, enic_attach, NULL, NULL); 139 140int 141enic_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 154void 155enic_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 = 194 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 195 IFQ_SET_READY(&ifp->if_snd); 196 197 /* Initialize ifmedia structures. */ 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 */ 234static 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 315void 316enic_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 326void 327enic_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 345void 346enic_shutdown(void *arg) 347{ 348 struct ifnet *ifp = arg; 349 350 enic_stop(ifp, 0); 351} 352 353void 354enic_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 370void 371enic_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 if (m) 488 m_freem(m); 489 sc->inited = 1; 490} 491 492void enic_refill(struct enic_softc *sc) 493{ 494 struct mbuf *m; 495 int waitmode = M_DONTWAIT; 496 497 MGETHDR(m, waitmode, MT_DATA); 498 if (m == NULL) 499 return; 500 m_set_rcvif(m, &sc->sc_ethercom.ec_if); 501 m->m_pkthdr.len = 0; 502 503 MCLGET(m, waitmode); 504 if ((m->m_flags & M_EXT) == 0) { 505 m_freem(m); 506 return; 507 } 508 509 m->m_len = MCLBYTES; 510 ADJUST_MBUF_OFFSET(m); 511 512 enic_post_recv(sc,m); 513} 514 515int 516enic_init(struct ifnet *ifp) 517{ 518 struct enic_softc *sc = ifp->if_softc; 519 uint32_t ctl; 520 521 /* no need to init many times unless we are in reset */ 522 if (sc->inited != 1) { 523 524 /* Cancel all xmit buffers */ 525 enic_kill_xmit(sc); 526 527 /* Re-post all recv buffers */ 528 enic_post_recv(sc,NULL); 529 } 530 531 /* Start the eNIC */ 532 ifp->if_flags |= IFF_RUNNING; 533 ifp->if_flags &= ~IFF_OACTIVE; 534 ifp->if_timer = 0; 535 ctl = sc->sc_regs->Control | EC_INTEN; 536 ctl &= ~EC_RXDIS; 537 sc->sc_regs->Control = ctl; 538#if 0 539 printf("enic_init <- %x\n",ctl); 540#endif 541 542 if_schedule_deferred_start(ifp); 543 544 return 0; 545} 546 547 548void 549enic_watchdog(struct ifnet *ifp) 550{ 551 struct enic_softc *sc = ifp->if_softc; 552 553#if 0 554 printf("enic_watch ctl=%x\n", sc->sc_regs->Control); 555#endif 556 log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 557 ++ifp->if_oerrors; 558 559 enic_reset(ifp); 560} 561 562int 563enic_mediachange(struct ifnet *ifp) 564{ 565#if 0 566 struct enic_softc *sc = ifp->if_softc; 567#endif 568 /* more code here.. */ 569 570 return 0; 571} 572 573void 574enic_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 575{ 576 struct enic_softc *sc = ifp->if_softc; 577 578 if ((ifp->if_flags & IFF_UP) == 0) 579 return; 580 581 ifmr->ifm_status = IFM_AVALID; 582 if (sc->sc_havecarrier) 583 ifmr->ifm_status |= IFM_ACTIVE; 584 585 /* more code here someday.. */ 586} 587 588/* 589 * Process an ioctl request. 590 */ 591int 592enic_ioctl(struct ifnet *ifp, u_long cmd, void *data) 593{ 594 struct enic_softc *sc = ifp->if_softc; 595 struct ifreq *ifr = (struct ifreq *)data; 596 int s, error = 0; 597 598 s = splnet(); 599 600 switch (cmd) { 601 case SIOCGIFMEDIA: 602 case SIOCSIFMEDIA: 603#if 0 /*DEBUG*/ 604 { 605 extern int ei_drops[]; 606 static int flip = 0; 607 if (flip++ == 2) { 608 int i; 609 flip = 0; 610 printf("enic_ioctl(%x) %qd/%qd %qd/%qd %d/%d %d:%d " 611 "%d+%d %d/%d/%d\n", ifp->if_flags, 612 ifp->if_ierrors, ifp->if_oerrors, 613 ifp->if_ipackets, ifp->if_opackets, 614 sc->sc_no_rd, sc->sc_no_td, 615 sc->xhit, sc->xmiss, 616 sc->tfull, sc->tfull2, 617 sc->brh, sc->rf, sc->bxh); 618 printf(" Ctl %x lt %x tim %d\n", 619 sc->sc_regs->Control, sc->it, ifp->if_timer); 620 621 for (i = 0; i < 64; i++) 622 if (ei_drops[i]) 623 printf(" %d.%d",i,ei_drops[i]); 624 printf("\n"); 625 } 626 } 627#endif 628 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 629 break; 630 631 default: 632 error = ether_ioctl(ifp, cmd, data); 633 if (cmd == SIOCSIFADDR) { 634 /* 635 * hackattack: NFS does not turn us back 636 * on after a stop. So. 637 */ 638#if 0 639 printf("enic_ioctl(%lx)\n",cmd); 640#endif 641 enic_init(ifp); 642 } 643 if (error != ENETRESET) 644 break; 645 error = 0; 646 if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) 647 break; 648 if (ifp->if_flags & IFF_RUNNING) { 649 enic_reset(ifp); 650 } 651 break; 652 } 653 splx(s); 654 655 return error; 656} 657 658int 659enic_intr(void *cookie, void *f) 660{ 661 struct enic_softc *sc = cookie; 662 uint32_t isr, saf, hi, lo, fl; 663 664 isr = sc->sc_regs->Control; 665 666 /* Make sure there is one and that we should take it */ 667 if ((isr & (EC_INTEN|EC_DONE)) != (EC_INTEN|EC_DONE)) 668 return 0; 669 670 if (isr & EC_ERROR) { 671 printf("%s: internal error\n", device_xname(sc->sc_dev)); 672 enic_reset(&sc->sc_ethercom.ec_if); 673 return 1; 674 } 675 676 /* 677 * pull out all completed buffers 678 */ 679 while ((isr & EC_OF_EMPTY) == 0) { 680 681 /* beware, order matters */ 682 saf = sc->sc_regs->SizeAndFlags; 683 hi = sc->sc_regs->BufferAddressHi32; /* BUGBUG 64bit */ 684 lo = sc->sc_regs->BufferAddressLo32; /* this pops the fifo */ 685 __USE(hi); 686 687 fl = saf & (ES_F_MASK &~ ES_F_DONE); 688 if (fl == ES_F_RECV) 689 enic_rint(sc,saf,lo); 690 else if (fl == ES_F_XMIT) 691 enic_tint(sc,saf,lo); 692 else { 693 /* 694 * we do not currently expect or care for 695 * command completions? 696 */ 697 if (fl != ES_F_CMD) 698 printf("%s: invalid saf=x%x (lo=%x)\n", 699 device_xname(sc->sc_dev), saf, lo); 700 } 701 702 isr = sc->sc_regs->Control; 703 } 704 705 rnd_add_uint32(&sc->rnd_source, isr); 706 707 return 1; 708} 709 710void 711enic_rint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 712{ 713 struct mbuf *m; 714 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 715 int len = saf & ES_S_MASK, i; 716 717 /* Find what buffer it is. Should be the first. */ 718 for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++) 719 if (sc->sc_recv[i].phys == phys) 720 goto found; 721 for (i = 0; i < sc->sc_recv_h; i++) 722 if (sc->sc_recv[i].phys == phys) 723 goto found; 724 725 /* uhu?? */ 726 printf("%s: bad recv phys %llx\n", device_xname(sc->sc_dev), 727 (long long)phys); 728 ifp->if_ierrors++; 729 return; 730 731 /* got it, pop it */ 732 found: 733 sc->sc_no_rd--; 734 m = sc->sc_recv[i].mbuf; 735 sc->sc_recv[i].mbuf = NULL; 736 sc->sc_recv[i].phys = ~0; 737 if (i == sc->sc_recv_h) { /* should be */ 738 sc->sc_recv_h = (++i == sc->sc_n_recv) ? 0 : i; 739 } 740#if DEBUG 741 else 742 sc->brh++; 743#endif 744 745 if (len <= sizeof(struct ether_header) || 746 len > ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ? 747 ETHER_VLAN_ENCAP_LEN + ETHERMTU + sizeof(struct ether_header) : 748 ETHERMTU + sizeof(struct ether_header))) { 749 ifp->if_ierrors++; 750 751 /* reuse it */ 752 enic_post_recv(sc,m); 753 return; 754 } 755 756 /* Adjust size */ 757 m->m_pkthdr.len = len; 758 m->m_len = len; /* recheck */ 759 760 /* Pass the packet up. */ 761 if_percpuq_enqueue(ifp->if_percpuq, m); 762 763 /* Need to refill now */ 764 enic_refill(sc); 765} 766 767void enic_tint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 768{ 769 struct mbuf *m; 770 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 771 int i; 772 773#if DEBUG 774 sc->it = 1; 775#endif 776 777 /* BUGBUG should there be a per-buffer error bit in SAF? */ 778 779 /* Find what buffer it is. Should be the first. */ 780 for (i = sc->sc_xmit_h; i < sc->sc_n_xmit; i++) 781 if (sc->sc_xmit[i].phys == phys) 782 goto found; 783 for (i = 0; i < sc->sc_xmit_h; i++) 784 if (sc->sc_xmit[i].phys == phys) 785 goto found; 786 787 /* uhu?? */ 788 printf("%s: bad xmit phys %llx\n", device_xname(sc->sc_dev), 789 (long long)phys); 790 ifp->if_oerrors++; 791 return; 792 793 /* got it, pop it */ 794 found: 795 m = sc->sc_xmit[i].mbuf; 796 sc->sc_xmit[i].mbuf = NULL; 797 sc->sc_xmit[i].phys = ~0; 798 if (i == sc->sc_xmit_h) { /* should be */ 799 sc->sc_xmit_h = (++i == sc->sc_n_xmit) ? 0 : i; 800 } 801#if DEBUG 802 else 803 sc->bxh++; 804#endif 805 m_freem(m); 806 ifp->if_opackets++; 807 808 if (--sc->sc_no_td == 0) 809 ifp->if_timer = 0; 810 811 ifp->if_flags &= ~IFF_OACTIVE; 812 if_schedule_deferred_start(ifp); 813#if DEBUG 814 sc->it = 1; 815#endif 816} 817 818/* 819 * Setup output on interface. 820 * Get another datagram to send off of the interface queue, and map it to the 821 * interface before starting the output. 822 * Called only at splnet or interrupt level. 823 */ 824void 825enic_start(struct ifnet *ifp) 826{ 827 struct enic_softc *sc = ifp->if_softc; 828 struct mbuf *m; 829 int len, ix, s; 830 paddr_t phys; 831 832#if DEBUG 833 sc->it = 0; 834#endif 835 836#if 0 837 printf("enic_start(%x)\n", ifp->if_flags); 838#endif 839 840 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 841 return; 842 843 s = splnet(); /* I know, I dont trust people.. */ 844 845 ix = sc->sc_xmit_h; 846 for (;;) { 847 848 /* Anything to do? */ 849 IFQ_POLL(&ifp->if_snd, m); 850 if (m == NULL) 851 break; 852 853 /* find a spot, if any */ 854 for (; ix < sc->sc_n_xmit; ix++) 855 if (sc->sc_xmit[ix].mbuf == NULL) 856 goto found; 857 for (ix = 0; ix < sc->sc_xmit_h; ix++) 858 if (sc->sc_xmit[ix].mbuf == NULL) 859 goto found; 860 /* oh well */ 861 ifp->if_flags |= IFF_OACTIVE; 862#if DEBUG 863 sc->tfull++; 864#endif 865 break; 866 867 found: 868 IFQ_DEQUEUE(&ifp->if_snd, m); 869 if (m == NULL) 870 break; 871 872 /* 873 * If BPF is listening on this interface, let it see the packet 874 * before we commit it to the wire. 875 */ 876 bpf_mtap(ifp, m, BPF_D_OUT); 877 878 /* 879 * Copy the mbuf chain into a contiguous transmit buffer. 880 */ 881 len = enic_put(sc, &m); 882 if (len == 0) 883 break; /* sanity */ 884 if (len > (ETHERMTU + sizeof(struct ether_header))) { 885 printf("enic? tlen %d > %d\n", 886 len, ETHERMTU + sizeof(struct ether_header)); 887 len = ETHERMTU + sizeof(struct ether_header); 888 } 889 890 ifp->if_timer = 5; 891 892 /* 893 * Remember and post the buffer 894 */ 895 phys = kvtophys((vaddr_t)m->m_data); 896 sc->sc_xmit[ix].mbuf = m; 897 sc->sc_xmit[ix].phys = phys; 898 899 sc->sc_no_td++; 900 901 tpostone(phys,len); 902 903 if (sc->sc_regs->Control & EC_IF_FULL) { 904 ifp->if_flags |= IFF_OACTIVE; 905#if DEBUG 906 sc->tfull2++; 907#endif 908 break; 909 } 910 911 ix++; 912 } 913 914 splx(s); 915} 916 917int enic_put(struct enic_softc *sc, struct mbuf **pm) 918{ 919 struct mbuf *n, *m = *pm, *mm; 920 int len, tlen = 0, xlen = m->m_pkthdr.len; 921 uint8_t *cp; 922 923#if 0 924 /* drop garbage */ 925 tlen = xlen; 926 for (; m; m = n) { 927 len = m->m_len; 928 if (len == 0) { 929 n = m_free(m); 930 if (m == *pm) 931 *pm = n; 932 continue; 933 } 934 tlen -= len; 935 KASSERT(m != m->m_next); 936 n = m->m_next; 937 if (tlen <= 0) 938 break; 939 } 940 941 /* 942 * We might be done: 943 * (a) empty chain (b) only one segment (c) bad chain 944 */ 945 if (((m = *pm) == NULL) || (tlen > 0)) 946 xlen = 0; 947#endif 948 949 if ((xlen == 0) || (xlen <= m->m_len)) { 950#if DEBUG 951 sc->xhit++; 952#endif 953 return xlen; 954 } 955 956 /* Nope, true chain. Copy to contig :-(( */ 957 tlen = xlen; 958 MGETHDR(n, M_NOWAIT, MT_DATA); 959 if (n == NULL) 960 goto Bad; 961 m_set_rcvif(n, &sc->sc_ethercom.ec_if); 962 n->m_pkthdr.len = tlen; 963 964 MCLGET(n, M_NOWAIT); 965 if ((n->m_flags & M_EXT) == 0) { 966 m_freem(n); 967 goto Bad; 968 } 969 970 n->m_len = tlen; 971 cp = mtod(n, uint8_t *); 972 for (; m && tlen; m = mm) { 973 974 len = m->m_len; 975 if (len > tlen) 976 len = tlen; 977 if (len) 978 memcpy(cp, mtod(m, void *), len); 979 980 cp += len; 981 tlen -= len; 982 mm = m_free(m); 983 984 } 985 986 *pm = n; 987#if DEBUG 988 sc->xmiss++; 989#endif 990 return (xlen); 991 992 Bad: 993 printf("enic_put: no mem?\n"); 994 m_freem(m); 995 return 0; 996} 997