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