FreeBSD/Linux Kernel Cross Reference
sys/dev/ex/if_ex.c
1 /*
2 * Copyright (c) 1996, Javier Martín Rueda (jmrueda@diatel.upm.es)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: releng/5.1/sys/dev/ex/if_ex.c 112801 2003-03-29 15:38:53Z mdodd $
28 *
29 * MAINTAINER: Matthew N. Dodd <winter@jurai.net>
30 * <mdodd@FreeBSD.org>
31 */
32
33 /*
34 * Intel EtherExpress Pro/10, Pro/10+ Ethernet driver
35 *
36 * Revision history:
37 *
38 * dd-mmm-yyyy: Multicast support ported from NetBSD's if_iy driver.
39 * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast.
40 */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/sockio.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48
49 #include <sys/module.h>
50 #include <sys/bus.h>
51
52 #include <machine/bus.h>
53 #include <machine/resource.h>
54 #include <sys/rman.h>
55
56 #include <net/if.h>
57 #include <net/if_arp.h>
58 #include <net/if_dl.h>
59 #include <net/if_media.h>
60 #include <net/ethernet.h>
61 #include <net/bpf.h>
62
63 #include <netinet/in.h>
64 #include <netinet/if_ether.h>
65
66
67 #include <isa/isavar.h>
68 #include <isa/pnpvar.h>
69
70 #include <dev/ex/if_exreg.h>
71 #include <dev/ex/if_exvar.h>
72
73 #ifdef EXDEBUG
74 # define Start_End 1
75 # define Rcvd_Pkts 2
76 # define Sent_Pkts 4
77 # define Status 8
78 static int debug_mask = 0;
79 static int exintr_count = 0;
80 # define DODEBUG(level, action) if (level & debug_mask) action
81 #else
82 # define DODEBUG(level, action)
83 #endif
84
85 devclass_t ex_devclass;
86
87 char irq2eemap[] =
88 { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 };
89 u_char ee2irqmap[] =
90 { 9, 3, 5, 10, 11, 0, 0, 0 };
91
92 char plus_irq2eemap[] =
93 { -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 };
94 u_char plus_ee2irqmap[] =
95 { 3, 4, 5, 7, 9, 10, 11, 12 };
96
97 /* Network Interface Functions */
98 static void ex_init (void *);
99 static void ex_start (struct ifnet *);
100 static int ex_ioctl (struct ifnet *, u_long, caddr_t);
101 static void ex_watchdog (struct ifnet *);
102
103 /* ifmedia Functions */
104 static int ex_ifmedia_upd (struct ifnet *);
105 static void ex_ifmedia_sts (struct ifnet *, struct ifmediareq *);
106
107 static int ex_get_media (u_int32_t iobase);
108
109 static void ex_reset (struct ex_softc *);
110 static void ex_setmulti (struct ex_softc *);
111
112 static void ex_tx_intr (struct ex_softc *);
113 static void ex_rx_intr (struct ex_softc *);
114
115 int
116 look_for_card (u_int32_t iobase)
117 {
118 int count1, count2;
119
120 /*
121 * Check for the i82595 signature, and check that the round robin
122 * counter actually advances.
123 */
124 if (((count1 = inb(iobase + ID_REG)) & Id_Mask) != Id_Sig)
125 return(0);
126 count2 = inb(iobase + ID_REG);
127 count2 = inb(iobase + ID_REG);
128 count2 = inb(iobase + ID_REG);
129
130 return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits));
131 }
132
133 void
134 ex_get_address (u_int32_t iobase, u_char *enaddr)
135 {
136 u_int16_t eaddr_tmp;
137
138 eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Lo);
139 enaddr[5] = eaddr_tmp & 0xff;
140 enaddr[4] = eaddr_tmp >> 8;
141 eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Mid);
142 enaddr[3] = eaddr_tmp & 0xff;
143 enaddr[2] = eaddr_tmp >> 8;
144 eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Hi);
145 enaddr[1] = eaddr_tmp & 0xff;
146 enaddr[0] = eaddr_tmp >> 8;
147
148 return;
149 }
150
151 int
152 ex_card_type (u_char *enaddr)
153 {
154 if ((enaddr[0] == 0x00) && (enaddr[1] == 0xA0) && (enaddr[2] == 0xC9))
155 return (CARD_TYPE_EX_10_PLUS);
156
157 return (CARD_TYPE_EX_10);
158 }
159
160 /*
161 * Caller is responsible for eventually calling
162 * ex_release_resources() on failure.
163 */
164 int
165 ex_alloc_resources (device_t dev)
166 {
167 struct ex_softc * sc = device_get_softc(dev);
168 int error = 0;
169
170 sc->ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->ioport_rid,
171 0, ~0, 1, RF_ACTIVE);
172 if (!sc->ioport) {
173 device_printf(dev, "No I/O space?!\n");
174 error = ENOMEM;
175 goto bad;
176 }
177
178 sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid,
179 0, ~0, 1, RF_ACTIVE);
180
181 if (!sc->irq) {
182 device_printf(dev, "No IRQ?!\n");
183 error = ENOMEM;
184 goto bad;
185 }
186
187 bad:
188 return (error);
189 }
190
191 void
192 ex_release_resources (device_t dev)
193 {
194 struct ex_softc * sc = device_get_softc(dev);
195
196 if (sc->ih) {
197 bus_teardown_intr(dev, sc->irq, sc->ih);
198 sc->ih = NULL;
199 }
200
201 if (sc->ioport) {
202 bus_release_resource(dev, SYS_RES_IOPORT,
203 sc->ioport_rid, sc->ioport);
204 sc->ioport = NULL;
205 }
206
207 if (sc->irq) {
208 bus_release_resource(dev, SYS_RES_IRQ,
209 sc->irq_rid, sc->irq);
210 sc->irq = NULL;
211 }
212
213 return;
214 }
215
216 int
217 ex_attach(device_t dev)
218 {
219 struct ex_softc * sc = device_get_softc(dev);
220 struct ifnet * ifp = &sc->arpcom.ac_if;
221 struct ifmedia * ifm;
222 int unit = device_get_unit(dev);
223 u_int16_t temp;
224
225 /* work out which set of irq <-> internal tables to use */
226 if (ex_card_type(sc->arpcom.ac_enaddr) == CARD_TYPE_EX_10_PLUS) {
227 sc->irq2ee = plus_irq2eemap;
228 sc->ee2irq = plus_ee2irqmap;
229 } else {
230 sc->irq2ee = irq2eemap;
231 sc->ee2irq = ee2irqmap;
232 }
233
234 sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card itself. */
235
236 /*
237 * Initialize the ifnet structure.
238 */
239 ifp->if_softc = sc;
240 ifp->if_unit = unit;
241 ifp->if_name = "ex";
242 ifp->if_mtu = ETHERMTU;
243 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
244 ifp->if_output = ether_output;
245 ifp->if_start = ex_start;
246 ifp->if_ioctl = ex_ioctl;
247 ifp->if_watchdog = ex_watchdog;
248 ifp->if_init = ex_init;
249 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
250
251 ifmedia_init(&sc->ifmedia, 0, ex_ifmedia_upd, ex_ifmedia_sts);
252
253 temp = eeprom_read(sc->iobase, EE_W5);
254 if (temp & EE_W5_PORT_TPE)
255 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
256 if (temp & EE_W5_PORT_BNC)
257 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL);
258 if (temp & EE_W5_PORT_AUI)
259 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
260
261 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
262 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL);
263 ifmedia_set(&sc->ifmedia, ex_get_media(sc->iobase));
264
265 ifm = &sc->ifmedia;
266 ifm->ifm_media = ifm->ifm_cur->ifm_media;
267 ex_ifmedia_upd(ifp);
268
269 /*
270 * Attach the interface.
271 */
272 ether_ifattach(ifp, sc->arpcom.ac_enaddr);
273
274 device_printf(sc->dev, "Ethernet address %6D\n",
275 sc->arpcom.ac_enaddr, ":");
276
277 return(0);
278 }
279
280 int
281 ex_detach (device_t dev)
282 {
283 struct ex_softc *sc;
284 struct ifnet *ifp;
285
286 sc = device_get_softc(dev);
287 ifp = &sc->arpcom.ac_if;
288
289 ex_stop(sc);
290
291 ifp->if_flags &= ~IFF_RUNNING;
292 ether_ifdetach(ifp);
293
294 ex_release_resources(dev);
295
296 return (0);
297 }
298
299 static void
300 ex_init(void *xsc)
301 {
302 struct ex_softc * sc = (struct ex_softc *) xsc;
303 struct ifnet * ifp = &sc->arpcom.ac_if;
304 int s;
305 int i;
306 register int iobase = sc->iobase;
307 unsigned short temp_reg;
308
309 DODEBUG(Start_End, printf("ex_init%d: start\n", ifp->if_unit););
310
311 if (TAILQ_FIRST(&ifp->if_addrhead) == NULL) {
312 return;
313 }
314 s = splimp();
315 ifp->if_timer = 0;
316
317 /*
318 * Load the ethernet address into the card.
319 */
320 outb(iobase + CMD_REG, Bank2_Sel);
321 temp_reg = inb(iobase + EEPROM_REG);
322 if (temp_reg & Trnoff_Enable) {
323 outb(iobase + EEPROM_REG, temp_reg & ~Trnoff_Enable);
324 }
325 for (i = 0; i < ETHER_ADDR_LEN; i++) {
326 outb(iobase + I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]);
327 }
328 /*
329 * - Setup transmit chaining and discard bad received frames.
330 * - Match broadcast.
331 * - Clear test mode.
332 * - Set receiving mode.
333 * - Set IRQ number.
334 */
335 outb(iobase + REG1, inb(iobase + REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr);
336 outb(iobase + REG2, inb(iobase + REG2) | No_SA_Ins | RX_CRC_InMem);
337 outb(iobase + REG3, inb(iobase + REG3) & 0x3f /* XXX constants. */ );
338 outb(iobase + CMD_REG, Bank1_Sel);
339 outb(iobase + INT_NO_REG, (inb(iobase + INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]);
340
341 /*
342 * Divide the available memory in the card into rcv and xmt buffers.
343 * By default, I use the first 3/4 of the memory for the rcv buffer,
344 * and the remaining 1/4 of the memory for the xmt buffer.
345 */
346 sc->rx_mem_size = sc->mem_size * 3 / 4;
347 sc->tx_mem_size = sc->mem_size - sc->rx_mem_size;
348 sc->rx_lower_limit = 0x0000;
349 sc->rx_upper_limit = sc->rx_mem_size - 2;
350 sc->tx_lower_limit = sc->rx_mem_size;
351 sc->tx_upper_limit = sc->mem_size - 2;
352 outb(iobase + RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8);
353 outb(iobase + RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8);
354 outb(iobase + XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8);
355 outb(iobase + XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8);
356
357 /*
358 * Enable receive and transmit interrupts, and clear any pending int.
359 */
360 outb(iobase + REG1, inb(iobase + REG1) | TriST_INT);
361 outb(iobase + CMD_REG, Bank0_Sel);
362 outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
363 outb(iobase + STATUS_REG, All_Int);
364
365 /*
366 * Initialize receive and transmit ring buffers.
367 */
368 outw(iobase + RCV_BAR, sc->rx_lower_limit);
369 sc->rx_head = sc->rx_lower_limit;
370 outw(iobase + RCV_STOP_REG, sc->rx_upper_limit | 0xfe);
371 outw(iobase + XMT_BAR, sc->tx_lower_limit);
372 sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
373
374 ifp->if_flags |= IFF_RUNNING;
375 ifp->if_flags &= ~IFF_OACTIVE;
376 DODEBUG(Status, printf("OIDLE init\n"););
377
378 ex_setmulti(sc);
379
380 /*
381 * Final reset of the board, and enable operation.
382 */
383 outb(iobase + CMD_REG, Sel_Reset_CMD);
384 DELAY(2);
385 outb(iobase + CMD_REG, Rcv_Enable_CMD);
386
387 ex_start(ifp);
388 splx(s);
389
390 DODEBUG(Start_End, printf("ex_init%d: finish\n", ifp->if_unit););
391 }
392
393
394 static void
395 ex_start(struct ifnet *ifp)
396 {
397 struct ex_softc * sc = ifp->if_softc;
398 int iobase = sc->iobase;
399 int i, s, len, data_len, avail, dest, next;
400 unsigned char tmp16[2];
401 struct mbuf * opkt;
402 struct mbuf * m;
403
404 DODEBUG(Start_End, printf("ex_start%d: start\n", unit););
405
406 s = splimp();
407
408 /*
409 * Main loop: send outgoing packets to network card until there are no
410 * more packets left, or the card cannot accept any more yet.
411 */
412 while (((opkt = ifp->if_snd.ifq_head) != NULL) &&
413 !(ifp->if_flags & IFF_OACTIVE)) {
414
415 /*
416 * Ensure there is enough free transmit buffer space for
417 * this packet, including its header. Note: the header
418 * cannot wrap around the end of the transmit buffer and
419 * must be kept together, so we allow space for twice the
420 * length of the header, just in case.
421 */
422
423 for (len = 0, m = opkt; m != NULL; m = m->m_next) {
424 len += m->m_len;
425 }
426
427 data_len = len;
428
429 DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len););
430
431 if (len & 1) {
432 len += XMT_HEADER_LEN + 1;
433 } else {
434 len += XMT_HEADER_LEN;
435 }
436
437 if ((i = sc->tx_tail - sc->tx_head) >= 0) {
438 avail = sc->tx_mem_size - i;
439 } else {
440 avail = -i;
441 }
442
443 DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail););
444
445 if (avail >= len + XMT_HEADER_LEN) {
446 IF_DEQUEUE(&ifp->if_snd, opkt);
447
448 #ifdef EX_PSA_INTR
449 /*
450 * Disable rx and tx interrupts, to avoid corruption
451 * of the host address register by interrupt service
452 * routines.
453 * XXX Is this necessary with splimp() enabled?
454 */
455 outb(iobase + MASK_REG, All_Int);
456 #endif
457
458 /*
459 * Compute the start and end addresses of this
460 * frame in the tx buffer.
461 */
462 dest = sc->tx_tail;
463 next = dest + len;
464
465 if (next > sc->tx_upper_limit) {
466 if ((sc->tx_upper_limit + 2 - sc->tx_tail) <=
467 XMT_HEADER_LEN) {
468 dest = sc->tx_lower_limit;
469 next = dest + len;
470 } else {
471 next = sc->tx_lower_limit +
472 next - sc->tx_upper_limit - 2;
473 }
474 }
475
476 /*
477 * Build the packet frame in the card's ring buffer.
478 */
479 DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next););
480
481 outw(iobase + HOST_ADDR_REG, dest);
482 outw(iobase + IO_PORT_REG, Transmit_CMD);
483 outw(iobase + IO_PORT_REG, 0);
484 outw(iobase + IO_PORT_REG, next);
485 outw(iobase + IO_PORT_REG, data_len);
486
487 /*
488 * Output the packet data to the card. Ensure all
489 * transfers are 16-bit wide, even if individual
490 * mbufs have odd length.
491 */
492
493 for (m = opkt, i = 0; m != NULL; m = m->m_next) {
494 DODEBUG(Sent_Pkts, printf("[%d]", m->m_len););
495 if (i) {
496 tmp16[1] = *(mtod(m, caddr_t));
497 outsw(iobase + IO_PORT_REG, tmp16, 1);
498 }
499 outsw(iobase + IO_PORT_REG,
500 mtod(m, caddr_t) + i, (m->m_len - i) / 2);
501
502 if ((i = (m->m_len - i) & 1) != 0) {
503 tmp16[0] = *(mtod(m, caddr_t) +
504 m->m_len - 1);
505 }
506 }
507 if (i) {
508 outsw(iobase + IO_PORT_REG, tmp16, 1);
509 }
510
511 /*
512 * If there were other frames chained, update the
513 * chain in the last one.
514 */
515 if (sc->tx_head != sc->tx_tail) {
516 if (sc->tx_tail != dest) {
517 outw(iobase + HOST_ADDR_REG,
518 sc->tx_last + XMT_Chain_Point);
519 outw(iobase + IO_PORT_REG, dest);
520 }
521 outw(iobase + HOST_ADDR_REG,
522 sc->tx_last + XMT_Byte_Count);
523 i = inw(iobase + IO_PORT_REG);
524 outw(iobase + HOST_ADDR_REG,
525 sc->tx_last + XMT_Byte_Count);
526 outw(iobase + IO_PORT_REG, i | Ch_bit);
527 }
528
529 /*
530 * Resume normal operation of the card:
531 * - Make a dummy read to flush the DRAM write
532 * pipeline.
533 * - Enable receive and transmit interrupts.
534 * - Send Transmit or Resume_XMT command, as
535 * appropriate.
536 */
537 inw(iobase + IO_PORT_REG);
538 #ifdef EX_PSA_INTR
539 outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
540 #endif
541 if (sc->tx_head == sc->tx_tail) {
542 outw(iobase + XMT_BAR, dest);
543 outb(iobase + CMD_REG, Transmit_CMD);
544 sc->tx_head = dest;
545 DODEBUG(Sent_Pkts, printf("Transmit\n"););
546 } else {
547 outb(iobase + CMD_REG, Resume_XMT_List_CMD);
548 DODEBUG(Sent_Pkts, printf("Resume\n"););
549 }
550
551 sc->tx_last = dest;
552 sc->tx_tail = next;
553
554 BPF_MTAP(ifp, opkt);
555
556 ifp->if_timer = 2;
557 ifp->if_opackets++;
558 m_freem(opkt);
559 } else {
560 ifp->if_flags |= IFF_OACTIVE;
561 DODEBUG(Status, printf("OACTIVE start\n"););
562 }
563 }
564
565 splx(s);
566
567 DODEBUG(Start_End, printf("ex_start%d: finish\n", unit););
568 }
569
570 void
571 ex_stop(struct ex_softc *sc)
572 {
573 int iobase = sc->iobase;
574
575 DODEBUG(Start_End, printf("ex_stop%d: start\n", unit););
576
577 /*
578 * Disable card operation:
579 * - Disable the interrupt line.
580 * - Flush transmission and disable reception.
581 * - Mask and clear all interrupts.
582 * - Reset the 82595.
583 */
584 outb(iobase + CMD_REG, Bank1_Sel);
585 outb(iobase + REG1, inb(iobase + REG1) & ~TriST_INT);
586 outb(iobase + CMD_REG, Bank0_Sel);
587 outb(iobase + CMD_REG, Rcv_Stop);
588 sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
589 sc->tx_last = 0; /* XXX I think these two lines are not necessary, because ex_init will always be called again to reinit the interface. */
590 outb(iobase + MASK_REG, All_Int);
591 outb(iobase + STATUS_REG, All_Int);
592 outb(iobase + CMD_REG, Reset_CMD);
593 DELAY(200);
594
595 DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit););
596
597 return;
598 }
599
600 void
601 ex_intr(void *arg)
602 {
603 struct ex_softc * sc = (struct ex_softc *)arg;
604 struct ifnet * ifp = &sc->arpcom.ac_if;
605 int iobase = sc->iobase;
606 int int_status, send_pkts;
607
608 DODEBUG(Start_End, printf("ex_intr%d: start\n", unit););
609
610 #ifdef EXDEBUG
611 if (++exintr_count != 1)
612 printf("WARNING: nested interrupt (%d). Mail the author.\n", exintr_count);
613 #endif
614
615 send_pkts = 0;
616 while ((int_status = inb(iobase + STATUS_REG)) & (Tx_Int | Rx_Int)) {
617 if (int_status & Rx_Int) {
618 outb(iobase + STATUS_REG, Rx_Int);
619
620 ex_rx_intr(sc);
621 } else if (int_status & Tx_Int) {
622 outb(iobase + STATUS_REG, Tx_Int);
623
624 ex_tx_intr(sc);
625 send_pkts = 1;
626 }
627 }
628
629 /*
630 * If any packet has been transmitted, and there are queued packets to
631 * be sent, attempt to send more packets to the network card.
632 */
633
634 if (send_pkts && (ifp->if_snd.ifq_head != NULL)) {
635 ex_start(ifp);
636 }
637
638 #ifdef EXDEBUG
639 exintr_count--;
640 #endif
641
642 DODEBUG(Start_End, printf("ex_intr%d: finish\n", unit););
643
644 return;
645 }
646
647 static void
648 ex_tx_intr(struct ex_softc *sc)
649 {
650 struct ifnet * ifp = &sc->arpcom.ac_if;
651 int iobase = sc->iobase;
652 int tx_status;
653
654 DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit););
655
656 /*
657 * - Cancel the watchdog.
658 * For all packets transmitted since last transmit interrupt:
659 * - Advance chain pointer to next queued packet.
660 * - Update statistics.
661 */
662
663 ifp->if_timer = 0;
664
665 while (sc->tx_head != sc->tx_tail) {
666 outw(iobase + HOST_ADDR_REG, sc->tx_head);
667
668 if (! inw(iobase + IO_PORT_REG) & Done_bit)
669 break;
670
671 tx_status = inw(iobase + IO_PORT_REG);
672 sc->tx_head = inw(iobase + IO_PORT_REG);
673
674 if (tx_status & TX_OK_bit) {
675 ifp->if_opackets++;
676 } else {
677 ifp->if_oerrors++;
678 }
679
680 ifp->if_collisions += tx_status & No_Collisions_bits;
681 }
682
683 /*
684 * The card should be ready to accept more packets now.
685 */
686
687 ifp->if_flags &= ~IFF_OACTIVE;
688
689 DODEBUG(Status, printf("OIDLE tx_intr\n"););
690 DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit););
691
692 return;
693 }
694
695 static void
696 ex_rx_intr(struct ex_softc *sc)
697 {
698 struct ifnet * ifp = &sc->arpcom.ac_if;
699 int iobase = sc->iobase;
700 int rx_status;
701 int pkt_len;
702 int QQQ;
703 struct mbuf * m;
704 struct mbuf * ipkt;
705 struct ether_header * eh;
706
707 DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit););
708
709 /*
710 * For all packets received since last receive interrupt:
711 * - If packet ok, read it into a new mbuf and queue it to interface,
712 * updating statistics.
713 * - If packet bad, just discard it, and update statistics.
714 * Finally, advance receive stop limit in card's memory to new location.
715 */
716
717 outw(iobase + HOST_ADDR_REG, sc->rx_head);
718
719 while (inw(iobase + IO_PORT_REG) == RCV_Done) {
720
721 rx_status = inw(iobase + IO_PORT_REG);
722 sc->rx_head = inw(iobase + IO_PORT_REG);
723 QQQ = pkt_len = inw(iobase + IO_PORT_REG);
724
725 if (rx_status & RCV_OK_bit) {
726 MGETHDR(m, M_DONTWAIT, MT_DATA);
727 ipkt = m;
728 if (ipkt == NULL) {
729 ifp->if_iqdrops++;
730 } else {
731 ipkt->m_pkthdr.rcvif = ifp;
732 ipkt->m_pkthdr.len = pkt_len;
733 ipkt->m_len = MHLEN;
734
735 while (pkt_len > 0) {
736 if (pkt_len > MINCLSIZE) {
737 MCLGET(m, M_DONTWAIT);
738 if (m->m_flags & M_EXT) {
739 m->m_len = MCLBYTES;
740 } else {
741 m_freem(ipkt);
742 ifp->if_iqdrops++;
743 goto rx_another;
744 }
745 }
746 m->m_len = min(m->m_len, pkt_len);
747
748 /*
749 * NOTE: I'm assuming that all mbufs allocated are of even length,
750 * except for the last one in an odd-length packet.
751 */
752
753 insw(iobase + IO_PORT_REG,
754 mtod(m, caddr_t), m->m_len / 2);
755
756 if (m->m_len & 1) {
757 *(mtod(m, caddr_t) + m->m_len - 1) = inb(iobase + IO_PORT_REG);
758 }
759 pkt_len -= m->m_len;
760
761 if (pkt_len > 0) {
762 MGET(m->m_next, M_DONTWAIT, MT_DATA);
763 if (m->m_next == NULL) {
764 m_freem(ipkt);
765 ifp->if_iqdrops++;
766 goto rx_another;
767 }
768 m = m->m_next;
769 m->m_len = MLEN;
770 }
771 }
772 eh = mtod(ipkt, struct ether_header *);
773 #ifdef EXDEBUG
774 if (debug_mask & Rcvd_Pkts) {
775 if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) {
776 printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":");
777 printf("%6D\n", eh->ether_dhost, ":");
778 } /* QQQ */
779 }
780 #endif
781 (*ifp->if_input)(ifp, ipkt);
782 ifp->if_ipackets++;
783 }
784 } else {
785 ifp->if_ierrors++;
786 }
787 outw(iobase + HOST_ADDR_REG, sc->rx_head);
788 rx_another: ;
789 }
790
791 if (sc->rx_head < sc->rx_lower_limit + 2)
792 outw(iobase + RCV_STOP_REG, sc->rx_upper_limit);
793 else
794 outw(iobase + RCV_STOP_REG, sc->rx_head - 2);
795
796 DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit););
797
798 return;
799 }
800
801
802 static int
803 ex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
804 {
805 struct ex_softc * sc = ifp->if_softc;
806 struct ifreq * ifr = (struct ifreq *)data;
807 int s;
808 int error = 0;
809
810 DODEBUG(Start_End, printf("ex_ioctl%d: start ", ifp->if_unit););
811
812 s = splimp();
813
814 switch(cmd) {
815 case SIOCSIFADDR:
816 case SIOCGIFADDR:
817 case SIOCSIFMTU:
818 error = ether_ioctl(ifp, cmd, data);
819 break;
820
821 case SIOCSIFFLAGS:
822 DODEBUG(Start_End, printf("SIOCSIFFLAGS"););
823 if ((ifp->if_flags & IFF_UP) == 0 &&
824 (ifp->if_flags & IFF_RUNNING)) {
825
826 ifp->if_flags &= ~IFF_RUNNING;
827 ex_stop(sc);
828 } else {
829 ex_init(sc);
830 }
831 break;
832 #ifdef NODEF
833 case SIOCGHWADDR:
834 DODEBUG(Start_End, printf("SIOCGHWADDR"););
835 bcopy((caddr_t)sc->sc_addr, (caddr_t)&ifr->ifr_data,
836 sizeof(sc->sc_addr));
837 break;
838 #endif
839 case SIOCADDMULTI:
840 case SIOCDELMULTI:
841 ex_init(sc);
842 error = 0;
843 break;
844 case SIOCSIFMEDIA:
845 case SIOCGIFMEDIA:
846 error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
847 break;
848 default:
849 DODEBUG(Start_End, printf("unknown"););
850 error = EINVAL;
851 }
852
853 splx(s);
854
855 DODEBUG(Start_End, printf("\nex_ioctl%d: finish\n", ifp->if_unit););
856
857 return(error);
858 }
859
860 static void
861 ex_setmulti(struct ex_softc *sc)
862 {
863 struct ifnet *ifp;
864 struct ifmultiaddr *maddr;
865 u_int16_t *addr;
866 int iobase = sc->iobase;
867 int count;
868 int timeout, status;
869
870 ifp = &sc->arpcom.ac_if;
871
872 count = 0;
873 TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
874 if (maddr->ifma_addr->sa_family != AF_LINK)
875 continue;
876 count++;
877 }
878
879 if ((ifp->if_flags & IFF_PROMISC) || (ifp->if_flags & IFF_ALLMULTI)
880 || count > 63) {
881 /* Interface is in promiscuous mode or there are too many
882 * multicast addresses for the card to handle */
883 outb(iobase + CMD_REG, Bank2_Sel);
884 outb(iobase + REG2, inb(iobase + REG2) | Promisc_Mode);
885 outb(iobase + REG3, inb(iobase + REG3));
886 outb(iobase + CMD_REG, Bank0_Sel);
887 }
888 else if ((ifp->if_flags & IFF_MULTICAST) && (count > 0)) {
889 /* Program multicast addresses plus our MAC address
890 * into the filter */
891 outb(iobase + CMD_REG, Bank2_Sel);
892 outb(iobase + REG2, inb(iobase + REG2) | Multi_IA);
893 outb(iobase + REG3, inb(iobase + REG3));
894 outb(iobase + CMD_REG, Bank0_Sel);
895
896 /* Borrow space from TX buffer; this should be safe
897 * as this is only called from ex_init */
898
899 outw(iobase + HOST_ADDR_REG, sc->tx_lower_limit);
900 outw(iobase + IO_PORT_REG, MC_Setup_CMD);
901 outw(iobase + IO_PORT_REG, 0);
902 outw(iobase + IO_PORT_REG, 0);
903 outw(iobase + IO_PORT_REG, (count + 1) * 6);
904
905 TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
906 if (maddr->ifma_addr->sa_family != AF_LINK)
907 continue;
908
909 addr = (u_int16_t*)LLADDR((struct sockaddr_dl *)
910 maddr->ifma_addr);
911 outw(iobase + IO_PORT_REG, *addr++);
912 outw(iobase + IO_PORT_REG, *addr++);
913 outw(iobase + IO_PORT_REG, *addr++);
914 }
915
916 /* Program our MAC address as well */
917 /* XXX: Is this necessary? The Linux driver does this
918 * but the NetBSD driver does not */
919 addr = (u_int16_t*)(&sc->arpcom.ac_enaddr);
920 outw(iobase + IO_PORT_REG, *addr++);
921 outw(iobase + IO_PORT_REG, *addr++);
922 outw(iobase + IO_PORT_REG, *addr++);
923
924 inw(iobase + IO_PORT_REG);
925 outw(iobase + XMT_BAR, sc->tx_lower_limit);
926 outb(iobase + CMD_REG, MC_Setup_CMD);
927
928 sc->tx_head = sc->tx_lower_limit;
929 sc->tx_tail = sc->tx_head + XMT_HEADER_LEN + (count + 1) * 6;
930
931 for (timeout=0; timeout<100; timeout++) {
932 DELAY(2);
933 if ((inb(iobase + STATUS_REG) & Exec_Int) == 0)
934 continue;
935
936 status = inb(iobase + CMD_REG);
937 outb(iobase + STATUS_REG, Exec_Int);
938 break;
939 }
940
941 sc->tx_head = sc->tx_tail;
942 }
943 else
944 {
945 /* No multicast or promiscuous mode */
946 outb(iobase + CMD_REG, Bank2_Sel);
947 outb(iobase + REG2, inb(iobase + REG2) & 0xDE);
948 /* ~(Multi_IA | Promisc_Mode) */
949 outb(iobase + REG3, inb(iobase + REG3));
950 outb(iobase + CMD_REG, Bank0_Sel);
951 }
952 }
953
954 static void
955 ex_reset(struct ex_softc *sc)
956 {
957 int s;
958
959 DODEBUG(Start_End, printf("ex_reset%d: start\n", unit););
960
961 s = splimp();
962
963 ex_stop(sc);
964 ex_init(sc);
965
966 splx(s);
967
968 DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit););
969
970 return;
971 }
972
973 static void
974 ex_watchdog(struct ifnet *ifp)
975 {
976 struct ex_softc * sc = ifp->if_softc;
977
978 DODEBUG(Start_End, printf("ex_watchdog%d: start\n", ifp->if_unit););
979
980 ifp->if_flags &= ~IFF_OACTIVE;
981
982 DODEBUG(Status, printf("OIDLE watchdog\n"););
983
984 ifp->if_oerrors++;
985 ex_reset(sc);
986 ex_start(ifp);
987
988 DODEBUG(Start_End, printf("ex_watchdog%d: finish\n", ifp->if_unit););
989
990 return;
991 }
992
993 static int
994 ex_get_media (u_int32_t iobase)
995 {
996 int current;
997 int media;
998
999 media = eeprom_read(iobase, EE_W5);
1000
1001 outb(iobase + CMD_REG, Bank2_Sel);
1002 current = inb(iobase + REG3);
1003 outb(iobase + CMD_REG, Bank0_Sel);
1004
1005 if ((current & TPE_bit) && (media & EE_W5_PORT_TPE))
1006 return(IFM_ETHER|IFM_10_T);
1007 if ((current & BNC_bit) && (media & EE_W5_PORT_BNC))
1008 return(IFM_ETHER|IFM_10_2);
1009
1010 if (media & EE_W5_PORT_AUI)
1011 return (IFM_ETHER|IFM_10_5);
1012
1013 return (IFM_ETHER|IFM_AUTO);
1014 }
1015
1016 static int
1017 ex_ifmedia_upd (ifp)
1018 struct ifnet * ifp;
1019 {
1020 struct ex_softc * sc = ifp->if_softc;
1021
1022 if (IFM_TYPE(sc->ifmedia.ifm_media) != IFM_ETHER)
1023 return EINVAL;
1024
1025 return (0);
1026 }
1027
1028 static void
1029 ex_ifmedia_sts(ifp, ifmr)
1030 struct ifnet * ifp;
1031 struct ifmediareq * ifmr;
1032 {
1033 struct ex_softc * sc = ifp->if_softc;
1034
1035 ifmr->ifm_active = ex_get_media(sc->iobase);
1036 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1037
1038 return;
1039 }
1040
1041 u_short
1042 eeprom_read(u_int32_t iobase, int location)
1043 {
1044 int i;
1045 u_short data = 0;
1046 int ee_addr;
1047 int read_cmd = location | EE_READ_CMD;
1048 short ctrl_val = EECS;
1049
1050 ee_addr = iobase + EEPROM_REG;
1051 outb(iobase + CMD_REG, Bank2_Sel);
1052 outb(ee_addr, EECS);
1053 for (i = 8; i >= 0; i--) {
1054 short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val;
1055 outb(ee_addr, outval);
1056 outb(ee_addr, outval | EESK);
1057 DELAY(3);
1058 outb(ee_addr, outval);
1059 DELAY(2);
1060 }
1061 outb(ee_addr, ctrl_val);
1062
1063 for (i = 16; i > 0; i--) {
1064 outb(ee_addr, ctrl_val | EESK);
1065 DELAY(3);
1066 data = (data << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
1067 outb(ee_addr, ctrl_val);
1068 DELAY(2);
1069 }
1070
1071 ctrl_val &= ~EECS;
1072 outb(ee_addr, ctrl_val | EESK);
1073 DELAY(3);
1074 outb(ee_addr, ctrl_val);
1075 DELAY(2);
1076 outb(iobase + CMD_REG, Bank0_Sel);
1077 return(data);
1078 }
Cache object: 7d1a69e6615b7890e4a771975c85f1fe
|