if_ex.c revision 29877
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 *	$Id$
28 */
29
30/*
31 * Intel EtherExpress Pro/10, 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
49#include <net/if.h>
50
51#ifdef INET
52#include <netinet/in.h>
53#include <netinet/if_ether.h>
54#endif
55
56#ifdef IPX
57#include <netipx/ipx.h>
58#include <netipx/ipx_if.h>
59#endif
60
61#ifdef NS
62#include <netns/ns.h>
63#include <netns/ns_if.h>
64#endif
65
66#if NBPFILTER > 0
67#include <net/bpf.h>
68#endif
69
70#include <machine/clock.h>
71
72#include <i386/isa/isa_device.h>
73#include <i386/isa/if_exreg.h>
74
75#ifdef EXDEBUG
76#define Start_End 1
77#define Rcvd_Pkts 2
78#define Sent_Pkts 4
79#define Status    8
80static int debug_mask = 0;
81static int exintr_count = 0;
82#define DODEBUG(level, action) if (level & debug_mask) action
83#else
84#define DODEBUG(level, action)
85#endif
86
87#define Conn_BNC 1
88#define Conn_TPE 2
89#define Conn_AUI 3
90
91struct ex_softc {
92  	struct arpcom arpcom;	/* Ethernet common data */
93	u_int iobase;	/* I/O base address. */
94	u_short connector;	/* Connector type. */
95	u_short irq_no; /* IRQ number. */
96	char *irq2ee; /* irq <-> internal representation conversion */
97	u_char *ee2irq;
98	u_int mem_size;	/* Total memory size, in bytes. */
99	u_int rx_mem_size;	/* Rx memory size (by default, first 3/4 of total memory). */
100  u_int rx_lower_limit, rx_upper_limit; /* Lower and upper limits of receive buffer. */
101  u_int rx_head; /* Head of receive ring buffer. */
102	u_int tx_mem_size;	/* Tx memory size (by default, last quarter of total memory). */
103  u_int tx_lower_limit, tx_upper_limit; /* Lower and upper limits of transmit buffer. */
104  u_int tx_head, tx_tail; /* Head and tail of transmit ring buffer. */
105  u_int tx_last; /* Pointer to beginning of last frame in the chain. */
106};
107
108static struct ex_softc ex_sc[NEX]; /* XXX would it be better to malloc(3) the memory? */
109
110static char irq2eemap[] = { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 };
111static u_char ee2irqmap[] = { 9, 3, 5, 10, 11, 0, 0, 0 };
112static char plus_irq2eemap[] = { -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 };
113static u_char plus_ee2irqmap[] = { 3, 4, 5, 7, 9, 10, 11, 12 };
114
115static int ex_probe __P((struct isa_device *));
116static int ex_attach __P((struct isa_device *));
117static void ex_init __P((void *));
118static void ex_start __P((struct ifnet *));
119static void ex_stop __P((int));
120static int ex_ioctl __P((struct ifnet *, int, caddr_t));
121static void ex_reset __P((int));
122static void ex_watchdog __P((struct ifnet *));
123
124static u_short eeprom_read __P((int, int));
125static int look_for_card __P((u_int));
126static void ex_tx_intr __P((int));
127static void ex_rx_intr __P((int));
128
129struct isa_driver exdriver = {
130	ex_probe,
131	ex_attach,
132	"ex",
133	0
134};
135
136static int look_for_card(u_int iobase)
137{
138	int count1, count2;
139
140	/*
141	 * Check for the i82595 signature, and check that the round robin
142	 * counter actually advances.
143	 */
144	if (((count1 = inb(iobase + ID_REG)) & Id_Mask) != Id_Sig)
145		return(0);
146	count2 = inb(iobase + ID_REG);
147	count2 = inb(iobase + ID_REG);
148	count2 = inb(iobase + ID_REG);
149	return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits));
150}
151
152
153int ex_probe(struct isa_device *dev)
154{
155	int unit = dev->id_unit;
156	struct ex_softc *sc = &ex_sc[unit];
157	u_int iobase;
158	u_short eaddr_tmp;
159	int tmp;
160
161	DODEBUG(Start_End, printf("ex_probe%d: start\n", unit););
162
163	/*
164	 * If an I/O address was supplied in the configuration file, probe only
165	 * that. Otherwise, cycle through the predefined set of possible addresses.
166	 */
167	if (dev->id_iobase != -1) {
168		if (! look_for_card(iobase = dev->id_iobase))
169			return(0);
170	}
171	else {
172		for (iobase = 0x200; iobase < 0x3a0; iobase += 0x10)
173			if (look_for_card(iobase))
174				break;
175		if (iobase >= 0x3a0)
176			return(0);
177		else
178			dev->id_iobase = iobase;
179	}
180
181	/*
182	 * Reset the card.
183	 */
184	outb(iobase + CMD_REG, Reset_CMD);
185	DELAY(400);
186
187	/*
188	 * Fill in several fields of the softc structure:
189	 *	- I/O base address.
190	 *	- Hardware Ethernet address.
191	 *	- IRQ number (if not supplied in config file, read it from EEPROM).
192	 *	- Connector type.
193	 */
194	sc->iobase = iobase;
195	eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Lo);
196	sc->arpcom.ac_enaddr[5] = eaddr_tmp & 0xff;
197	sc->arpcom.ac_enaddr[4] = eaddr_tmp >> 8;
198	eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Mid);
199	sc->arpcom.ac_enaddr[3] = eaddr_tmp & 0xff;
200	sc->arpcom.ac_enaddr[2] = eaddr_tmp >> 8;
201	eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Hi);
202	sc->arpcom.ac_enaddr[1] = eaddr_tmp & 0xff;
203	sc->arpcom.ac_enaddr[0] = eaddr_tmp >> 8;
204	tmp = eeprom_read(iobase, EE_IRQ_No) & IRQ_No_Mask;
205
206	/* work out which set of irq <-> internal tables to use */
207	if (sc->arpcom.ac_enaddr[0] == 0x00 &&
208	    sc->arpcom.ac_enaddr[1] == 0xA0 &&
209	    sc->arpcom.ac_enaddr[2] == 0xC9) {    /* it's a 10+ */
210		sc->irq2ee = plus_irq2eemap;
211		sc->ee2irq = plus_ee2irqmap;
212	} else {                                  /* it's an ordinary 10 */
213		sc->irq2ee = irq2eemap;
214		sc->ee2irq = ee2irqmap;
215	}
216
217	if (dev->id_irq > 0) {
218		if (sc->ee2irq[tmp] != ffs(dev->id_irq) - 1)
219			printf("ex%d: WARNING: board's EEPROM is configured for IRQ %d, using %d\n", unit, sc->ee2irq[tmp], ffs(dev->id_irq) - 1);
220		sc->irq_no = ffs(dev->id_irq) - 1;
221	}
222	else {
223		sc->irq_no = sc->ee2irq[tmp];
224		dev->id_irq = 1 << sc->irq_no;
225	}
226	if (sc->irq_no == 0) {
227		printf("ex%d: invalid IRQ.\n", unit);
228		return(0);
229	}
230	outb(iobase + CMD_REG, Bank2_Sel);
231	tmp = inb(iobase + REG3);
232	if (tmp & TPE_bit)
233		sc->connector = Conn_TPE;
234	else if (tmp & BNC_bit)
235		sc->connector = Conn_BNC;
236	else
237		sc->connector = Conn_AUI;
238	sc->mem_size = CARD_RAM_SIZE;	/* XXX This should be read from the card itself. */
239
240	outb(iobase + CMD_REG, Bank0_Sel);
241
242	DODEBUG(Start_End, printf("ex_probe%d: finish\n", unit););
243	return(EX_IOSIZE);
244}
245
246
247int ex_attach(struct isa_device *dev)
248{
249	int unit = dev->id_unit;
250	struct ex_softc *sc = &ex_sc[unit];
251	struct ifnet *ifp = &sc->arpcom.ac_if;
252	struct ifaddr *ifa;
253	struct sockaddr_dl *sdl;
254
255	DODEBUG(Start_End, printf("ex_attach%d: start\n", unit););
256
257	/*
258	 * Initialize the ifnet structure.
259	 */
260	ifp->if_softc = sc;
261	ifp->if_unit = unit;
262	ifp->if_name = "ex";
263	ifp->if_init = ex_init;
264	ifp->if_output = ether_output;
265	ifp->if_start = ex_start;
266	ifp->if_ioctl = ex_ioctl;
267	ifp->if_watchdog = ex_watchdog;
268	ifp->if_mtu = ETHERMTU;
269	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST /* XXX not done yet. | IFF_MULTICAST */;
270
271	/*
272	 * Attach the interface.
273	 */
274	if_attach(ifp);
275	ether_ifattach(ifp);
276
277	if (sc->arpcom.ac_enaddr[0] == 0x00 &&
278	    sc->arpcom.ac_enaddr[1] == 0xA0 &&
279	    sc->arpcom.ac_enaddr[2] == 0xC9) {
280		printf("ex%d: Intel EtherExpress Pro/10+, address %6D, connector ", dev->id_unit, sc->arpcom.ac_enaddr, ":");
281	} else {
282		printf("ex%d: Intel EtherExpress Pro/10, address %6D, connector ", dev->id_unit, sc->arpcom.ac_enaddr, ":");
283	}
284	switch(sc->connector) {
285		case Conn_TPE: printf("TPE\n"); break;
286		case Conn_BNC: printf("BNC\n"); break;
287		case Conn_AUI: printf("AUI\n"); break;
288		default: printf("???\n");
289	}
290
291	/*
292	 * If BPF is in the kernel, call the attach for it
293	 */
294#if NBPFILTER > 0
295	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
296#endif
297	DODEBUG(Start_End, printf("ex_attach%d: finish\n", unit););
298	return(1);
299}
300
301
302void ex_init(void *xsc)
303{
304	register struct ex_softc *sc = (struct ex_softc *) xsc;
305	struct ifnet *ifp = &sc->arpcom.ac_if;
306	int s, i;
307	register int iobase = sc->iobase;
308	unsigned short temp_reg;
309
310	DODEBUG(Start_End, printf("ex_init%d: start\n", ifp->if_unit););
311
312	if (ifp->if_addrhead.tqh_first == NULL)
313	  return;
314	s = splimp();
315	sc->arpcom.ac_if.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	for (i = 0; i < ETHER_ADDR_LEN; i++)
325	  outb(iobase + I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]);
326	/*
327	 * - Setup transmit chaining and discard bad received frames.
328	 * - Match broadcast.
329	 * - Clear test mode.
330	 * - Set receiving mode.
331	 * - Set IRQ number.
332	 */
333	outb(iobase + REG1, inb(iobase + REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr);
334	outb(iobase + REG2, inb(iobase + REG2) | No_SA_Ins | RX_CRC_InMem);
335	outb(iobase + REG3, inb(iobase + REG3) & 0x3f /* XXX constants. */ );
336	outb(iobase + CMD_REG, Bank1_Sel);
337	outb(iobase + INT_NO_REG, (inb(iobase + INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]);
338
339	/*
340	 * Divide the available memory in the card into rcv and xmt buffers.
341	 * By default, I use the first 3/4 of the memory for the rcv buffer,
342	 * and the remaining 1/4 of the memory for the xmt buffer.
343	 */
344	sc->rx_mem_size = sc->mem_size * 3 / 4;
345	sc->tx_mem_size = sc->mem_size - sc->rx_mem_size;
346	sc->rx_lower_limit = 0x0000;
347	sc->rx_upper_limit = sc->rx_mem_size - 2;
348	sc->tx_lower_limit = sc->rx_mem_size;
349	sc->tx_upper_limit = sc->mem_size - 2;
350	outb(iobase + RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8);
351	outb(iobase + RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8);
352	outb(iobase + XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8);
353	outb(iobase + XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8);
354
355	/*
356	 * Enable receive and transmit interrupts, and clear any pending int.
357	 */
358	outb(iobase + REG1, inb(iobase + REG1) | TriST_INT);
359	outb(iobase + CMD_REG, Bank0_Sel);
360	outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
361	outb(iobase + STATUS_REG, All_Int);
362
363	/*
364	 * Initialize receive and transmit ring buffers.
365	 */
366	outw(iobase + RCV_BAR, sc->rx_lower_limit);
367	sc->rx_head = sc->rx_lower_limit;
368	outw(iobase + RCV_STOP_REG, sc->rx_upper_limit | 0xfe);
369	outw(iobase + XMT_BAR, sc->tx_lower_limit);
370	sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
371
372	ifp->if_flags |= IFF_RUNNING;
373	ifp->if_flags &= ~IFF_OACTIVE;
374	DODEBUG(Status, printf("OIDLE init\n"););
375
376	/*
377	 * Final reset of the board, and enable operation.
378	 */
379	outb(iobase + CMD_REG, Sel_Reset_CMD);
380	DELAY(2);
381	outb(iobase + CMD_REG, Rcv_Enable_CMD);
382
383	ex_start(ifp);
384	splx(s);
385
386	DODEBUG(Start_End, printf("ex_init%d: finish\n", ifp->if_unit););
387}
388
389
390void ex_start(struct ifnet *ifp)
391{
392  int unit = ifp->if_unit;
393  register struct ex_softc *sc = &ex_sc[unit];
394  register int iobase = sc->iobase;
395  int i, s, len, data_len, avail, dest, next;
396  unsigned char tmp16[2], *cP;
397  struct mbuf *opkt;
398  register struct mbuf *m;
399
400  DODEBUG(Start_End, printf("ex_start%d: start\n", unit););
401
402  s = splimp();
403
404  /*
405   * Main loop: send outgoing packets to network card until there are no
406   * more packets left, or the card cannot accept any more yet.
407   */
408  while (((opkt = ifp->if_snd.ifq_head) != NULL) && ! (ifp->if_flags & IFF_OACTIVE)) {
409
410    /*
411     * Ensure there is enough free transmit buffer space for this packet,
412     * including its header. Note: the header cannot wrap around the end of
413     * the transmit buffer and must be kept together, so we allow space for
414     * twice the length of the header, just in case.
415     */
416    for (len = 0, m = opkt; m != NULL; m = m->m_next)
417      len += m->m_len;
418    data_len = len;
419    DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len););
420    if (len & 1)
421      len += XMT_HEADER_LEN + 1;
422    else
423      len += XMT_HEADER_LEN;
424    if ((i = sc->tx_tail - sc->tx_head) >= 0)
425      avail = sc->tx_mem_size - i;
426    else
427      avail = -i;
428	DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail););
429    if (avail >= len + XMT_HEADER_LEN) {
430      IF_DEQUEUE(&ifp->if_snd, opkt);
431
432#ifdef EX_PSA_INTR
433      /*
434       * Disable rx and tx interrupts, to avoid corruption of the host
435       * address register by interrupt service routines. XXX Is this necessary with splimp() enabled?
436       */
437      outb(iobase + MASK_REG, All_Int);
438#endif
439
440      /*
441       * Compute the start and end addresses of this frame in the tx buffer.
442       */
443      dest = sc->tx_tail;
444      next = dest + len;
445      if (next > sc->tx_upper_limit) {
446	if ((sc->tx_upper_limit + 2 - sc->tx_tail) <= XMT_HEADER_LEN) {
447	  dest = sc->tx_lower_limit;
448	  next = dest + len;
449	}
450	else
451	  next = sc->tx_lower_limit + next - sc->tx_upper_limit - 2;
452      }
453
454      /*
455       * Build the packet frame in the card's ring buffer.
456       */
457      DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next););
458      outw(iobase + HOST_ADDR_REG, dest);
459      outw(iobase + IO_PORT_REG, Transmit_CMD);
460      outw(iobase + IO_PORT_REG, 0);
461      outw(iobase + IO_PORT_REG, next);
462      outw(iobase + IO_PORT_REG, data_len);
463
464	/*
465	 * Output the packet data to the card. Ensure all transfers are
466	 * 16-bit wide, even if individual mbufs have odd length.
467	 */
468
469     for (m = opkt, i = 0; m != NULL; m = m->m_next) {
470		DODEBUG(Sent_Pkts, printf("[%d]", m->m_len););
471		if (i) {
472			tmp16[1] = *(mtod(m, caddr_t));
473			outsw(iobase + IO_PORT_REG, tmp16, 1);
474		}
475		outsw(iobase + IO_PORT_REG, mtod(m, caddr_t) + i, (m->m_len - i) / 2);
476		if (i = (m->m_len - i) & 1)
477			tmp16[0] = *(mtod(m, caddr_t) + m->m_len - 1);
478	}
479	if (i)
480		outsw(iobase + IO_PORT_REG, tmp16, 1);
481
482      /*
483       * If there were other frames chained, update the chain in the last one.
484       */
485      if (sc->tx_head != sc->tx_tail) {
486	if (sc->tx_tail != dest) {
487	  outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_Chain_Point);
488	  outw(iobase + IO_PORT_REG, dest);
489	}
490	outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_Byte_Count);
491	i = inw(iobase + IO_PORT_REG);
492	outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_Byte_Count);
493	outw(iobase + IO_PORT_REG, i | Ch_bit);
494      }
495
496      /*
497       * Resume normal operation of the card:
498       * - Make a dummy read to flush the DRAM write pipeline.
499       * - Enable receive and transmit interrupts.
500       * - Send Transmit or Resume_XMT command, as appropriate.
501       */
502      inw(iobase + IO_PORT_REG);
503#ifdef EX_PSA_INTR
504      outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
505#endif
506      if (sc->tx_head == sc->tx_tail) {
507	outw(iobase + XMT_BAR, dest);
508	outb(iobase + CMD_REG, Transmit_CMD);
509	sc->tx_head = dest;
510	DODEBUG(Sent_Pkts, printf("Transmit\n"););
511      }
512      else {
513	outb(iobase + CMD_REG, Resume_XMT_List_CMD);
514	DODEBUG(Sent_Pkts, printf("Resume\n"););
515	}
516      sc->tx_last = dest;
517      sc->tx_tail = next;
518
519#if NBPFILTER > 0
520      if (ifp->if_bpf != NULL)
521	bpf_mtap(ifp, opkt);
522#endif
523      ifp->if_timer = 2;
524      ifp->if_opackets++;
525      m_freem(opkt);
526    }
527    else {
528      ifp->if_flags |= IFF_OACTIVE;
529	  DODEBUG(Status, printf("OACTIVE start\n"););
530	}
531  }
532
533  splx(s);
534
535  DODEBUG(Start_End, printf("ex_start%d: finish\n", unit););
536}
537
538
539void ex_stop(int unit)
540{
541  struct ex_softc *sc = &ex_sc[unit];
542  int iobase = sc->iobase;
543
544  DODEBUG(Start_End, printf("ex_stop%d: start\n", unit););
545
546  /*
547   * Disable card operation:
548   * - Disable the interrupt line.
549   * - Flush transmission and disable reception.
550   * - Mask and clear all interrupts.
551   * - Reset the 82595.
552   */
553  outb(iobase + CMD_REG, Bank1_Sel);
554  outb(iobase + REG1, inb(iobase + REG1) & ~TriST_INT);
555  outb(iobase + CMD_REG, Bank0_Sel);
556  outb(iobase + CMD_REG, Rcv_Stop);
557  sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
558  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. */
559  outb(iobase + MASK_REG, All_Int);
560  outb(iobase + STATUS_REG, All_Int);
561  outb(iobase + CMD_REG, Reset_CMD);
562  DELAY(200);
563
564  DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit););
565}
566
567
568void exintr(int unit)
569{
570  struct ex_softc *sc = &ex_sc[unit];
571  struct ifnet *ifp = &sc->arpcom.ac_if;
572  int iobase = sc->iobase;
573  int s, int_status, send_pkts;
574
575  DODEBUG(Start_End, printf("exintr%d: start\n", unit););
576
577#ifdef EXDEBUG
578	if (++exintr_count != 1)
579		printf("WARNING: nested interrupt (%d). Mail the author.\n", exintr_count);
580#endif
581
582  send_pkts = 0;
583  while ((int_status = inb(iobase + STATUS_REG)) & (Tx_Int | Rx_Int)) {
584    if (int_status & Rx_Int) {
585      outb(iobase + STATUS_REG, Rx_Int);
586      ex_rx_intr(unit);
587    }
588	else if (int_status & Tx_Int) {
589      outb(iobase + STATUS_REG, Tx_Int);
590      ex_tx_intr(unit);
591      send_pkts = 1;
592    }
593  }
594
595  /*
596   * If any packet has been transmitted, and there are queued packets to
597   * be sent, attempt to send more packets to the network card.
598   */
599
600  if (send_pkts && (ifp->if_snd.ifq_head != NULL))
601    ex_start(ifp);
602
603#ifdef EXDEBUG
604	exintr_count--;
605#endif
606
607  DODEBUG(Start_End, printf("exintr%d: finish\n", unit););
608}
609
610
611void ex_tx_intr(int unit)
612{
613  register struct ex_softc *sc = &ex_sc[unit];
614  register struct ifnet *ifp = &sc->arpcom.ac_if;
615  register int iobase = sc->iobase;
616  int tx_status;
617
618  DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit););
619
620  /*
621   * - Cancel the watchdog.
622   * For all packets transmitted since last transmit interrupt:
623   * - Advance chain pointer to next queued packet.
624   * - Update statistics.
625   */
626
627  ifp->if_timer = 0;
628  while (sc->tx_head != sc->tx_tail) {
629    outw(iobase + HOST_ADDR_REG, sc->tx_head);
630    if (! inw(iobase + IO_PORT_REG) & Done_bit)
631      break;
632    tx_status = inw(iobase + IO_PORT_REG);
633    sc->tx_head = inw(iobase + IO_PORT_REG);
634    if (tx_status & TX_OK_bit)
635      ifp->if_opackets++;
636    else
637      ifp->if_oerrors++;
638    ifp->if_collisions += tx_status & No_Collisions_bits;
639  }
640
641  /*
642   * The card should be ready to accept more packets now.
643   */
644
645  ifp->if_flags &= ~IFF_OACTIVE;
646  DODEBUG(Status, printf("OIDLE tx_intr\n"););
647
648  DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit););
649}
650
651
652void ex_rx_intr(int unit)
653{
654  register struct ex_softc *sc = &ex_sc[unit];
655  register struct ifnet *ifp = &sc->arpcom.ac_if;
656  register int iobase = sc->iobase;
657  int rx_status, pkt_len, QQQ;
658  register struct mbuf *m, *ipkt;
659  struct ether_header *eh;
660
661  DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit););
662
663  /*
664   * For all packets received since last receive interrupt:
665   * - If packet ok, read it into a new mbuf and queue it to interface,
666   *   updating statistics.
667   * - If packet bad, just discard it, and update statistics.
668   * Finally, advance receive stop limit in card's memory to new location.
669   */
670
671  outw(iobase + HOST_ADDR_REG, sc->rx_head);
672  while (inw(iobase + IO_PORT_REG) == RCV_Done) {
673    rx_status = inw(iobase + IO_PORT_REG);
674    sc->rx_head = inw(iobase + IO_PORT_REG);
675    QQQ = pkt_len = inw(iobase + IO_PORT_REG);
676    if (rx_status & RCV_OK_bit) {
677      MGETHDR(m, M_DONTWAIT, MT_DATA);
678      ipkt = m;
679      if (ipkt == NULL)
680	ifp->if_iqdrops++;
681      else {
682	ipkt->m_pkthdr.rcvif = ifp;
683	ipkt->m_pkthdr.len = pkt_len;
684	ipkt->m_len = MHLEN;
685	while (pkt_len > 0) {
686	  if (pkt_len > MINCLSIZE) {
687	    MCLGET(m, M_DONTWAIT);
688	    if (m->m_flags & M_EXT)
689	      m->m_len = MCLBYTES;
690	    else {
691	      m_freem(ipkt);
692	      ifp->if_iqdrops++;
693	      goto rx_another;
694	    }
695	  }
696	  m->m_len = min(m->m_len, pkt_len);
697
698	  /*
699	   * NOTE: I'm assuming that all mbufs allocated are of even length,
700	   * except for the last one in an odd-length packet.
701	   */
702	  insw(iobase + IO_PORT_REG, mtod(m, caddr_t), m->m_len / 2);
703	  if (m->m_len & 1)
704		*(mtod(m, caddr_t) + m->m_len - 1) = inb(iobase + IO_PORT_REG);
705	  pkt_len -= m->m_len;
706	  if (pkt_len > 0) {
707	    MGET(m->m_next, M_DONTWAIT, MT_DATA);
708	    if (m->m_next == NULL) {
709	      m_freem(ipkt);
710	      ifp->if_iqdrops++;
711	      goto rx_another;
712	    }
713	    m = m->m_next;
714	    m->m_len = MLEN;
715	  }
716	}
717	eh = mtod(ipkt, struct ether_header *);
718#ifdef EXDEBUG
719	  if (debug_mask & Rcvd_Pkts) {
720          if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) {
721            printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":");
722            printf("%6D\n", eh->ether_dhost, ":");
723	  } /* QQQ */
724	  }
725#endif
726#if NBPFILTER > 0
727	if (ifp->if_bpf != NULL) {
728		bpf_mtap(ifp, ipkt);
729
730		/*
731		 * Note that the interface cannot be in promiscuous mode if there are
732		 * no BPF listeners. And if we are in promiscuous mode, we have to
733		 * check if this packet is really ours.
734		 */
735		if ((ifp->if_flags & IFF_PROMISC) &&
736		    (eh->ether_dhost[0] & 1) == 0 &&
737		    bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, sizeof(eh->ether_dhost)) != 0 &&
738		    bcmp(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)) != 0) {
739			m_freem(ipkt);
740			goto rx_another;
741		}
742	}
743#endif
744	m_adj(ipkt, sizeof(struct ether_header));
745	ether_input(ifp, eh, ipkt);
746	ifp->if_ipackets++;
747      }
748    }
749    else
750      ifp->if_ierrors++;
751    outw(iobase + HOST_ADDR_REG, sc->rx_head);
752  rx_another: ;
753  }
754  if (sc->rx_head < sc->rx_lower_limit + 2)
755    outw(iobase + RCV_STOP_REG, sc->rx_upper_limit);
756  else
757    outw(iobase + RCV_STOP_REG, sc->rx_head - 2);
758
759  DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit););
760}
761
762
763int ex_ioctl(register struct ifnet *ifp, int cmd, caddr_t data)
764{
765  register struct ifaddr *ifa = (struct ifaddr *) data;
766  struct ex_softc *sc = &ex_sc[ifp->if_unit];
767  struct ifreq *ifr = (struct ifreq *) data;
768  int s, error = 0;
769
770  DODEBUG(Start_End, printf("ex_ioctl%d: start ", ifp->if_unit););
771
772  s = splimp();
773
774  switch(cmd) {
775  case SIOCSIFADDR:
776    DODEBUG(Start_End, printf("SIOCSIFADDR"););
777    ifp->if_flags |= IFF_UP;
778
779    switch(ifa->ifa_addr->sa_family) {
780#ifdef INET
781    case AF_INET:
782      ex_init(sc);
783      arp_ifinit((struct arpcom *) ifp, ifa);
784      break;
785#endif
786#ifdef IPX_NOTYET
787    case AF_IPX:
788      {
789	register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
790
791	if (ipx_nullhost(*ina))
792	  ina->x_host = *(union ipx_host *) (sc->arpcom.ac_enaddr);
793	else {
794	  ifp->if_flags &= ~IFF_RUNNING;
795	  bcopy((caddr_t) ina->x_host.c_host, (caddr_t) sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr));
796	}
797	ex_init(sc);
798	break;
799      }
800#endif
801#ifdef NS
802    case AF_NS:
803      {
804	register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
805
806	if (ns_nullhost(*ina))
807	  ina->x_host = *(union ns_host *) (sc->arpcom.ac_enaddr);
808	else {
809	  ifp->if_flags &= ~IFF_RUNNING;
810	  bcopy((caddr_t) ina->x_host.c_host, (caddr_t) sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr));
811	}
812	ex_init(sc);
813	break;
814      }
815#endif
816    default:
817      ex_init(sc);
818      break;
819    }
820    break;
821  case SIOCGIFADDR:
822    {
823      struct sockaddr *sa;
824
825      DODEBUG(Start_End, printf("SIOCGIFADDR"););
826      sa = (struct sockaddr *) &ifr->ifr_data;
827      bcopy((caddr_t) sc->arpcom.ac_enaddr, (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
828    }
829  break;
830  case SIOCSIFFLAGS:
831    DODEBUG(Start_End, printf("SIOCSIFFLAGS"););
832    if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
833      ifp->if_flags &= ~IFF_RUNNING;
834      ex_stop(ifp->if_unit);
835    }
836    else
837      ex_init(sc);
838    break;
839#ifdef NODEF
840  case SIOCGHWADDR:
841    DODEBUG(Start_End, printf("SIOCGHWADDR"););
842    bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr));
843    break;
844#endif
845  case SIOCSIFMTU:
846    DODEBUG(Start_End, printf("SIOCSIFMTU"););
847    if (ifr->ifr_mtu > ETHERMTU)
848      error = EINVAL;
849    else
850      ifp->if_mtu = ifr->ifr_mtu;
851    break;
852  case SIOCADDMULTI:
853    DODEBUG(Start_End, printf("SIOCADDMULTI"););
854  case SIOCDELMULTI:
855    DODEBUG(Start_End, printf("SIOCDELMULTI"););
856    /* XXX Support not done yet. */
857    error = EINVAL;
858    break;
859  default:
860    DODEBUG(Start_End, printf("unknown"););
861    error = EINVAL;
862  }
863
864  splx(s);
865
866  DODEBUG(Start_End, printf("\nex_ioctl%d: finish\n", ifp->if_unit););
867  return(error);
868}
869
870
871void ex_reset(int unit)
872{
873  struct ex_softc *sc = &ex_sc[unit];
874  struct ifnet *ifp = &sc->arpcom.ac_if;
875  int s;
876
877  DODEBUG(Start_End, printf("ex_reset%d: start\n", unit););
878
879  s = splimp();
880
881  ex_stop(unit);
882  ex_init(sc);
883
884  splx(s);
885
886  DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit););
887}
888
889
890void ex_watchdog(struct ifnet *ifp)
891{
892  struct ex_softc *sc = &ex_sc[ifp->if_unit];
893
894  DODEBUG(Start_End, printf("ex_watchdog%d: start\n", ifp->if_unit););
895
896  ifp->if_flags &= ~IFF_OACTIVE;
897  DODEBUG(Status, printf("OIDLE watchdog\n"););
898  ifp->if_oerrors++;
899  ex_reset(ifp->if_unit);
900  ex_start(ifp);
901
902  DODEBUG(Start_End, printf("ex_watchdog%d: finish\n", ifp->if_unit););
903}
904
905
906static u_short eeprom_read(int iobase, int location)
907{
908	int i;
909	u_short data = 0;
910	int ee_addr;
911	int read_cmd = location | EE_READ_CMD;
912	short ctrl_val = EECS;
913
914	ee_addr = iobase + EEPROM_REG;
915	outb(iobase + CMD_REG, Bank2_Sel);
916	outb(ee_addr, EECS);
917	for (i = 8; i >= 0; i--) {
918		short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val;
919		outb(ee_addr, outval);
920		outb(ee_addr, outval | EESK);
921		DELAY(3);
922		outb(ee_addr, outval);
923		DELAY(2);
924	}
925	outb(ee_addr, ctrl_val);
926
927	for (i = 16; i > 0; i--) {
928		outb(ee_addr, ctrl_val | EESK);
929		DELAY(3);
930		data = (data << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
931		outb(ee_addr, ctrl_val);
932		DELAY(2);
933	}
934
935	ctrl_val &= ~EECS;
936	outb(ee_addr, ctrl_val | EESK);
937	DELAY(3);
938	outb(ee_addr, ctrl_val);
939	DELAY(2);
940	outb(iobase + CMD_REG, Bank0_Sel);
941	return(data);
942}
943
944#endif /* NEX > 0 */
945