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