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