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