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