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