1 /* $NetBSD: if_ec.c,v 1.3 2001/12/17 18:14:17 fredette Exp $ */ 2 3 /* 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matthew Fredette. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * 3Com 3C400 device driver 41 */ 42 43 #include "opt_inet.h" 44 #include "opt_ns.h" 45 #include "bpfilter.h" 46 #include "rnd.h" 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/errno.h> 51 #include <sys/ioctl.h> 52 #include <sys/mbuf.h> 53 #include <sys/socket.h> 54 #include <sys/syslog.h> 55 #include <sys/device.h> 56 #include <sys/endian.h> 57 #if NRND > 0 58 #include <sys/rnd.h> 59 #endif 60 61 #include <net/if.h> 62 #include <net/if_dl.h> 63 #include <net/if_types.h> 64 65 #include <net/if_ether.h> 66 #include <net/if_media.h> 67 68 #ifdef INET 69 #include <netinet/in.h> 70 #include <netinet/in_systm.h> 71 #include <netinet/in_var.h> 72 #include <netinet/ip.h> 73 #include <netinet/if_inarp.h> 74 #endif 75 76 #ifdef NS 77 #include <netns/ns.h> 78 #include <netns/ns_if.h> 79 #endif 80 81 #if NBPFILTER > 0 82 #include <net/bpf.h> 83 #include <net/bpfdesc.h> 84 #endif 85 86 #include <machine/cpu.h> 87 #include <machine/autoconf.h> 88 #include <machine/idprom.h> 89 #include <machine/bus.h> 90 #include <machine/intr.h> 91 92 #include <sun2/dev/if_ecreg.h> 93 94 /* 95 * Interface softc. 96 */ 97 struct ec_softc { 98 struct device sc_dev; 99 void *sc_ih; 100 101 struct ethercom sc_ethercom; /* ethernet common */ 102 struct ifmedia sc_media; /* our supported media */ 103 104 bus_space_tag_t sc_iot; /* bus space tag */ 105 bus_space_handle_t sc_ioh; /* bus space handle */ 106 107 u_char sc_jammed; /* nonzero if the net is jammed */ 108 u_char sc_colliding; /* nonzero if the net is colliding */ 109 u_int32_t sc_backoff_seed; /* seed for the backoff PRNG */ 110 111 #if NRND > 0 112 rndsource_element_t rnd_source; 113 #endif 114 }; 115 116 /* Macros to read and write the CSR. */ 117 #define ECREG_CSR_RD bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECREG_CSR) 118 #define ECREG_CSR_WR(val) bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_CSR, val) 119 120 /* After this many collisions, the packet is dropped. */ 121 #define EC_COLLISIONS_JAMMED 16 122 123 /* 124 * Various constants used in the backoff pseudorandom 125 * number generator. 126 */ 127 #define EC_BACKOFF_PRNG_COLL_MAX 10 128 #define EC_BACKOFF_PRNG_MUL 1103515245 129 #define EC_BACKOFF_PRNG_ADD 12345 130 #define EC_BACKOFF_PRNG_MASK 0x7fffffff 131 132 /* 133 * Prototypes 134 */ 135 int ec_intr __P((void *)); 136 void ec_reset __P((struct ifnet *)); 137 int ec_init __P((struct ifnet *)); 138 int ec_ioctl __P((struct ifnet *, u_long, caddr_t)); 139 void ec_watchdog __P((struct ifnet *)); 140 void ec_start __P((struct ifnet *)); 141 142 void ec_recv __P((struct ec_softc *, int)); 143 void ec_coll __P((struct ec_softc *)); 144 void ec_copyin __P((struct ec_softc *, void *, int, size_t)); 145 void ec_copyout __P((struct ec_softc *, const void *, int, size_t)); 146 147 int ec_mediachange __P((struct ifnet *)); 148 void ec_mediastatus __P((struct ifnet *, struct ifmediareq *)); 149 150 int ec_match __P((struct device *, struct cfdata *, void *)); 151 void ec_attach __P((struct device *, struct device *, void *)); 152 153 struct cfattach ec_ca = { 154 sizeof(struct ec_softc), ec_match, ec_attach 155 }; 156 157 /* 158 * Copy board memory to kernel. 159 */ 160 void 161 ec_copyin(sc, p, offset, size) 162 struct ec_softc *sc; 163 void *p; 164 int offset; 165 size_t size; 166 { 167 bus_space_copyin(sc->sc_iot, sc->sc_ioh, offset, p, size); 168 } 169 170 /* 171 * Copy from kernel space to board memory. 172 */ 173 void 174 ec_copyout(sc, p, offset, size) 175 struct ec_softc *sc; 176 const void *p; 177 int offset; 178 size_t size; 179 { 180 bus_space_copyout(sc->sc_iot, sc->sc_ioh, offset, p, size); 181 } 182 183 int 184 ec_match(parent, match, aux) 185 struct device *parent; 186 struct cfdata *match; 187 void *aux; 188 { 189 struct mbmem_attach_args *mbma = aux; 190 bus_space_handle_t bh; 191 int matched; 192 193 /* No default Multibus address. */ 194 if (mbma->mbma_paddr == -1) 195 return (0); 196 197 /* Make sure there is something there... */ 198 if (bus_space_map(mbma->mbma_bustag, mbma->mbma_paddr, ECREG_BANK_SZ, 199 0, &bh)) 200 return (0); 201 matched = (bus_space_peek_2(mbma->mbma_bustag, bh, 0, NULL) == 0); 202 bus_space_unmap(mbma->mbma_bustag, bh, ECREG_BANK_SZ); 203 if (!matched) 204 return (0); 205 206 /* Default interrupt priority. */ 207 if (mbma->mbma_pri == -1) 208 mbma->mbma_pri = 3; 209 210 return (1); 211 } 212 213 void 214 ec_attach(parent, self, aux) 215 struct device *parent, *self; 216 void *aux; 217 { 218 struct ec_softc *sc = (void *) self; 219 struct mbmem_attach_args *mbma = aux; 220 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 221 u_int8_t myaddr[ETHER_ADDR_LEN]; 222 223 printf("\n"); 224 225 /* Map in the board control regs. */ 226 sc->sc_iot = mbma->mbma_bustag; 227 if (bus_space_map(mbma->mbma_bustag, mbma->mbma_paddr, ECREG_BANK_SZ, 228 0, &sc->sc_ioh)) 229 panic("ec_attach: can't map regs"); 230 231 /* Reset the board. */ 232 ECREG_CSR_WR(EC_CSR_RESET); 233 delay(160); 234 235 /* 236 * Copy out the board ROM Ethernet address, 237 * and use the non-vendor-ID part to seed 238 * our backoff pseudorandom number generator. 239 */ 240 bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, ECREG_AROM, myaddr, ETHER_ADDR_LEN); 241 sc->sc_backoff_seed = (myaddr[3] << 16) | (myaddr[4] << 8) | (myaddr[5]) | 1; 242 243 /* Initialize ifnet structure. */ 244 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 245 ifp->if_softc = sc; 246 ifp->if_start = ec_start; 247 ifp->if_ioctl = ec_ioctl; 248 ifp->if_init = ec_init; 249 ifp->if_watchdog = ec_watchdog; 250 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 251 IFQ_SET_READY(&ifp->if_snd); 252 253 /* Initialize ifmedia structures. */ 254 ifmedia_init(&sc->sc_media, 0, ec_mediachange, ec_mediastatus); 255 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 256 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); 257 258 /* Now we can attach the interface. */ 259 if_attach(ifp); 260 idprom_etheraddr(myaddr); 261 ether_ifattach(ifp, myaddr); 262 printf("%s: address %s\n", self->dv_xname, ether_sprintf(myaddr)); 263 264 bus_intr_establish(mbma->mbma_bustag, mbma->mbma_pri, IPL_NET, 0, 265 ec_intr, sc); 266 267 #if NRND > 0 268 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname, 269 RND_TYPE_NET, 0); 270 #endif 271 } 272 273 /* 274 * Reset interface. 275 */ 276 void 277 ec_reset(ifp) 278 struct ifnet *ifp; 279 { 280 int s; 281 282 s = splnet(); 283 ec_init(ifp); 284 splx(s); 285 } 286 287 288 /* 289 * Initialize interface. 290 */ 291 int 292 ec_init(ifp) 293 struct ifnet *ifp; 294 { 295 struct ec_softc *sc = ifp->if_softc; 296 297 /* Reset the board. */ 298 ECREG_CSR_WR(EC_CSR_RESET); 299 delay(160); 300 301 /* Set the Ethernet address. */ 302 bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, ECREG_ARAM, LLADDR(sc->sc_ethercom.ec_if.if_sadl), ETHER_ADDR_LEN); 303 ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_AMSW); 304 ECREG_CSR_WR(ECREG_CSR_RD & 0); 305 306 /* Enable interrupts. */ 307 ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_BINT | EC_CSR_AINT | (ifp->if_flags & IFF_PROMISC ? EC_CSR_PROMISC : EC_CSR_PA)); 308 309 /* Set flags appropriately. */ 310 ifp->if_flags |= IFF_RUNNING; 311 ifp->if_flags &= ~IFF_OACTIVE; 312 313 /* Start output. */ 314 ec_start(ifp); 315 316 return (0); 317 } 318 319 /* 320 * Start output on interface. 321 */ 322 void 323 ec_start(ifp) 324 struct ifnet *ifp; 325 { 326 struct ec_softc *sc = ifp->if_softc; 327 struct mbuf *m, *m0; 328 int s; 329 u_int count; 330 bus_size_t off; 331 332 s = splnet(); 333 334 /* Don't do anything if output is active. */ 335 if ((ifp->if_flags & IFF_OACTIVE) != 0) { 336 splx(s); 337 return; 338 } 339 /* Don't do anything if the output queue is empty. */ 340 IFQ_DEQUEUE(&ifp->if_snd, m0); 341 if (m0 == NULL) { 342 splx(s); 343 return; 344 } 345 346 #if NBPFILTER > 0 347 /* The BPF tap. */ 348 if (ifp->if_bpf) 349 bpf_mtap(ifp->if_bpf, m0); 350 #endif 351 352 /* Size the packet. */ 353 for (count = EC_BUF_SZ, m = m0; m != NULL; m = m->m_next) 354 count -= m->m_len; 355 356 /* Copy the packet into the xmit buffer. */ 357 count = MIN(count, EC_PKT_MAXTDOFF); 358 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_TBUF, count); 359 for (off = count, m = m0; m != 0; off += m->m_len, m = m->m_next) 360 ec_copyout(sc, mtod(m, u_int8_t *), ECREG_TBUF + off, m->m_len); 361 m_freem(m0); 362 363 /* Enable the transmitter. */ 364 ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_PA) | EC_CSR_TBSW | EC_CSR_TINT | EC_CSR_JINT); 365 ifp->if_flags |= IFF_OACTIVE; 366 367 /* Done. */ 368 splx(s); 369 } 370 371 /* 372 * Controller interrupt. 373 */ 374 int 375 ec_intr(arg) 376 void *arg; 377 { 378 struct ec_softc *sc = arg; 379 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 380 int recv_first; 381 int recv_second; 382 int retval; 383 struct mbuf *m0; 384 385 retval = 0; 386 387 /* Check for received packet(s). */ 388 recv_first = recv_second = 0; 389 switch (ECREG_CSR_RD & (EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_RBBA)) { 390 391 case (EC_CSR_BBSW | EC_CSR_ABSW): 392 case (EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_RBBA): 393 /* Neither buffer is full. Is this a transmit interrupt? 394 * Acknowledge the interrupt ourselves. */ 395 ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_TINT | EC_CSR_JINT | EC_CSR_PAMASK)); 396 ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_BINT | EC_CSR_AINT); 397 break; 398 399 case EC_CSR_BBSW: 400 case (EC_CSR_BBSW | EC_CSR_RBBA): 401 /* Only the A buffer is full. */ 402 recv_first = EC_CSR_AINT; 403 break; 404 405 case EC_CSR_ABSW: 406 case (EC_CSR_ABSW | EC_CSR_RBBA): 407 /* Only the B buffer is full. */ 408 recv_first = EC_CSR_BINT; 409 break; 410 411 case 0: 412 /* Both the A buffer and the B buffer are full, and the A 413 * buffer is older than the B buffer. */ 414 recv_first = EC_CSR_AINT; 415 recv_second = EC_CSR_BINT; 416 break; 417 418 case EC_CSR_RBBA: 419 /* Both the A buffer and the B buffer are full, and the B 420 * buffer is older than the A buffer. */ 421 recv_first = EC_CSR_BINT; 422 recv_second = EC_CSR_AINT; 423 break; 424 } 425 426 /* Receive packets. */ 427 if (recv_first) { 428 429 /* Acknowledge the interrupt. */ 430 ECREG_CSR_WR(ECREG_CSR_RD & ((EC_CSR_BINT | EC_CSR_AINT | EC_CSR_TINT | EC_CSR_JINT | EC_CSR_PAMASK) ^ (recv_first | recv_second))); 431 432 /* Receive a packet. */ 433 ec_recv(sc, recv_first); 434 435 /* Receive a packet. */ 436 if (recv_second) 437 ec_recv(sc, recv_second); 438 439 retval++; 440 } 441 /* Check for a transmitted packet. */ 442 if (ifp->if_flags & IFF_OACTIVE) { 443 444 /* If we got a collision. */ 445 if (ECREG_CSR_RD & EC_CSR_JAM) { 446 ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK)); 447 sc->sc_ethercom.ec_if.if_collisions++; 448 retval++; 449 ec_coll(sc); 450 451 } 452 /* If we transmitted a packet. */ 453 else if ((ECREG_CSR_RD & EC_CSR_TBSW) == 0) { 454 ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK)); 455 retval++; 456 sc->sc_ethercom.ec_if.if_opackets++; 457 sc->sc_jammed = 0; 458 ifp->if_flags &= ~IFF_OACTIVE; 459 IFQ_POLL(&ifp->if_snd, m0); 460 if (m0 != NULL) 461 ec_start(ifp); 462 } 463 } else { 464 465 /* Make sure we disable transmitter interrupts. */ 466 ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK)); 467 } 468 469 return retval; 470 } 471 472 /* 473 * Read in a packet from the board. 474 */ 475 void 476 ec_recv(sc, intbit) 477 struct ec_softc *sc; 478 int intbit; 479 { 480 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 481 struct mbuf *m0, *m, *newm; 482 bus_size_t buf; 483 u_int16_t status; 484 u_int16_t doff; 485 int length, total_length; 486 487 buf = EC_CSR_INT_BUF(intbit); 488 489 /* Read in the packet status. */ 490 status = bus_space_read_2(sc->sc_iot, sc->sc_ioh, buf); 491 doff = status & EC_PKT_DOFF; 492 493 for (total_length = -1, m0 = 0;;) { 494 495 /* Check for an error. */ 496 if (status & (EC_PKT_FCSERR | EC_PKT_RGERR | EC_PKT_FRERR) || 497 doff < EC_PKT_MINRDOFF || 498 doff > EC_PKT_MAXRDOFF) { 499 printf("%s: garbled packet, status 0x%04x; dropping\n", 500 sc->sc_dev.dv_xname, (unsigned int) status); 501 break; 502 } 503 504 /* Adjust for the header. */ 505 total_length = doff - EC_PKT_RDOFF; 506 buf += EC_PKT_RDOFF; 507 508 /* XXX - sometimes the card reports a large data offset. */ 509 if (total_length > (ETHER_MAX_LEN - ETHER_CRC_LEN)) { 510 #ifdef DEBUG 511 printf("%s: fixing too-large length of %d\n", 512 sc->sc_dev.dv_xname, total_length); 513 #endif 514 total_length = (ETHER_MAX_LEN - ETHER_CRC_LEN); 515 } 516 517 MGETHDR(m0, M_DONTWAIT, MT_DATA); 518 if (m0 == 0) 519 break; 520 m0->m_pkthdr.rcvif = ifp; 521 m0->m_pkthdr.len = total_length; 522 length = MHLEN; 523 m = m0; 524 525 while (total_length > 0) { 526 if (total_length >= MINCLSIZE) { 527 MCLGET(m, M_DONTWAIT); 528 if ((m->m_flags & M_EXT) == 0) 529 break; 530 length = MCLBYTES; 531 } 532 m->m_len = length = min(total_length, length); 533 ec_copyin(sc, mtod(m, u_int8_t *), buf, length); 534 total_length -= length; 535 buf += length; 536 537 if (total_length > 0) { 538 MGET(newm, M_DONTWAIT, MT_DATA); 539 if (newm == 0) 540 break; 541 length = MLEN; 542 m = m->m_next = newm; 543 } 544 } 545 break; 546 } 547 548 if (total_length == 0) { 549 ifp->if_ipackets++; 550 551 #if NBPFILTER > 0 552 /* 553 * Check if there's a BPF listener on this interface. 554 * If so, hand off the raw packet to BPF. 555 */ 556 if (ifp->if_bpf) 557 bpf_mtap(ifp->if_bpf, m0); 558 #endif 559 560 /* Pass the packet up. */ 561 (*ifp->if_input) (ifp, m0); 562 563 } else { 564 /* Something went wrong. */ 565 if (m0) 566 m_freem(m0); 567 ifp->if_ierrors++; 568 } 569 570 /* Give the receive buffer back to the card. */ 571 buf = EC_CSR_INT_BUF(intbit); 572 bus_space_write_2(sc->sc_iot, sc->sc_ioh, buf, 0); 573 ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_INT_BSW(intbit) | intbit); 574 } 575 576 int 577 ec_mediachange(ifp) 578 struct ifnet *ifp; 579 { 580 return (0); 581 } 582 583 void 584 ec_mediastatus(ifp, ifmr) 585 struct ifnet *ifp; 586 struct ifmediareq *ifmr; 587 { 588 if ((ifp->if_flags & IFF_UP) == 0) 589 return; 590 591 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 592 } 593 594 /* 595 * Process an ioctl request. This code needs some work - it looks pretty ugly. 596 */ 597 int 598 ec_ioctl(ifp, cmd, data) 599 struct ifnet *ifp; 600 u_long cmd; 601 caddr_t data; 602 { 603 struct ifaddr *ifa = (struct ifaddr *) data; 604 struct ifreq *ifr = (struct ifreq *)data; 605 struct ec_softc *sc = ifp->if_softc; 606 int s, error = 0; 607 608 s = splnet(); 609 610 switch (cmd) { 611 612 case SIOCSIFADDR: 613 ifp->if_flags |= IFF_UP; 614 615 switch (ifa->ifa_addr->sa_family) { 616 #ifdef INET 617 case AF_INET: 618 ec_init(ifp); 619 arp_ifinit(ifp, ifa); 620 break; 621 #endif 622 #ifdef NS 623 /* XXX - This code is probably wrong. */ 624 case AF_NS: 625 { 626 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 627 628 if (ns_nullhost(*ina)) 629 ina->x_host = 630 *(union ns_host *) LLADDR(ifp->if_sadl); 631 else 632 bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl), 633 ETHER_ADDR_LEN); 634 /* Set new address. */ 635 ec_init(ifp); 636 break; 637 } 638 #endif 639 default: 640 ec_init(ifp); 641 break; 642 } 643 break; 644 645 case SIOCSIFFLAGS: 646 if ((ifp->if_flags & IFF_UP) == 0 && 647 (ifp->if_flags & IFF_RUNNING) != 0) { 648 /* 649 * If interface is marked down and it is running, then 650 * stop it. 651 */ 652 ifp->if_flags &= ~IFF_RUNNING; 653 } else if ((ifp->if_flags & IFF_UP) != 0 && 654 (ifp->if_flags & IFF_RUNNING) == 0) { 655 /* 656 * If interface is marked up and it is stopped, then 657 * start it. 658 */ 659 ec_init(ifp); 660 } else { 661 /* 662 * Some other important flag might have changed, so 663 * reset. 664 */ 665 ec_reset(ifp); 666 } 667 break; 668 669 case SIOCGIFMEDIA: 670 case SIOCSIFMEDIA: 671 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 672 break; 673 674 default: 675 error = EINVAL; 676 break; 677 } 678 679 splx(s); 680 return error; 681 } 682 683 /* 684 * Collision routine. 685 */ 686 void 687 ec_coll(sc) 688 struct ec_softc *sc; 689 { 690 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 691 u_short jams; 692 struct mbuf *m0; 693 694 if ((++sc->sc_colliding) >= EC_COLLISIONS_JAMMED) { 695 sc->sc_ethercom.ec_if.if_oerrors++; 696 if (!sc->sc_jammed) 697 printf("%s: ethernet jammed\n", 698 sc->sc_dev.dv_xname); 699 sc->sc_jammed = 1; 700 sc->sc_colliding = 0; 701 ifp->if_flags &= ~IFF_OACTIVE; 702 IFQ_POLL(&ifp->if_snd, m0); 703 if (m0 != NULL) 704 ec_start(ifp); 705 } else { 706 jams = MAX(sc->sc_colliding, EC_BACKOFF_PRNG_COLL_MAX); 707 sc->sc_backoff_seed = ((sc->sc_backoff_seed * EC_BACKOFF_PRNG_MUL) + EC_BACKOFF_PRNG_ADD) & EC_BACKOFF_PRNG_MASK; 708 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_BACKOFF, -(((sc->sc_backoff_seed >> 8) & ~(-1 << jams)) + 1)); 709 ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_JAM | EC_CSR_TINT | EC_CSR_JINT); 710 } 711 } 712 713 /* 714 * Device timeout routine. 715 */ 716 void 717 ec_watchdog(ifp) 718 struct ifnet *ifp; 719 { 720 struct ec_softc *sc = ifp->if_softc; 721 722 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); 723 sc->sc_ethercom.ec_if.if_oerrors++; 724 725 ec_reset(ifp); 726 } 727