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