1/* $OpenBSD: if_eg.c,v 1.52 2023/09/11 08:41:26 mvs Exp $ */ 2/* $NetBSD: if_eg.c,v 1.26 1996/05/12 23:52:27 mycroft Exp $ */ 3 4/* 5 * Copyright (c) 1993 Dean Huxley <dean@fsa.ca> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Dean Huxley. 19 * 4. The name of Dean Huxley may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33/* 34 * Support for 3Com 3c505 Etherlink+ card. 35 */ 36 37/* To do: 38 * - multicast 39 * - promiscuous 40 */ 41#include "bpfilter.h" 42 43#include <sys/param.h> 44#include <sys/mbuf.h> 45#include <sys/socket.h> 46#include <sys/ioctl.h> 47#include <sys/errno.h> 48#include <sys/syslog.h> 49#include <sys/systm.h> 50#include <sys/device.h> 51 52#include <net/if.h> 53 54#include <netinet/in.h> 55#include <netinet/if_ether.h> 56 57#if NBPFILTER > 0 58#include <net/bpf.h> 59#endif 60 61#include <machine/cpu.h> 62#include <machine/intr.h> 63 64#include <dev/isa/isavar.h> 65#include <dev/isa/if_egreg.h> 66#include <dev/isa/elink.h> 67 68/* for debugging convenience */ 69#ifdef EGDEBUG 70#define DPRINTF(x) printf x 71#else 72#define DPRINTF(x) 73#endif 74 75#define EG_INLEN 10 76#define EG_BUFLEN 0x0670 77 78/* 79 * Ethernet software status per interface. 80 */ 81struct eg_softc { 82 struct device sc_dev; 83 void *sc_ih; 84 bus_space_tag_t sc_bst; 85 bus_space_handle_t sc_bsh; 86 struct arpcom sc_arpcom; /* Ethernet common part */ 87 u_char eg_rom_major; /* Cards ROM version (major number) */ 88 u_char eg_rom_minor; /* Cards ROM version (minor number) */ 89 short eg_ram; /* Amount of RAM on the card */ 90 u_char eg_pcb[64]; /* Primary Command Block buffer */ 91 u_char eg_incount; /* Number of buffers currently used */ 92 u_char *eg_inbuf; /* Incoming packet buffer */ 93 u_char *eg_outbuf; /* Outgoing packet buffer */ 94}; 95 96int egprobe(struct device *, void *, void *); 97void egattach(struct device *, struct device *, void *); 98 99const struct cfattach eg_ca = { 100 sizeof(struct eg_softc), egprobe, egattach 101}; 102 103struct cfdriver eg_cd = { 104 NULL, "eg", DV_IFNET 105}; 106 107int egintr(void *); 108void eginit(struct eg_softc *); 109int egioctl(struct ifnet *, u_long, caddr_t); 110void egrecv(struct eg_softc *); 111void egstart(struct ifnet *); 112void egwatchdog(struct ifnet *); 113void egreset(struct eg_softc *); 114void egread(struct eg_softc *, caddr_t, int); 115struct mbuf *egget(struct eg_softc *, caddr_t, int); 116void egstop(struct eg_softc *); 117 118static __inline void egprintpcb(struct eg_softc *); 119static int egoutPCB(struct eg_softc *, u_char); 120static int egreadPCBstat(struct eg_softc *, u_char); 121static int egreadPCBready(struct eg_softc *); 122static int egwritePCB(struct eg_softc *); 123static int egreadPCB(struct eg_softc *); 124 125/* 126 * Support stuff 127 */ 128 129static __inline void 130egprintpcb(struct eg_softc *sc) 131{ 132 int i; 133 134 for (i = 0; i < sc->eg_pcb[1] + 2; i++) 135 DPRINTF(("pcb[%2d] = %x\n", i, sc->eg_pcb[i])); 136} 137 138 139static int 140egoutPCB(struct eg_softc *sc, u_char b) 141{ 142 bus_space_tag_t bst = sc->sc_bst; 143 bus_space_handle_t bsh = sc->sc_bsh; 144 int i; 145 146 for (i = 0; i < 4000; i++) { 147 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE) { 148 bus_space_write_1(bst, bsh, EG_COMMAND, b); 149 return 0; 150 } 151 delay(10); 152 } 153 DPRINTF(("egoutPCB failed\n")); 154 return (1); 155} 156 157static int 158egreadPCBstat(struct eg_softc *sc, u_char statb) 159{ 160 bus_space_tag_t bst = sc->sc_bst; 161 bus_space_handle_t bsh = sc->sc_bsh; 162 int i; 163 164 for (i=0; i < 5000; i++) { 165 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) != 166 EG_PCB_NULL) 167 break; 168 delay(10); 169 } 170 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) == statb) 171 return (0); 172 return (1); 173} 174 175static int 176egreadPCBready(struct eg_softc *sc) 177{ 178 bus_space_tag_t bst = sc->sc_bst; 179 bus_space_handle_t bsh = sc->sc_bsh; 180 int i; 181 182 for (i=0; i < 10000; i++) { 183 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF) 184 return (0); 185 delay(5); 186 } 187 DPRINTF(("PCB read not ready status %02x\n", 188 bus_space_read_1(bst, bsh, EG_STATUS))); 189 return (1); 190} 191 192static int 193egwritePCB(struct eg_softc *sc) 194{ 195 bus_space_tag_t bst = sc->sc_bst; 196 bus_space_handle_t bsh = sc->sc_bsh; 197 int i; 198 u_char len; 199 200 bus_space_write_1(bst, bsh, EG_CONTROL, 201 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) | 202 EG_PCB_NULL); 203 204 len = sc->eg_pcb[1] + 2; 205 for (i = 0; i < len; i++) 206 egoutPCB(sc, sc->eg_pcb[i]); 207 208 for (i=0; i < 4000; i++) { 209 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE) 210 break; 211 delay(10); 212 } 213 214 bus_space_write_1(bst, bsh, EG_CONTROL, 215 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) | 216 EG_PCB_DONE); 217 218 egoutPCB(sc, len); 219 220 if (egreadPCBstat(sc, EG_PCB_ACCEPT)) 221 return (1); 222 return (0); 223} 224 225static int 226egreadPCB(struct eg_softc *sc) 227{ 228 bus_space_tag_t bst = sc->sc_bst; 229 bus_space_handle_t bsh = sc->sc_bsh; 230 int i; 231 u_char b; 232 233 bus_space_write_1(bst, bsh, EG_CONTROL, 234 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) | 235 EG_PCB_NULL); 236 237 bzero(sc->eg_pcb, sizeof(sc->eg_pcb)); 238 239 if (egreadPCBready(sc)) 240 return (1); 241 242 sc->eg_pcb[0] = bus_space_read_1(bst, bsh, EG_COMMAND); 243 244 if (egreadPCBready(sc)) 245 return (1); 246 247 sc->eg_pcb[1] = bus_space_read_1(bst, bsh, EG_COMMAND); 248 249 if (sc->eg_pcb[1] > 62) { 250 DPRINTF(("len %d too large\n", sc->eg_pcb[1])); 251 return (1); 252 } 253 254 for (i = 0; i < sc->eg_pcb[1]; i++) { 255 if (egreadPCBready(sc)) 256 return (1); 257 sc->eg_pcb[2+i] = bus_space_read_1(bst, bsh, EG_COMMAND); 258 } 259 if (egreadPCBready(sc)) 260 return (1); 261 if (egreadPCBstat(sc, EG_PCB_DONE)) 262 return (1); 263 if ((b = bus_space_read_1(bst, bsh, EG_COMMAND)) != sc->eg_pcb[1] + 2) { 264 DPRINTF(("%d != %d\n", b, sc->eg_pcb[1] + 2)); 265 return (1); 266 } 267 268 bus_space_write_1(bst, bsh, EG_CONTROL, 269 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) | 270 EG_PCB_ACCEPT); 271 272 return (0); 273} 274 275/* 276 * Real stuff 277 */ 278 279int 280egprobe(struct device *parent, void *match, void *aux) 281{ 282 struct eg_softc *sc = match; 283 struct isa_attach_args *ia = aux; 284 bus_space_tag_t bst = sc->sc_bst = ia->ia_iot; 285 bus_space_handle_t bsh; 286 int i; 287 288 if ((ia->ia_iobase & ~0x07f0) != 0) { 289 DPRINTF(("Weird iobase %x\n", ia->ia_iobase)); 290 return (0); 291 } 292 293 if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) { 294 DPRINTF(("%s: can't map i/o space\n", sc->sc_dev.dv_xname)); 295 return (0); 296 } 297 sc->sc_bsh = bsh; 298 299 /* hard reset card */ 300 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_RESET); 301 bus_space_write_1(bst, bsh, EG_CONTROL, 0); 302 for (i = 0; i < 5000; i++) { 303 delay(1000); 304 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) == 305 EG_PCB_NULL) 306 break; 307 } 308 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) != 309 EG_PCB_NULL) { 310 DPRINTF(("eg: Reset failed\n")); 311 goto lose; 312 } 313 sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */ 314 sc->eg_pcb[1] = 0; 315 if (egwritePCB(sc) != 0) 316 goto lose; 317 318 if (egreadPCB(sc) != 0) { 319 egprintpcb(sc); 320 goto lose; 321 } 322 323 if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */ 324 sc->eg_pcb[1] != 0x0a) { 325 egprintpcb(sc); 326 goto lose; 327 } 328 sc->eg_rom_major = sc->eg_pcb[3]; 329 sc->eg_rom_minor = sc->eg_pcb[2]; 330 sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8); 331 332 ia->ia_iosize = 0x08; 333 ia->ia_msize = 0; 334 bus_space_unmap(bst, bsh, EG_IO_PORTS); 335 return (1); 336 337lose: 338 bus_space_unmap(bst, bsh, EG_IO_PORTS); 339 return (0); 340} 341 342void 343egattach(struct device *parent, struct device *self, void *aux) 344{ 345 struct eg_softc *sc = (void *)self; 346 struct isa_attach_args *ia = aux; 347 bus_space_tag_t bst = sc->sc_bst = ia->ia_iot; 348 bus_space_handle_t bsh; 349 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 350 351 if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) { 352 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); 353 return; 354 } 355 sc->sc_bsh = bsh; 356 357 egstop(sc); 358 359 sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */ 360 sc->eg_pcb[1] = 0; 361 if (egwritePCB(sc) != 0) { 362 DPRINTF(("write error\n")); 363 return; 364 } 365 if (egreadPCB(sc) != 0) { 366 DPRINTF(("read error\n")); 367 egprintpcb(sc); 368 return; 369 } 370 371 /* check Get station address response */ 372 if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) { 373 DPRINTF(("parse error\n")); 374 egprintpcb(sc); 375 return; 376 } 377 bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); 378 379 printf(": ROM v%d.%02d %dk address %s\n", 380 sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram, 381 ether_sprintf(sc->sc_arpcom.ac_enaddr)); 382 383 sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */ 384 if (egwritePCB(sc) != 0) { 385 DPRINTF(("write error2\n")); 386 return; 387 } 388 if (egreadPCB(sc) != 0) { 389 DPRINTF(("read error2\n")); 390 egprintpcb(sc); 391 return; 392 } 393 if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 || 394 sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) { 395 DPRINTF(("parse error2\n")); 396 egprintpcb(sc); 397 return; 398 } 399 400 /* Initialize ifnet structure. */ 401 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 402 ifp->if_softc = sc; 403 ifp->if_start = egstart; 404 ifp->if_ioctl = egioctl; 405 ifp->if_watchdog = egwatchdog; 406 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 407 408 /* Now we can attach the interface. */ 409 if_attach(ifp); 410 ether_ifattach(ifp); 411 412 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 413 IPL_NET, egintr, sc, sc->sc_dev.dv_xname); 414} 415 416void 417eginit(register struct eg_softc *sc) 418{ 419 bus_space_tag_t bst = sc->sc_bst; 420 bus_space_handle_t bsh = sc->sc_bsh; 421 register struct ifnet *ifp = &sc->sc_arpcom.ac_if; 422 423 /* soft reset the board */ 424 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_FLSH); 425 delay(100); 426 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_ATTN); 427 delay(100); 428 bus_space_write_1(bst, bsh, EG_CONTROL, 0); 429 delay(200); 430 431 sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */ 432 sc->eg_pcb[1] = 2; 433 sc->eg_pcb[2] = 3; /* receive broadcast & multicast */ 434 sc->eg_pcb[3] = 0; 435 if (egwritePCB(sc) != 0) 436 DPRINTF(("write error3\n")); 437 438 if (egreadPCB(sc) != 0) { 439 DPRINTF(("read error3\n")); 440 egprintpcb(sc); 441 } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) 442 printf("%s: configure card command failed\n", 443 sc->sc_dev.dv_xname); 444 445 if (sc->eg_inbuf == 0) 446 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT); 447 sc->eg_incount = 0; 448 449 if (sc->eg_outbuf == 0) 450 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT); 451 452 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_CMDE); 453 454 sc->eg_incount = 0; 455 egrecv(sc); 456 457 /* Interface is now `running', with no output active. */ 458 ifp->if_flags |= IFF_RUNNING; 459 ifq_clr_oactive(&ifp->if_snd); 460 461 /* Attempt to start output, if any. */ 462 egstart(ifp); 463} 464 465void 466egrecv(struct eg_softc *sc) 467{ 468 while (sc->eg_incount < EG_INLEN) { 469 sc->eg_pcb[0] = EG_CMD_RECVPACKET; 470 sc->eg_pcb[1] = 0x08; 471 sc->eg_pcb[2] = 0; /* address not used.. we send zero */ 472 sc->eg_pcb[3] = 0; 473 sc->eg_pcb[4] = 0; 474 sc->eg_pcb[5] = 0; 475 sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */ 476 sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff; 477 sc->eg_pcb[8] = 0; /* timeout, 0 == none */ 478 sc->eg_pcb[9] = 0; 479 if (egwritePCB(sc) != 0) 480 break; 481 sc->eg_incount++; 482 } 483} 484 485void 486egstart(struct ifnet *ifp) 487{ 488 struct eg_softc *sc = ifp->if_softc; 489 bus_space_tag_t bst = sc->sc_bst; 490 bus_space_handle_t bsh = sc->sc_bsh; 491 struct mbuf *m0, *m; 492 caddr_t buffer; 493 int len; 494 u_short *ptr; 495 u_int i; 496 497 /* Don't transmit if interface is busy or not running */ 498 if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) 499 return; 500 501loop: 502 /* Dequeue the next datagram. */ 503 m0 = ifq_dequeue(&ifp->if_snd); 504 if (m0 == NULL) 505 return; 506 507 ifq_set_oactive(&ifp->if_snd); 508 509 /* We need to use m->m_pkthdr.len, so require the header */ 510 if ((m0->m_flags & M_PKTHDR) == 0) 511 panic("egstart: no header mbuf"); 512 len = max(m0->m_pkthdr.len, ETHER_MIN_LEN); 513 514#if NBPFILTER > 0 515 if (ifp->if_bpf) 516 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT); 517#endif 518 519 sc->eg_pcb[0] = EG_CMD_SENDPACKET; 520 sc->eg_pcb[1] = 0x06; 521 sc->eg_pcb[2] = 0; /* address not used, we send zero */ 522 sc->eg_pcb[3] = 0; 523 sc->eg_pcb[4] = 0; 524 sc->eg_pcb[5] = 0; 525 sc->eg_pcb[6] = len; /* length of packet */ 526 sc->eg_pcb[7] = len >> 8; 527 if (egwritePCB(sc) != 0) { 528 DPRINTF(("egwritePCB in egstart failed\n")); 529 ifp->if_oerrors++; 530 ifq_clr_oactive(&ifp->if_snd); 531 m_freem(m0); 532 goto loop; 533 } 534 535 buffer = sc->eg_outbuf; 536 for (m = m0; m != 0; m = m->m_next) { 537 bcopy(mtod(m, caddr_t), buffer, m->m_len); 538 buffer += m->m_len; 539 } 540 if (len > m0->m_pkthdr.len) 541 bzero(buffer, len - m0->m_pkthdr.len); 542 543 /* set direction bit: host -> adapter */ 544 bus_space_write_1(bst, bsh, EG_CONTROL, 545 bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_CTL_DIR); 546 547 for (ptr = (u_short *)sc->eg_outbuf; len > 0; len -= 2) { 548 bus_space_write_2(bst, bsh, EG_DATA, *ptr++); 549 for (i = 10000; i != 0; i--) { 550 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY) 551 break; 552 delay(10); 553 } 554 if (i == 0) { 555 printf("%s: start failed\n", sc->sc_dev.dv_xname); 556 break; 557 } 558 } 559 560 m_freem(m0); 561} 562 563int 564egintr(void *arg) 565{ 566 struct eg_softc *sc = arg; 567 bus_space_tag_t bst = sc->sc_bst; 568 bus_space_handle_t bsh = sc->sc_bsh; 569 int ret = 0; 570 int i, len; 571 u_short *ptr; 572 573 while (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF) { 574 ret = 1; 575 egreadPCB(sc); 576 switch (sc->eg_pcb[0]) { 577 case EG_RSP_RECVPACKET: 578 len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8); 579 580 /* Set direction bit : Adapter -> host */ 581 bus_space_write_1(bst, bsh, EG_CONTROL, 582 bus_space_read_1(bst, bsh, EG_CONTROL) | 583 EG_CTL_DIR); 584 585 for (ptr = (u_short *)sc->eg_inbuf; len > 0; len -= 2) { 586 for (i = 10000; i != 0; i--) { 587 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY) 588 break; 589 delay(10); 590 } 591 if (i == 0) { 592 printf("%s: receive failed\n", 593 sc->sc_dev.dv_xname); 594 break; 595 } 596 *ptr++ = bus_space_read_2(bst, bsh, EG_DATA); 597 } 598 599 if (len <= 0) { 600 len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8); 601 egread(sc, sc->eg_inbuf, len); 602 603 sc->eg_incount--; 604 egrecv(sc); 605 } 606 break; 607 608 case EG_RSP_SENDPACKET: 609 if (sc->eg_pcb[6] || sc->eg_pcb[7]) { 610 DPRINTF(("packet dropped\n")); 611 sc->sc_arpcom.ac_if.if_oerrors++; 612 } 613 sc->sc_arpcom.ac_if.if_collisions += 614 sc->eg_pcb[8] & 0xf; 615 ifq_clr_oactive(&sc->sc_arpcom.ac_if.if_snd); 616 egstart(&sc->sc_arpcom.ac_if); 617 break; 618 619 case EG_RSP_GETSTATS: 620 DPRINTF(("Card Statistics\n")); 621 bcopy(&sc->eg_pcb[2], &i, sizeof(i)); 622 DPRINTF(("Receive Packets %d\n", i)); 623 bcopy(&sc->eg_pcb[6], &i, sizeof(i)); 624 DPRINTF(("Transmit Packets %d\n", i)); 625 DPRINTF(("CRC errors %d\n", *(short *)&sc->eg_pcb[10])); 626 DPRINTF(("alignment errors %d\n", 627 *(short *)&sc->eg_pcb[12])); 628 DPRINTF(("no resources errors %d\n", 629 *(short *)&sc->eg_pcb[14])); 630 DPRINTF(("overrun errors %d\n", 631 *(short *)&sc->eg_pcb[16])); 632 break; 633 634 default: 635 DPRINTF(("egintr: Unknown response %x??\n", 636 sc->eg_pcb[0])); 637 egprintpcb(sc); 638 break; 639 } 640 } 641 642 return (ret); 643} 644 645/* 646 * Pass a packet up to the higher levels. 647 */ 648void 649egread(struct eg_softc *sc, caddr_t buf, int len) 650{ 651 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 652 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 653 struct mbuf *m; 654 655 if (len <= sizeof(struct ether_header) || 656 len > ETHER_MAX_LEN) { 657 printf("%s: invalid packet size %d; dropping\n", 658 sc->sc_dev.dv_xname, len); 659 ifp->if_ierrors++; 660 return; 661 } 662 663 /* Pull packet off interface. */ 664 m = egget(sc, buf, len); 665 if (m == NULL) { 666 ifp->if_ierrors++; 667 return; 668 } 669 670 ml_enqueue(&ml, m); 671 if_input(ifp, &ml); 672} 673 674/* 675 * convert buf into mbufs 676 */ 677struct mbuf * 678egget(struct eg_softc *sc, caddr_t buf, int totlen) 679{ 680 struct mbuf *top, **mp, *m; 681 int len; 682 683 MGETHDR(m, M_DONTWAIT, MT_DATA); 684 if (m == NULL) 685 return (0); 686 m->m_pkthdr.len = totlen; 687 len = MHLEN; 688 top = 0; 689 mp = ⊤ 690 691 while (totlen > 0) { 692 if (top) { 693 MGET(m, M_DONTWAIT, MT_DATA); 694 if (m == NULL) { 695 m_freem(top); 696 return (0); 697 } 698 len = MLEN; 699 } 700 if (totlen >= MINCLSIZE) { 701 MCLGET(m, M_DONTWAIT); 702 if (m->m_flags & M_EXT) 703 len = MCLBYTES; 704 } 705 m->m_len = len = min(totlen, len); 706 bcopy((caddr_t)buf, mtod(m, caddr_t), len); 707 buf += len; 708 totlen -= len; 709 *mp = m; 710 mp = &m->m_next; 711 } 712 713 return (top); 714} 715 716int 717egioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) 718{ 719 struct eg_softc *sc = ifp->if_softc; 720 int s, error = 0; 721 722 s = splnet(); 723 724 switch (cmd) { 725 case SIOCSIFADDR: 726 ifp->if_flags |= IFF_UP; 727 eginit(sc); 728 break; 729 730 case SIOCSIFFLAGS: 731 if ((ifp->if_flags & IFF_UP) == 0 && 732 (ifp->if_flags & IFF_RUNNING) != 0) { 733 /* 734 * If interface is marked down and it is running, then 735 * stop it. 736 */ 737 egstop(sc); 738 ifp->if_flags &= ~IFF_RUNNING; 739 } else if ((ifp->if_flags & IFF_UP) != 0 && 740 (ifp->if_flags & IFF_RUNNING) == 0) { 741 /* 742 * If interface is marked up and it is stopped, then 743 * start it. 744 */ 745 eginit(sc); 746 } else { 747 sc->eg_pcb[0] = EG_CMD_GETSTATS; 748 sc->eg_pcb[1] = 0; 749 if (egwritePCB(sc) != 0) 750 DPRINTF(("write error\n")); 751 /* 752 * XXX deal with flags changes: 753 * IFF_MULTICAST, IFF_PROMISC, 754 * IFF_LINK0, IFF_LINK1, 755 */ 756 } 757 break; 758 759 default: 760 error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data); 761 } 762 763 splx(s); 764 return (error); 765} 766 767void 768egreset(struct eg_softc *sc) 769{ 770 int s; 771 772 DPRINTF(("egreset()\n")); 773 s = splnet(); 774 egstop(sc); 775 eginit(sc); 776 splx(s); 777} 778 779void 780egwatchdog(struct ifnet *ifp) 781{ 782 struct eg_softc *sc = ifp->if_softc; 783 784 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); 785 sc->sc_arpcom.ac_if.if_oerrors++; 786 787 egreset(sc); 788} 789 790void 791egstop(register struct eg_softc *sc) 792{ 793 bus_space_tag_t bst = sc->sc_bst; 794 bus_space_handle_t bsh = sc->sc_bsh; 795 796 bus_space_write_1(bst, bsh, EG_CONTROL, 0); 797} 798