Annotation of sys/dev/isa/if_ex.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_ex.c,v 1.16 2007/06/06 09:44:30 henning Exp $ */
2: /*
3: * Copyright (c) 1997, Donald A. Schmidt
4: * Copyright (c) 1996, Javier Martín Rueda (jmrueda@diatel.upm.es)
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice unmodified, this list of conditions, and the following
12: * disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * Intel EtherExpress Pro/10 Ethernet driver
32: *
33: * Revision history:
34: *
35: * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast.
36: */
37:
38: #include "ex.h"
39: #if NEX > 0
40: #include "bpfilter.h"
41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/conf.h>
45: #include <sys/sockio.h>
46: #include <sys/mbuf.h>
47: #include <sys/socket.h>
48: #include <sys/device.h>
49:
50: #include <net/if.h>
51:
52: #ifdef INET
53: #include <netinet/in.h>
54: #include <netinet/if_ether.h>
55: #endif
56:
57: #if NBPFILTER > 0
58: #include <net/bpf.h>
59: #endif
60:
61: #include <machine/cpu.h>
62: #include <machine/bus.h>
63:
64: #include <dev/isa/isavar.h>
65: #include <dev/isa/if_exreg.h>
66:
67:
68: #ifdef EXDEBUG
69: #define Start_End 1
70: #define Rcvd_Pkts 2
71: #define Sent_Pkts 4
72: #define Status 8
73: static int debug_mask = 0;
74: static int exintr_count = 0;
75: #define DODEBUG(level, action) if (level & debug_mask) action
76: #else
77: #define DODEBUG(level, action)
78: #endif
79:
80:
81: #define Conn_BNC 1
82: #define Conn_TPE 2
83: #define Conn_AUI 3
84:
85: struct ex_softc {
86: struct arpcom arpcom; /* Ethernet common data */
87: int iobase; /* I/O base address. */
88: u_short connector; /* Connector type. */
89: u_short irq_no; /* IRQ number. */
90: u_int mem_size; /* Total memory size, in bytes. */
91: u_int rx_mem_size; /* Rx memory size (by default, first 3/4 of
92: total memory). */
93: u_int rx_lower_limit,
94: rx_upper_limit; /* Lower and upper limits of receive buffer. */
95: u_int rx_head; /* Head of receive ring buffer. */
96: u_int tx_mem_size; /* Tx memory size (by default, last quarter of
97: total memory). */
98: u_int tx_lower_limit,
99: tx_upper_limit; /* Lower and upper limits of transmit buffer. */
100: u_int tx_head, tx_tail; /* Head and tail of transmit ring buffer. */
101: u_int tx_last; /* Pointer to beginning of last frame in the
102: chain. */
103: bus_space_tag_t sc_iot; /* ISA i/o space tag */
104: bus_space_handle_t sc_ioh; /* ISA i/o space handle */
105: void *sc_ih; /* Device interrupt handler */
106: };
107:
108: /* static struct ex_softc ex_sc[NEX]; XXX would it be better to malloc(3)
109: the memory? */
110:
111: static char irq2eemap[] = { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1,
112: -1, -1 };
113: static u_char ee2irqmap[] = { 9, 3, 5, 10, 11, 0, 0, 0 };
114:
115: static int ex_probe(struct device *, void *, void *);
116: static void ex_attach(struct device *, struct device *, void *);
117: static void ex_init(struct ex_softc *);
118: static void ex_start(struct ifnet *);
119: static void ex_stop(struct ex_softc *);
120: static int ex_ioctl(struct ifnet *, u_long, caddr_t);
121: static void ex_reset(struct ex_softc *);
122: static void ex_watchdog(struct ifnet *);
123:
124: static u_short eeprom_read(struct ex_softc *, int);
125: static int look_for_card(struct isa_attach_args *, struct ex_softc *sc);
126: static int exintr(void *);
127: static void ex_tx_intr(struct ex_softc *);
128: static void ex_rx_intr(struct ex_softc *);
129:
130:
131: struct cfattach ex_ca = {
132: sizeof(struct ex_softc), ex_probe, ex_attach
133: };
134:
135: struct cfdriver ex_cd = {
136: NULL, "ex", DV_IFNET
137: };
138:
139: #define BANK_SEL(X) bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMD_REG, \
140: (X))
141: #define ISA_GET(offset) bus_space_read_1(sc->sc_iot, sc->sc_ioh, (offset))
142: #define ISA_PUT(offset, value) bus_space_write_1(sc->sc_iot, sc->sc_ioh, \
143: (offset), (value))
144: #define ISA_GET_2(offset) bus_space_read_2(sc->sc_iot, sc->sc_ioh, \
145: (offset))
146: #define ISA_PUT_2(offset, value) bus_space_write_2(sc->sc_iot, sc->sc_ioh, \
147: (offset), (value))
148: #define ISA_GET_2_MULTI(offset, addr, count) bus_space_read_multi_2( \
149: sc->sc_iot, sc->sc_ioh, (offset), (addr), (count))
150: #define ISA_PUT_2_MULTI(offset, addr, count) bus_space_write_multi_2( \
151: sc->sc_iot, sc->sc_ioh, (offset), (addr), (count))
152:
153:
154: static int
155: look_for_card(ia, sc)
156: struct isa_attach_args *ia;
157: struct ex_softc *sc;
158: {
159: int count1, count2;
160:
161: /*
162: * Check for the i82595 signature, and check that the round robin
163: * counter actually advances.
164: */
165: if (((count1 = ISA_GET(ID_REG)) & Id_Mask) != Id_Sig)
166: return(0);
167: count2 = ISA_GET(ID_REG);
168: count2 = ISA_GET(ID_REG);
169: count2 = ISA_GET(ID_REG);
170: if ((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits))
171: return(1);
172: else
173: return(0);
174: }
175:
176:
177: int
178: ex_probe(parent, match, aux)
179: struct device *parent;
180: void *match, *aux;
181: {
182: struct ex_softc *sc = match;
183: struct isa_attach_args *ia = aux;
184: u_short eaddr_tmp;
185: int tmp;
186:
187: DODEBUG(Start_End, printf("ex_probe: start\n"););
188:
189: if ((ia->ia_iobase >= 0x200) && (ia->ia_iobase <= 0x3a0)) {
190: sc->sc_iot = ia->ia_iot;
191: if(bus_space_map(sc->sc_iot, ia->ia_iobase, EX_IOSIZE, 0,
192: &sc->sc_ioh))
193: return(0);
194:
195: if (!look_for_card(ia, sc)) {
196: bus_space_unmap(sc->sc_iot, sc->sc_ioh, EX_IOSIZE);
197: return(0);
198: }
199: } else
200: return(0);
201:
202: ia->ia_iosize = EX_IOSIZE;
203:
204: /*
205: * Reset the card.
206: */
207: ISA_PUT(CMD_REG, Reset_CMD);
208: delay(200);
209:
210: /*
211: * Fill in several fields of the softc structure:
212: * - I/O base address.
213: * - Hardware Ethernet address.
214: * - IRQ number (if not supplied in config file, read it from
215: * EEPROM).
216: * - Connector type.
217: */
218: sc->iobase = ia->ia_iobase;
219: eaddr_tmp = eeprom_read(sc, EE_Eth_Addr_Lo);
220: sc->arpcom.ac_enaddr[5] = eaddr_tmp & 0xff;
221: sc->arpcom.ac_enaddr[4] = eaddr_tmp >> 8;
222: eaddr_tmp = eeprom_read(sc, EE_Eth_Addr_Mid);
223: sc->arpcom.ac_enaddr[3] = eaddr_tmp & 0xff;
224: sc->arpcom.ac_enaddr[2] = eaddr_tmp >> 8;
225: eaddr_tmp = eeprom_read(sc, EE_Eth_Addr_Hi);
226: sc->arpcom.ac_enaddr[1] = eaddr_tmp & 0xff;
227: sc->arpcom.ac_enaddr[0] = eaddr_tmp >> 8;
228: tmp = eeprom_read(sc, EE_IRQ_No) & IRQ_No_Mask;
229: if (ia->ia_irq > 0) {
230: if (ee2irqmap[tmp] != ia->ia_irq)
231: printf("ex: WARING: board's EEPROM is configured for IRQ %d, using %d\n", ee2irqmap[tmp], ia->ia_irq);
232: sc->irq_no = ia->ia_irq;
233: }
234: else {
235: sc->irq_no = ee2irqmap[tmp];
236: ia->ia_irq = sc->irq_no;
237: }
238: if (sc->irq_no == 0) {
239: printf("ex: invalid IRQ.\n");
240: return(0);
241: }
242: BANK_SEL(Bank2_Sel);
243: tmp = ISA_GET(REG3);
244: if (tmp & TPE_bit)
245: sc->connector = Conn_TPE;
246: else if (tmp & BNC_bit)
247: sc->connector = Conn_BNC;
248: else
249: sc->connector = Conn_AUI;
250: sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card
251: itself. */
252:
253: BANK_SEL(Bank0_Sel);
254:
255: DODEBUG(Start_End, printf("ex_probe: finish\n"););
256: return(1);
257: }
258:
259:
260: void
261: ex_attach(parent, self, aux)
262: struct device *parent, *self;
263: void *aux;
264: {
265: struct ex_softc *sc = (void *)self;
266: struct isa_attach_args *ia = aux;
267: struct ifnet *ifp = &sc->arpcom.ac_if;
268:
269: /* struct ifaddr *ifa; XXX what are these for? */
270: /* struct sockaddr_dl *sdl; */
271:
272: DODEBUG(Start_End, printf("ex_attach: start\n"););
273:
274: /*
275: * Initialize the ifnet structure.
276:
277: */
278: ifp->if_softc = sc;
279: bcopy(self->dv_xname, ifp->if_xname, IFNAMSIZ);
280: ifp->if_start = ex_start;
281: ifp->if_ioctl = ex_ioctl;
282: ifp->if_watchdog = ex_watchdog;
283: ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST; /* XXX not done yet.
284: | IFF_MULTICAST */
285: IFQ_SET_READY(&ifp->if_snd);
286:
287: /*
288: * Attach the interface.
289: */
290: if_attach(ifp);
291: ether_ifattach(ifp);
292: printf(": address %s, connecter ",
293: ether_sprintf(sc->arpcom.ac_enaddr));
294: switch(sc->connector) {
295: case Conn_TPE: printf("TPE\n"); break;
296: case Conn_BNC: printf("BNC\n"); break;
297: case Conn_AUI: printf("AUI\n"); break;
298: default: printf("???\n");
299: }
300:
301: sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
302: IPL_NET, exintr, sc, self->dv_xname);
303: ex_init(sc);
304:
305: DODEBUG(Start_End, printf("ex_attach: finish\n"););
306: }
307:
308:
309: void
310: ex_init(sc)
311: struct ex_softc *sc;
312: {
313: struct ifnet *ifp = &sc->arpcom.ac_if;
314: int s, i;
315: unsigned short temp_reg;
316:
317: DODEBUG(Start_End, printf("ex_init: start\n"););
318:
319: if (TAILQ_EMPTY(&ifp->if_addrlist))
320: return;
321: s = splnet();
322: sc->arpcom.ac_if.if_timer = 0;
323:
324: /*
325: * Load the ethernet address into the card.
326: */
327: BANK_SEL(Bank2_Sel);
328: temp_reg = ISA_GET(EEPROM_REG);
329: if (temp_reg & Trnoff_Enable)
330: ISA_PUT(EEPROM_REG, temp_reg & ~Trnoff_Enable);
331: for (i = 0; i < ETHER_ADDR_LEN; i++)
332: ISA_PUT(I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]);
333: /*
334: * - Setup transmit chaining and discard bad received frames.
335: * - Match broadcast.
336: * - Clear test mode.
337: * - Set receiving mode.
338: * - Set IRQ number.
339: */
340: ISA_PUT(REG1, ISA_GET(REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp |
341: Disc_Bad_Fr);
342: ISA_PUT(REG2, ISA_GET(REG2) | No_SA_Ins | RX_CRC_InMem);
343: ISA_PUT(REG3, (ISA_GET(REG3) & 0x3f));
344: BANK_SEL(Bank1_Sel);
345: ISA_PUT(INT_NO_REG, (ISA_GET(INT_NO_REG) & 0xf8) |
346: irq2eemap[sc->irq_no]);
347:
348: /*
349: * Divide the available memory in the card into rcv and xmt buffers.
350: * By default, I use the first 3/4 of the memory for the rcv buffer,
351: * and the remaining 1/4 of the memory for the xmt buffer.
352: */
353: sc->rx_mem_size = sc->mem_size * 3 / 4;
354: sc->tx_mem_size = sc->mem_size - sc->rx_mem_size;
355: sc->rx_lower_limit = 0x0000;
356: sc->rx_upper_limit = sc->rx_mem_size - 2;
357: sc->tx_lower_limit = sc->rx_mem_size;
358: sc->tx_upper_limit = sc->mem_size - 2;
359: ISA_PUT(RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8);
360: ISA_PUT(RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8);
361: ISA_PUT(XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8);
362: ISA_PUT(XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8);
363:
364: /*
365: * Enable receive and transmit interrupts, and clear any pending int.
366: */
367: ISA_PUT(REG1, ISA_GET(REG1) | TriST_INT);
368: BANK_SEL(Bank0_Sel);
369: ISA_PUT(MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
370: ISA_PUT(STATUS_REG, All_Int);
371:
372: /*
373: * Initialize receive and transmit ring buffers.
374: */
375: ISA_PUT_2(RCV_BAR, sc->rx_lower_limit);
376: sc->rx_head = sc->rx_lower_limit;
377: ISA_PUT_2(RCV_STOP_REG, sc->rx_upper_limit | 0xfe);
378: ISA_PUT_2(XMT_BAR, sc->tx_lower_limit);
379: sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
380:
381: ifp->if_flags |= IFF_RUNNING;
382: ifp->if_flags &= ~IFF_OACTIVE;
383: DODEBUG(Status, printf("OIDLE init\n"););
384:
385: /*
386: * Final reset of the board, and enable operation.
387: */
388: ISA_PUT(CMD_REG, Sel_Reset_CMD);
389: delay(2);
390: ISA_PUT(CMD_REG, Rcv_Enable_CMD);
391:
392: ex_start(ifp);
393: splx(s);
394:
395: DODEBUG(Start_End, printf("ex_init: finish\n"););
396: }
397:
398:
399: void
400: ex_start(ifp)
401: struct ifnet *ifp;
402: {
403: register struct ex_softc *sc = ifp->if_softc;
404: int i, s, len, data_len, avail, dest, next;
405: unsigned char tmp16[2];
406: struct mbuf *opkt;
407: register struct mbuf *m;
408:
409: DODEBUG(Start_End, printf("ex_start: start\n"););
410:
411: s = splnet();
412:
413: /*
414: * Main loop: send outgoing packets to network card until there are no
415: * more packets left, or the card cannot accept any more yet.
416: */
417: while (!(ifp->if_flags & IFF_OACTIVE)) {
418: IFQ_POLL(&ifp->if_snd, opkt);
419: if (opkt == NULL)
420: break;
421:
422: /*
423: * Ensure there is enough free transmit buffer space for this
424: * packet, including its header. Note: the header cannot wrap
425: * around the end of the transmit buffer and must be kept
426: * together, so we allow space for twice the length of the
427: * header, just in case.
428: */
429: for (len = 0, m = opkt; m != NULL; m = m->m_next)
430: len += m->m_len;
431: data_len = len;
432: DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len););
433: if (len & 1)
434: len += XMT_HEADER_LEN + 1;
435: else
436: len += XMT_HEADER_LEN;
437: if ((i = sc->tx_tail - sc->tx_head) >= 0)
438: avail = sc->tx_mem_size - i;
439: else
440: avail = -i;
441: DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail););
442: if (avail >= len + XMT_HEADER_LEN) {
443: IFQ_DEQUEUE(&ifp->if_snd, opkt);
444:
445: #ifdef EX_PSA_INTR
446: /*
447: * Disable rx and tx interrupts, to avoid corruption of
448: * the host address register by interrupt service
449: * routines. XXX Is this necessary with splnet()
450: * enabled?
451: */
452: ISA_WRITE(MASK_REG, All_Int);
453: #endif
454:
455: /*
456: * Compute the start and end addresses of this frame
457: * in the tx buffer.
458: */
459: dest = sc->tx_tail;
460: next = dest + len;
461: if (next > sc->tx_upper_limit) {
462: if ((sc->tx_upper_limit + 2 - sc->tx_tail) <=
463: XMT_HEADER_LEN) {
464: dest = sc->tx_lower_limit;
465: next = dest + len;
466: } else
467: next = sc->tx_lower_limit + next -
468: sc->tx_upper_limit - 2;
469: }
470:
471: /* Build the packet frame in the card's ring buffer. */
472: DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next););
473: ISA_PUT_2(HOST_ADDR_REG, dest);
474: ISA_PUT_2(IO_PORT_REG, Transmit_CMD);
475: ISA_PUT_2(IO_PORT_REG, 0);
476: ISA_PUT_2(IO_PORT_REG, next);
477: ISA_PUT_2(IO_PORT_REG, data_len);
478:
479: /*
480: * Output the packet data to the card. Ensure all
481: * transfers are 16-bit wide, even if individual mbufs
482: * have odd length.
483: */
484:
485: for (m = opkt, i = 0; m != NULL; m = m->m_next) {
486: DODEBUG(Sent_Pkts, printf("[%d]", m->m_len););
487: if (i) {
488: tmp16[1] = *(mtod(m, caddr_t));
489: ISA_PUT_2_MULTI(IO_PORT_REG, tmp16, 1);
490: }
491: ISA_PUT_2_MULTI(IO_PORT_REG, mtod(m, caddr_t)
492: + i, (m->m_len - i) / 2);
493: if ((i = (m->m_len - i) & 1))
494: tmp16[0] = *(mtod(m, caddr_t) +
495: m->m_len - 1);
496: }
497: if (i)
498: ISA_PUT_2_MULTI(IO_PORT_REG, tmp16, 1);
499:
500: /*
501: * If there were other frames chained, update the
502: * chain in the last one.
503: */
504: if (sc->tx_head != sc->tx_tail) {
505: if (sc->tx_tail != dest) {
506: ISA_PUT_2(HOST_ADDR_REG,
507: sc->tx_last + XMT_Chain_Point);
508: ISA_PUT_2(IO_PORT_REG, dest);
509: }
510: ISA_PUT_2(HOST_ADDR_REG, sc->tx_last +
511: XMT_Byte_Count);
512: i = ISA_GET_2(IO_PORT_REG);
513: ISA_PUT_2(HOST_ADDR_REG, sc->tx_last +
514: XMT_Byte_Count);
515: ISA_PUT_2(IO_PORT_REG, i | Ch_bit);
516: }
517:
518: /*
519: * Resume normal operation of the card:
520: * -Make a dummy read to flush the DRAM write pipeline.
521: * -Enable receive and transmit interrupts.
522: * -Send Transmit or Resume_XMT command, as appropriate.
523: */
524: ISA_GET_2(IO_PORT_REG);
525: #ifdef EX_PSA_INTR
526: ISA_PUT_2(MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
527: #endif
528: if (sc->tx_head == sc->tx_tail) {
529: ISA_PUT_2(XMT_BAR, dest);
530: ISA_PUT(CMD_REG, Transmit_CMD);
531: sc->tx_head = dest;
532: DODEBUG(Sent_Pkts, printf("Transmit\n"););
533: } else {
534: ISA_PUT(CMD_REG, Resume_XMT_List_CMD);
535: DODEBUG(Sent_Pkts, printf("Resume\n"););
536: }
537: sc->tx_last = dest;
538: sc->tx_tail = next;
539: #if NBPFILTER > 0
540: if (ifp->if_bpf != NULL)
541: bpf_mtap(ifp->if_bpf, opkt,
542: BPF_DIRECTION_OUT);
543: #endif
544: ifp->if_timer = 2;
545: ifp->if_opackets++;
546: m_freem(opkt);
547: } else {
548: ifp->if_flags |= IFF_OACTIVE;
549: DODEBUG(Status, printf("OACTIVE start\n"););
550: }
551: }
552:
553: splx(s);
554:
555: DODEBUG(Start_End, printf("ex_start: finish\n"););
556: }
557:
558:
559: void
560: ex_stop(sc)
561: struct ex_softc *sc;
562: {
563: DODEBUG(Start_End, printf("ex_stop: start\n"););
564:
565: /*
566: * Disable card operation:
567: * - Disable the interrupt line.
568: * - Flush transmission and disable reception.
569: * - Mask and clear all interrupts.
570: * - Reset the 82595.
571: */
572: BANK_SEL(Bank1_Sel);
573: ISA_PUT(REG1, ISA_GET(REG1) & ~TriST_INT);
574: BANK_SEL(Bank0_Sel);
575: ISA_PUT(CMD_REG, Rcv_Stop);
576: sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
577: sc->tx_last = 0; /* XXX I think these two lines are not necessary,
578: because ex_init will always be called again
579: to reinit the interface. */
580: ISA_PUT(MASK_REG, All_Int);
581: ISA_PUT(STATUS_REG, All_Int);
582: ISA_PUT(CMD_REG, Reset_CMD);
583: delay(200);
584:
585: DODEBUG(Start_End, printf("ex_stop: finish\n"););
586: }
587:
588:
589: int
590: exintr(arg)
591: void *arg;
592: {
593: struct ex_softc *sc = arg;
594: struct ifnet *ifp = &sc->arpcom.ac_if;
595: int int_status, send_pkts;
596: int handled;
597:
598: DODEBUG(Start_End, printf("exintr: start\n"););
599:
600: #ifdef EXDEBUG
601: if (++exintr_count != 1)
602: printf("WARNING: nested interrupt (%d). Mail the author.\n",
603: exintr_count);
604: #endif
605:
606: send_pkts = 0;
607: while ((int_status = ISA_GET(STATUS_REG)) & (Tx_Int | Rx_Int)) {
608: if (int_status & Rx_Int) {
609: ISA_PUT(STATUS_REG, Rx_Int);
610: handled = 1;
611: ex_rx_intr(sc);
612: } else if (int_status & Tx_Int) {
613: ISA_PUT(STATUS_REG, Tx_Int);
614: handled = 1;
615: ex_tx_intr(sc);
616: send_pkts = 1;
617: } else
618: handled = 0;
619: }
620:
621: /*
622: * If any packet has been transmitted, and there are queued packets to
623: * be sent, attempt to send more packets to the network card.
624: */
625:
626: if (send_pkts && IFQ_IS_EMPTY(&ifp->if_snd) == 0)
627: ex_start(ifp);
628: #ifdef EXDEBUG
629: exintr_count--;
630: #endif
631: DODEBUG(Start_End, printf("exintr: finish\n"););
632:
633: return handled;
634: }
635:
636:
637: void
638: ex_tx_intr(sc)
639: struct ex_softc *sc;
640: {
641: register struct ifnet *ifp = &sc->arpcom.ac_if;
642: int tx_status;
643:
644: DODEBUG(Start_End, printf("ex_tx_intr: start\n"););
645: /*
646: * - Cancel the watchdog.
647: * For all packets transmitted since last transmit interrupt:
648: * - Advance chain pointer to next queued packet.
649: * - Update statistics.
650: */
651: ifp->if_timer = 0;
652: while (sc->tx_head != sc->tx_tail) {
653: ISA_PUT_2(HOST_ADDR_REG, sc->tx_head);
654: if (! ISA_GET_2(IO_PORT_REG) & Done_bit)
655: break;
656: tx_status = ISA_GET_2(IO_PORT_REG);
657: sc->tx_head = ISA_GET_2(IO_PORT_REG);
658: if (tx_status & TX_OK_bit)
659: ifp->if_opackets++;
660: else
661: ifp->if_oerrors++;
662: ifp->if_collisions += tx_status & No_Collisions_bits;
663: }
664:
665: /* The card should be ready to accept more packets now. */
666: ifp->if_flags &= ~IFF_OACTIVE;
667: DODEBUG(Status, printf("OIDLE tx_intr\n"););
668:
669: DODEBUG(Start_End, printf("ex_tx_intr: finish\n"););
670: }
671:
672:
673: void
674: ex_rx_intr(sc)
675: struct ex_softc *sc;
676: {
677: register struct ifnet *ifp = &sc->arpcom.ac_if;
678: int rx_status, pkt_len, QQQ;
679: register struct mbuf *m, *ipkt;
680:
681: DODEBUG(Start_End, printf("ex_rx_intr: start\n"););
682: /*
683: * For all packets received since last receive interrupt:
684: * - If packet ok, read it into a new mbuf and queue it to interface,
685: * updating statistics.
686: * - If packet bad, just discard it, and update statistics.
687: * Finally, advance receive stop limit in card's memory to new location.
688: */
689: ISA_PUT_2(HOST_ADDR_REG, sc->rx_head);
690: while (ISA_GET_2(IO_PORT_REG) == RCV_Done) {
691: rx_status = ISA_GET_2(IO_PORT_REG);
692: sc->rx_head = ISA_GET_2(IO_PORT_REG);
693: QQQ = pkt_len = ISA_GET_2(IO_PORT_REG);
694: if (rx_status & RCV_OK_bit) {
695: MGETHDR(m, M_DONTWAIT, MT_DATA);
696: ipkt = m;
697: if (ipkt == NULL)
698: ifp->if_iqdrops++;
699: else {
700: ipkt->m_pkthdr.rcvif = ifp;
701: ipkt->m_pkthdr.len = pkt_len;
702: ipkt->m_len = MHLEN;
703: while (pkt_len > 0) {
704: if (pkt_len > MINCLSIZE) {
705: MCLGET(m, M_DONTWAIT);
706: if (m->m_flags & M_EXT)
707: m->m_len = MCLBYTES;
708: else {
709: m_freem(ipkt);
710: ifp->if_iqdrops++;
711: goto rx_another;
712: }
713: }
714: m->m_len = min(m->m_len, pkt_len);
715: /*
716: * NOTE: I'm assuming that all mbufs
717: * allocated are of even length, except
718: * for the last one in an odd-length
719: * packet.
720: */
721: ISA_GET_2_MULTI(IO_PORT_REG,
722: mtod(m, caddr_t), m->m_len / 2);
723: if (m->m_len & 1)
724: *(mtod(m, caddr_t) +
725: m->m_len - 1) =
726: ISA_GET(IO_PORT_REG);
727: pkt_len -= m->m_len;
728: if (pkt_len > 0) {
729: MGET(m->m_next, M_DONTWAIT,
730: MT_DATA);
731: if (m->m_next == NULL) {
732: m_freem(ipkt);
733: ifp->if_iqdrops++;
734: goto rx_another;
735: }
736: m = m->m_next;
737: m->m_len = MLEN;
738: }
739: }
740: #ifdef EXDEBUG
741: if (debug_mask & Rcvd_Pkts) {
742: if ((eh->ether_dhost[5] != 0xff) ||
743: (eh->ether_dhost[0] != 0xff)) {
744: printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":");
745: printf("%6D\n", eh->ether_dhost, ":");
746: } /* QQQ */
747: }
748: #endif
749: #if NBPFILTER > 0
750: if (ifp->if_bpf != NULL)
751: bpf_mtap(ifp->if_bpf, ipkt,
752: BPF_DIRECTION_IN);
753: #endif
754: ether_input_mbuf(ifp, ipkt);
755: ifp->if_ipackets++;
756: }
757: } else
758: ifp->if_ierrors++;
759: ISA_PUT_2(HOST_ADDR_REG, sc->rx_head);
760: rx_another: ;
761: }
762: if (sc->rx_head < sc->rx_lower_limit + 2)
763: ISA_PUT_2(RCV_STOP_REG, sc->rx_upper_limit);
764: else
765: ISA_PUT_2(RCV_STOP_REG, sc->rx_head - 2);
766:
767: DODEBUG(Start_End, printf("ex_rx_intr: finish\n"););
768: }
769:
770:
771: int
772: ex_ioctl(ifp, cmd, data)
773: register struct ifnet *ifp;
774: u_long cmd;
775: caddr_t data;
776: {
777: register struct ifaddr *ifa = (struct ifaddr *) data;
778: struct ex_softc *sc = ifp->if_softc;
779: struct ifreq *ifr = (struct ifreq *) data;
780: int s, error = 0;
781:
782: DODEBUG(Start_End, printf("ex_ioctl: start "););
783:
784: s = splnet();
785:
786: switch(cmd) {
787: case SIOCSIFADDR:
788: DODEBUG(Start_End, printf("SIOCSIFADDR"););
789: ifp->if_flags |= IFF_UP;
790:
791: switch(ifa->ifa_addr->sa_family) {
792: #ifdef INET
793: case AF_INET:
794: ex_init(sc);
795: arp_ifinit((struct arpcom *) ifp, ifa);
796: break;
797: #endif
798: default:
799: ex_init(sc);
800: break;
801: }
802: break;
803: case SIOCGIFADDR:
804: {
805: struct sockaddr *sa;
806:
807: DODEBUG(Start_End, printf("SIOCGIFADDR"););
808: sa = (struct sockaddr *) &ifr->ifr_data;
809: bcopy((caddr_t) sc->arpcom.ac_enaddr, (caddr_t) sa->sa_data,
810: ETHER_ADDR_LEN);
811: }
812: break;
813: case SIOCSIFFLAGS:
814: DODEBUG(Start_End, printf("SIOCSIFFLAGS"););
815: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
816: ifp->if_flags &= ~IFF_RUNNING;
817: ex_stop(sc);
818: }
819: else
820: ex_init(sc);
821: break;
822: #ifdef NODEF
823: case SIOCGHWADDR:
824: DODEBUG(Start_End, printf("SIOCGHWADDR"););
825: bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr));
826: break;
827: #endif
828: case SIOCSIFMTU:
829: DODEBUG(Start_End, printf("SIOCSIFMTU"););
830: if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
831: error = EINVAL;
832: } else if (ifp->if_mtu != ifr->ifr_mtu) {
833: ifp->if_mtu = ifr->ifr_mtu;
834: }
835: break;
836: case SIOCADDMULTI:
837: DODEBUG(Start_End, printf("SIOCADDMULTI"););
838: case SIOCDELMULTI:
839: DODEBUG(Start_End, printf("SIOCDELMULTI"););
840: /* XXX Support not done yet. */
841: error = EINVAL;
842: break;
843: default:
844: DODEBUG(Start_End, printf("unknown"););
845: error = EINVAL;
846: }
847:
848: splx(s);
849:
850: DODEBUG(Start_End, printf("\nex_ioctl: finish\n"););
851: return(error);
852: }
853:
854:
855: void
856: ex_reset(sc)
857: struct ex_softc *sc;
858: {
859: int s;
860:
861: DODEBUG(Start_End, printf("ex_reset: start\n"););
862:
863: s = splnet();
864: ex_stop(sc);
865: ex_init(sc);
866: splx(s);
867:
868: DODEBUG(Start_End, printf("ex_reset: finish\n"););
869: }
870:
871:
872: void
873: ex_watchdog(ifp)
874: struct ifnet *ifp;
875: {
876: struct ex_softc *sc = ifp->if_softc;
877:
878: DODEBUG(Start_End, printf("ex_watchdog: start\n"););
879:
880: ifp->if_flags &= ~IFF_OACTIVE;
881: DODEBUG(Status, printf("OIDLE watchdog\n"););
882: ifp->if_oerrors++;
883: ex_reset(sc);
884: ex_start(ifp);
885:
886: DODEBUG(Start_End, printf("ex_watchdog: finish\n"););
887: }
888:
889:
890: static u_short
891: eeprom_read(sc, location)
892: struct ex_softc *sc;
893: int location;
894: {
895: int i;
896: u_short data = 0;
897: int read_cmd = location | EE_READ_CMD;
898: short ctrl_val = EECS;
899:
900: BANK_SEL(Bank2_Sel);
901: ISA_PUT(EEPROM_REG, EECS);
902: for (i = 8; i >= 0; i--) {
903: short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI :
904: ctrl_val;
905: ISA_PUT(EEPROM_REG, outval);
906: ISA_PUT(EEPROM_REG, outval | EESK);
907: delay(3);
908: ISA_PUT(EEPROM_REG, outval);
909: delay(2);
910: }
911: ISA_PUT(EEPROM_REG, ctrl_val);
912: for (i = 16; i > 0; i--) {
913: ISA_PUT(EEPROM_REG, ctrl_val | EESK);
914: delay(3);
915: data = (data << 1) | ((ISA_GET(EEPROM_REG) & EEDO) ? 1 : 0);
916: ISA_PUT(EEPROM_REG, ctrl_val);
917: delay(2);
918: }
919: ctrl_val &= ~EECS;
920: ISA_PUT(EEPROM_REG, ctrl_val | EESK);
921: delay(3);
922: ISA_PUT(EEPROM_REG, ctrl_val);
923: delay(2);
924: BANK_SEL(Bank0_Sel);
925: return(data);
926: }
927:
928: #endif /* NEX > 0 */
CVSweb