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