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