if_ec.c revision 1.13.10.1 1 /* $NetBSD: if_ec.c,v 1.13.10.1 2008/05/16 02:23:16 yamt 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.13.10.1 2008/05/16 02:23:16 yamt 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