if_ex.c revision 271849
155825Speter/*-
2104930Sobrien * Copyright (c) 1996, Javier Mart��n Rueda (jmrueda@diatel.upm.es)
339818Speter * All rights reserved.
439818Speter *
547719Speter * Redistribution and use in source and binary forms, with or without
639818Speter * modification, are permitted provided that the following conditions
739818Speter * are met:
839818Speter * 1. Redistributions of source code must retain the above copyright
9120654Speter *    notice unmodified, this list of conditions, and the following
10218822Sdim *    disclaimer.
11218822Sdim * 2. Redistributions in binary form must reproduce the above copyright
12218822Sdim *    notice, this list of conditions and the following disclaimer in the
13218822Sdim *    documentation and/or other materials provided with the distribution.
14218822Sdim *
15218822Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16218822Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17218822Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18218822Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19218822Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20218822Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22218822Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23218822Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24218822Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25218822Sdim * SUCH DAMAGE.
26218822Sdim *
27218822Sdim *
28218822Sdim * MAINTAINER: Matthew N. Dodd <winter@jurai.net>
29218822Sdim *                             <mdodd@FreeBSD.org>
30218822Sdim */
31218822Sdim
32218822Sdim#include <sys/cdefs.h>
33218822Sdim__FBSDID("$FreeBSD: head/sys/dev/ex/if_ex.c 271849 2014-09-19 03:51:26Z glebius $");
34218822Sdim
35218822Sdim/*
36218822Sdim * Intel EtherExpress Pro/10, Pro/10+ Ethernet driver
37218822Sdim *
38218822Sdim * Revision history:
39218822Sdim *
40218822Sdim * dd-mmm-yyyy: Multicast support ported from NetBSD's if_iy driver.
41218822Sdim * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast.
42218822Sdim */
43218822Sdim
44218822Sdim#include <sys/param.h>
4539818Speter#include <sys/systm.h>
46218822Sdim#include <sys/kernel.h>
47218822Sdim#include <sys/sockio.h>
48218822Sdim#include <sys/mbuf.h>
49218822Sdim#include <sys/socket.h>
50218822Sdim
51218822Sdim#include <sys/module.h>
52218822Sdim#include <sys/bus.h>
5339818Speter
5439818Speter#include <machine/bus.h>
55218822Sdim#include <machine/resource.h>
56218822Sdim#include <sys/rman.h>
57218822Sdim
58218822Sdim#include <net/if.h>
59218822Sdim#include <net/if_var.h>
60218822Sdim#include <net/if_arp.h>
61218822Sdim#include <net/if_dl.h>
6239818Speter#include <net/if_media.h>
63218822Sdim#include <net/if_types.h>
64218822Sdim#include <net/ethernet.h>
65218822Sdim#include <net/bpf.h>
66218822Sdim
67218822Sdim#include <netinet/in.h>
6839818Speter#include <netinet/if_ether.h>
6939818Speter
70218822Sdim
71218822Sdim#include <isa/isavar.h>
72218822Sdim#include <isa/pnpvar.h>
73218822Sdim
74218822Sdim#include <dev/ex/if_exreg.h>
75218822Sdim#include <dev/ex/if_exvar.h>
76218822Sdim
77218822Sdim#ifdef EXDEBUG
7839818Speter# define Start_End 1
79218822Sdim# define Rcvd_Pkts 2
80218822Sdim# define Sent_Pkts 4
81218822Sdim# define Status    8
8239818Speterstatic int debug_mask = 0;
83218822Sdim# define DODEBUG(level, action) if (level & debug_mask) action
84218822Sdim#else
85218822Sdim# define DODEBUG(level, action)
86218822Sdim#endif
87218822Sdim
88218822Sdimdevclass_t ex_devclass;
89218822Sdim
90218822Sdimchar irq2eemap[] =
91218822Sdim	{ -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 };
92218822Sdimu_char ee2irqmap[] =
93218822Sdim	{ 9, 3, 5, 10, 11, 0, 0, 0 };
94218822Sdim
95218822Sdimchar plus_irq2eemap[] =
96218822Sdim	{ -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 };
97108777Sphku_char plus_ee2irqmap[] =
98108777Sphk	{ 3, 4, 5, 7, 9, 10, 11, 12 };
99218822Sdim
10039818Speter/* Network Interface Functions */
101218822Sdimstatic void	ex_init(void *);
102218822Sdimstatic void	ex_init_locked(struct ex_softc *);
103218822Sdimstatic void	ex_start(struct ifnet *);
104218822Sdimstatic void	ex_start_locked(struct ifnet *);
105218822Sdimstatic int	ex_ioctl(struct ifnet *, u_long, caddr_t);
106218822Sdimstatic void	ex_watchdog(void *);
107218822Sdim
108218822Sdim/* ifmedia Functions	*/
109218822Sdimstatic int	ex_ifmedia_upd(struct ifnet *);
110218822Sdimstatic void	ex_ifmedia_sts(struct ifnet *, struct ifmediareq *);
111218822Sdim
112218822Sdimstatic int	ex_get_media(struct ex_softc *);
113218822Sdim
114218822Sdimstatic void	ex_reset(struct ex_softc *);
115218822Sdimstatic void	ex_setmulti(struct ex_softc *);
116218822Sdim
117218822Sdimstatic void	ex_tx_intr(struct ex_softc *);
118218822Sdimstatic void	ex_rx_intr(struct ex_softc *);
11939818Speter
120108777Sphkvoid
121108777Sphkex_get_address(struct ex_softc *sc, u_char *enaddr)
122218822Sdim{
12339818Speter	uint16_t	eaddr_tmp;
124218822Sdim
125218822Sdim	eaddr_tmp = ex_eeprom_read(sc, EE_Eth_Addr_Lo);
126218822Sdim	enaddr[5] = eaddr_tmp & 0xff;
127218822Sdim	enaddr[4] = eaddr_tmp >> 8;
128218822Sdim	eaddr_tmp = ex_eeprom_read(sc, EE_Eth_Addr_Mid);
12939818Speter	enaddr[3] = eaddr_tmp & 0xff;
130218822Sdim	enaddr[2] = eaddr_tmp >> 8;
131218822Sdim	eaddr_tmp = ex_eeprom_read(sc, EE_Eth_Addr_Hi);
132218822Sdim	enaddr[1] = eaddr_tmp & 0xff;
133218822Sdim	enaddr[0] = eaddr_tmp >> 8;
134218822Sdim
135218822Sdim	return;
136218822Sdim}
137218822Sdim
138218822Sdimint
139218822Sdimex_card_type(u_char *enaddr)
140218822Sdim{
141218822Sdim	if ((enaddr[0] == 0x00) && (enaddr[1] == 0xA0) && (enaddr[2] == 0xC9))
142218822Sdim		return (CARD_TYPE_EX_10_PLUS);
143218822Sdim
14439818Speter	return (CARD_TYPE_EX_10);
145218822Sdim}
14639818Speter
14739818Speter/*
148218822Sdim * Caller is responsible for eventually calling
14939818Speter * ex_release_resources() on failure.
150218822Sdim */
151218822Sdimint
152218822Sdimex_alloc_resources(device_t dev)
153218822Sdim{
154218822Sdim	struct ex_softc *	sc = device_get_softc(dev);
155218822Sdim	int			error = 0;
15639818Speter
15739818Speter	sc->ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
158218822Sdim					    &sc->ioport_rid, RF_ACTIVE);
159218822Sdim	if (!sc->ioport) {
160218822Sdim		device_printf(dev, "No I/O space?!\n");
16139818Speter		error = ENOMEM;
162218822Sdim		goto bad;
163218822Sdim	}
164218822Sdim
165218822Sdim	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
166218822Sdim					RF_ACTIVE);
16739818Speter
168218822Sdim	if (!sc->irq) {
16939818Speter		device_printf(dev, "No IRQ?!\n");
17039818Speter		error = ENOMEM;
17139818Speter		goto bad;
17239818Speter	}
17339818Speter
17439818Speterbad:
17539818Speter	return (error);
17639818Speter}
17739818Speter
17839818Spetervoid
17939818Speterex_release_resources(device_t dev)
18039818Speter{
18139818Speter	struct ex_softc *	sc = device_get_softc(dev);
182218822Sdim
18339818Speter	if (sc->ih) {
18439818Speter		bus_teardown_intr(dev, sc->irq, sc->ih);
18539818Speter		sc->ih = NULL;
18639818Speter	}
18739818Speter
18839818Speter	if (sc->ioport) {
18939818Speter		bus_release_resource(dev, SYS_RES_IOPORT,
19039818Speter					sc->ioport_rid, sc->ioport);
19139818Speter		sc->ioport = NULL;
19239818Speter	}
19339818Speter
194218822Sdim	if (sc->irq) {
195218822Sdim		bus_release_resource(dev, SYS_RES_IRQ,
196218822Sdim					sc->irq_rid, sc->irq);
197218822Sdim		sc->irq = NULL;
198218822Sdim	}
19939818Speter
200	if (sc->ifp)
201		if_free(sc->ifp);
202
203	return;
204}
205
206int
207ex_attach(device_t dev)
208{
209	struct ex_softc *	sc = device_get_softc(dev);
210	struct ifnet *		ifp;
211	struct ifmedia *	ifm;
212	int			error;
213	uint16_t		temp;
214
215	ifp = sc->ifp = if_alloc(IFT_ETHER);
216	if (ifp == NULL) {
217		device_printf(dev, "can not if_alloc()\n");
218		return (ENOSPC);
219	}
220	/* work out which set of irq <-> internal tables to use */
221	if (ex_card_type(sc->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	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
236	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
237	ifp->if_start = ex_start;
238	ifp->if_ioctl = ex_ioctl;
239	ifp->if_init = ex_init;
240	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
241
242	ifmedia_init(&sc->ifmedia, 0, ex_ifmedia_upd, ex_ifmedia_sts);
243	mtx_init(&sc->lock, device_get_nameunit(dev), MTX_NETWORK_LOCK,
244	    MTX_DEF);
245	callout_init_mtx(&sc->timer, &sc->lock, 0);
246
247	temp = ex_eeprom_read(sc, EE_W5);
248	if (temp & EE_W5_PORT_TPE)
249		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
250	if (temp & EE_W5_PORT_BNC)
251		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL);
252	if (temp & EE_W5_PORT_AUI)
253		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
254
255	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
256	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL);
257	ifmedia_set(&sc->ifmedia, ex_get_media(sc));
258
259	ifm = &sc->ifmedia;
260	ifm->ifm_media = ifm->ifm_cur->ifm_media;
261	ex_ifmedia_upd(ifp);
262
263	/*
264	 * Attach the interface.
265	 */
266	ether_ifattach(ifp, sc->enaddr);
267
268	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
269				NULL, ex_intr, (void *)sc, &sc->ih);
270	if (error) {
271		device_printf(dev, "bus_setup_intr() failed!\n");
272		ether_ifdetach(ifp);
273		mtx_destroy(&sc->lock);
274		return (error);
275	}
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->ifp;
288
289	EX_LOCK(sc);
290        ex_stop(sc);
291	EX_UNLOCK(sc);
292
293	ether_ifdetach(ifp);
294	callout_drain(&sc->timer);
295
296	ex_release_resources(dev);
297	mtx_destroy(&sc->lock);
298
299	return (0);
300}
301
302static void
303ex_init(void *xsc)
304{
305	struct ex_softc *	sc = (struct ex_softc *) xsc;
306
307	EX_LOCK(sc);
308	ex_init_locked(sc);
309	EX_UNLOCK(sc);
310}
311
312static void
313ex_init_locked(struct ex_softc *sc)
314{
315	struct ifnet *		ifp = sc->ifp;
316	int			i;
317	unsigned short		temp_reg;
318
319	DODEBUG(Start_End, printf("%s: ex_init: start\n", ifp->if_xname););
320
321	sc->tx_timeout = 0;
322
323	/*
324	 * Load the ethernet address into the card.
325	 */
326	CSR_WRITE_1(sc, CMD_REG, Bank2_Sel);
327	temp_reg = CSR_READ_1(sc, EEPROM_REG);
328	if (temp_reg & Trnoff_Enable)
329		CSR_WRITE_1(sc, EEPROM_REG, temp_reg & ~Trnoff_Enable);
330	for (i = 0; i < ETHER_ADDR_LEN; i++)
331		CSR_WRITE_1(sc, I_ADDR_REG0 + i, IF_LLADDR(sc->ifp)[i]);
332
333	/*
334	 * - Setup transmit chaining and discard bad received frames.
335	 * - Match broadcast.
336	 * - Clear test mode.
337	 * - Set receiving mode.
338	 */
339	CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr);
340	CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | No_SA_Ins | RX_CRC_InMem);
341	CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3) & 0x3f /* XXX constants. */ );
342	/*
343	 * - Set IRQ number, if this part has it.  ISA devices have this,
344	 * while PC Card devices don't seem to.  Either way, we have to
345	 * switch to Bank1 as the rest of this code relies on that.
346	 */
347	CSR_WRITE_1(sc, CMD_REG, Bank1_Sel);
348	if (sc->flags & HAS_INT_NO_REG)
349		CSR_WRITE_1(sc, INT_NO_REG,
350		    (CSR_READ_1(sc, INT_NO_REG) & 0xf8) |
351		    sc->irq2ee[sc->irq_no]);
352
353	/*
354	 * Divide the available memory in the card into rcv and xmt buffers.
355	 * By default, I use the first 3/4 of the memory for the rcv buffer,
356	 * and the remaining 1/4 of the memory for the xmt buffer.
357	 */
358	sc->rx_mem_size = sc->mem_size * 3 / 4;
359	sc->tx_mem_size = sc->mem_size - sc->rx_mem_size;
360	sc->rx_lower_limit = 0x0000;
361	sc->rx_upper_limit = sc->rx_mem_size - 2;
362	sc->tx_lower_limit = sc->rx_mem_size;
363	sc->tx_upper_limit = sc->mem_size - 2;
364	CSR_WRITE_1(sc, RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8);
365	CSR_WRITE_1(sc, RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8);
366	CSR_WRITE_1(sc, XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8);
367	CSR_WRITE_1(sc, XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8);
368
369	/*
370	 * Enable receive and transmit interrupts, and clear any pending int.
371	 */
372	CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) | TriST_INT);
373	CSR_WRITE_1(sc, CMD_REG, Bank0_Sel);
374	CSR_WRITE_1(sc, MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
375	CSR_WRITE_1(sc, STATUS_REG, All_Int);
376
377	/*
378	 * Initialize receive and transmit ring buffers.
379	 */
380	CSR_WRITE_2(sc, RCV_BAR, sc->rx_lower_limit);
381	sc->rx_head = sc->rx_lower_limit;
382	CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_upper_limit | 0xfe);
383	CSR_WRITE_2(sc, XMT_BAR, sc->tx_lower_limit);
384	sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
385
386	ifp->if_drv_flags |= IFF_DRV_RUNNING;
387	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
388	DODEBUG(Status, printf("OIDLE init\n"););
389	callout_reset(&sc->timer, hz, ex_watchdog, sc);
390
391	ex_setmulti(sc);
392
393	/*
394	 * Final reset of the board, and enable operation.
395	 */
396	CSR_WRITE_1(sc, CMD_REG, Sel_Reset_CMD);
397	DELAY(2);
398	CSR_WRITE_1(sc, CMD_REG, Rcv_Enable_CMD);
399
400	ex_start_locked(ifp);
401
402	DODEBUG(Start_End, printf("%s: ex_init: finish\n", ifp->if_xname););
403}
404
405static void
406ex_start(struct ifnet *ifp)
407{
408	struct ex_softc *	sc = ifp->if_softc;
409
410	EX_LOCK(sc);
411	ex_start_locked(ifp);
412	EX_UNLOCK(sc);
413}
414
415static void
416ex_start_locked(struct ifnet *ifp)
417{
418	struct ex_softc *	sc = ifp->if_softc;
419	int			i, len, data_len, avail, dest, next;
420	unsigned char		tmp16[2];
421	struct mbuf *		opkt;
422	struct mbuf *		m;
423
424	DODEBUG(Start_End, printf("ex_start%d: start\n", unit););
425
426	/*
427	 * Main loop: send outgoing packets to network card until there are no
428	 * more packets left, or the card cannot accept any more yet.
429	 */
430	while (((opkt = ifp->if_snd.ifq_head) != NULL) &&
431	       !(ifp->if_drv_flags & IFF_DRV_OACTIVE)) {
432
433		/*
434		 * Ensure there is enough free transmit buffer space for
435		 * this packet, including its header. Note: the header
436		 * cannot wrap around the end of the transmit buffer and
437		 * must be kept together, so we allow space for twice the
438		 * length of the header, just in case.
439		 */
440
441		for (len = 0, m = opkt; m != NULL; m = m->m_next) {
442			len += m->m_len;
443		}
444
445		data_len = len;
446
447		DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len););
448
449		if (len & 1) {
450			len += XMT_HEADER_LEN + 1;
451		} else {
452			len += XMT_HEADER_LEN;
453		}
454
455		if ((i = sc->tx_tail - sc->tx_head) >= 0) {
456			avail = sc->tx_mem_size - i;
457		} else {
458			avail = -i;
459		}
460
461		DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail););
462
463		if (avail >= len + XMT_HEADER_LEN) {
464			IF_DEQUEUE(&ifp->if_snd, opkt);
465
466#ifdef EX_PSA_INTR
467			/*
468			 * Disable rx and tx interrupts, to avoid corruption
469			 * of the host address register by interrupt service
470			 * routines.
471			 * XXX Is this necessary with splimp() enabled?
472			 */
473			CSR_WRITE_1(sc, MASK_REG, All_Int);
474#endif
475
476			/*
477			 * Compute the start and end addresses of this
478			 * frame in the tx buffer.
479			 */
480			dest = sc->tx_tail;
481			next = dest + len;
482
483			if (next > sc->tx_upper_limit) {
484				if ((sc->tx_upper_limit + 2 - sc->tx_tail) <=
485				    XMT_HEADER_LEN) {
486					dest = sc->tx_lower_limit;
487					next = dest + len;
488				} else {
489					next = sc->tx_lower_limit +
490						next - sc->tx_upper_limit - 2;
491				}
492			}
493
494			/*
495			 * Build the packet frame in the card's ring buffer.
496			 */
497			DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next););
498
499			CSR_WRITE_2(sc, HOST_ADDR_REG, dest);
500			CSR_WRITE_2(sc, IO_PORT_REG, Transmit_CMD);
501			CSR_WRITE_2(sc, IO_PORT_REG, 0);
502			CSR_WRITE_2(sc, IO_PORT_REG, next);
503			CSR_WRITE_2(sc, IO_PORT_REG, data_len);
504
505			/*
506			 * Output the packet data to the card. Ensure all
507			 * transfers are 16-bit wide, even if individual
508			 * mbufs have odd length.
509			 */
510			for (m = opkt, i = 0; m != NULL; m = m->m_next) {
511				DODEBUG(Sent_Pkts, printf("[%d]", m->m_len););
512				if (i) {
513					tmp16[1] = *(mtod(m, caddr_t));
514					CSR_WRITE_MULTI_2(sc, IO_PORT_REG,
515					    (uint16_t *) tmp16, 1);
516				}
517				CSR_WRITE_MULTI_2(sc, IO_PORT_REG,
518				    (uint16_t *) (mtod(m, caddr_t) + i),
519				    (m->m_len - i) / 2);
520				if ((i = (m->m_len - i) & 1) != 0) {
521					tmp16[0] = *(mtod(m, caddr_t) +
522						   m->m_len - 1);
523				}
524			}
525			if (i)
526				CSR_WRITE_MULTI_2(sc, IO_PORT_REG,
527				    (uint16_t *) tmp16, 1);
528			/*
529			 * If there were other frames chained, update the
530			 * chain in the last one.
531			 */
532			if (sc->tx_head != sc->tx_tail) {
533				if (sc->tx_tail != dest) {
534					CSR_WRITE_2(sc, HOST_ADDR_REG,
535					     sc->tx_last + XMT_Chain_Point);
536					CSR_WRITE_2(sc, IO_PORT_REG, dest);
537				}
538				CSR_WRITE_2(sc, HOST_ADDR_REG,
539				     sc->tx_last + XMT_Byte_Count);
540				i = CSR_READ_2(sc, IO_PORT_REG);
541				CSR_WRITE_2(sc, HOST_ADDR_REG,
542				     sc->tx_last + XMT_Byte_Count);
543				CSR_WRITE_2(sc, IO_PORT_REG, i | Ch_bit);
544			}
545
546			/*
547			 * Resume normal operation of the card:
548			 * - Make a dummy read to flush the DRAM write
549			 *   pipeline.
550			 * - Enable receive and transmit interrupts.
551			 * - Send Transmit or Resume_XMT command, as
552			 *   appropriate.
553			 */
554			CSR_READ_2(sc, IO_PORT_REG);
555#ifdef EX_PSA_INTR
556			CSR_WRITE_1(sc, MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
557#endif
558			if (sc->tx_head == sc->tx_tail) {
559				CSR_WRITE_2(sc, XMT_BAR, dest);
560				CSR_WRITE_1(sc, CMD_REG, Transmit_CMD);
561				sc->tx_head = dest;
562				DODEBUG(Sent_Pkts, printf("Transmit\n"););
563			} else {
564				CSR_WRITE_1(sc, CMD_REG, Resume_XMT_List_CMD);
565				DODEBUG(Sent_Pkts, printf("Resume\n"););
566			}
567
568			sc->tx_last = dest;
569			sc->tx_tail = next;
570
571			BPF_MTAP(ifp, opkt);
572
573			sc->tx_timeout = 2;
574			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
575			m_freem(opkt);
576		} else {
577			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
578			DODEBUG(Status, printf("OACTIVE start\n"););
579		}
580	}
581
582	DODEBUG(Start_End, printf("ex_start%d: finish\n", unit););
583}
584
585void
586ex_stop(struct ex_softc *sc)
587{
588
589	DODEBUG(Start_End, printf("ex_stop%d: start\n", unit););
590
591	EX_ASSERT_LOCKED(sc);
592	/*
593	 * Disable card operation:
594	 * - Disable the interrupt line.
595	 * - Flush transmission and disable reception.
596	 * - Mask and clear all interrupts.
597	 * - Reset the 82595.
598	 */
599	CSR_WRITE_1(sc, CMD_REG, Bank1_Sel);
600	CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) & ~TriST_INT);
601	CSR_WRITE_1(sc, CMD_REG, Bank0_Sel);
602	CSR_WRITE_1(sc, CMD_REG, Rcv_Stop);
603	sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
604	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. */
605	CSR_WRITE_1(sc, MASK_REG, All_Int);
606	CSR_WRITE_1(sc, STATUS_REG, All_Int);
607	CSR_WRITE_1(sc, CMD_REG, Reset_CMD);
608	DELAY(200);
609	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
610	sc->tx_timeout = 0;
611	callout_stop(&sc->timer);
612
613	DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit););
614
615	return;
616}
617
618void
619ex_intr(void *arg)
620{
621	struct ex_softc *sc = (struct ex_softc *)arg;
622	struct ifnet 	*ifp = sc->ifp;
623	int		int_status, send_pkts;
624	int		loops = 100;
625
626	DODEBUG(Start_End, printf("ex_intr%d: start\n", unit););
627
628	EX_LOCK(sc);
629	send_pkts = 0;
630	while (loops-- > 0 &&
631	    (int_status = CSR_READ_1(sc, STATUS_REG)) & (Tx_Int | Rx_Int)) {
632		/* don't loop forever */
633		if (int_status == 0xff)
634			break;
635		if (int_status & Rx_Int) {
636			CSR_WRITE_1(sc, STATUS_REG, Rx_Int);
637			ex_rx_intr(sc);
638		} else if (int_status & Tx_Int) {
639			CSR_WRITE_1(sc, STATUS_REG, Tx_Int);
640			ex_tx_intr(sc);
641			send_pkts = 1;
642		}
643	}
644	if (loops == 0)
645		printf("100 loops are not enough\n");
646
647	/*
648	 * If any packet has been transmitted, and there are queued packets to
649	 * be sent, attempt to send more packets to the network card.
650	 */
651	if (send_pkts && (ifp->if_snd.ifq_head != NULL))
652		ex_start_locked(ifp);
653	EX_UNLOCK(sc);
654
655	DODEBUG(Start_End, printf("ex_intr%d: finish\n", unit););
656
657	return;
658}
659
660static void
661ex_tx_intr(struct ex_softc *sc)
662{
663	struct ifnet *	ifp = sc->ifp;
664	int		tx_status;
665
666	DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit););
667
668	/*
669	 * - Cancel the watchdog.
670	 * For all packets transmitted since last transmit interrupt:
671	 * - Advance chain pointer to next queued packet.
672	 * - Update statistics.
673	 */
674
675	sc->tx_timeout = 0;
676
677	while (sc->tx_head != sc->tx_tail) {
678		CSR_WRITE_2(sc, HOST_ADDR_REG, sc->tx_head);
679
680		if (!(CSR_READ_2(sc, IO_PORT_REG) & Done_bit))
681			break;
682
683		tx_status = CSR_READ_2(sc, IO_PORT_REG);
684		sc->tx_head = CSR_READ_2(sc, IO_PORT_REG);
685
686		if (tx_status & TX_OK_bit) {
687			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
688		} else {
689			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
690		}
691
692		if_inc_counter(ifp, IFCOUNTER_COLLISIONS, tx_status & No_Collisions_bits);
693	}
694
695	/*
696	 * The card should be ready to accept more packets now.
697	 */
698
699	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
700
701	DODEBUG(Status, printf("OIDLE tx_intr\n"););
702	DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit););
703
704	return;
705}
706
707static void
708ex_rx_intr(struct ex_softc *sc)
709{
710	struct ifnet *		ifp = sc->ifp;
711	int			rx_status;
712	int			pkt_len;
713	int			QQQ;
714	struct mbuf *		m;
715	struct mbuf *		ipkt;
716	struct ether_header *	eh;
717
718	DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit););
719
720	/*
721	 * For all packets received since last receive interrupt:
722	 * - If packet ok, read it into a new mbuf and queue it to interface,
723	 *   updating statistics.
724	 * - If packet bad, just discard it, and update statistics.
725	 * Finally, advance receive stop limit in card's memory to new location.
726	 */
727
728	CSR_WRITE_2(sc, HOST_ADDR_REG, sc->rx_head);
729
730	while (CSR_READ_2(sc, IO_PORT_REG) == RCV_Done) {
731
732		rx_status = CSR_READ_2(sc, IO_PORT_REG);
733		sc->rx_head = CSR_READ_2(sc, IO_PORT_REG);
734		QQQ = pkt_len = CSR_READ_2(sc, IO_PORT_REG);
735
736		if (rx_status & RCV_OK_bit) {
737			MGETHDR(m, M_NOWAIT, MT_DATA);
738			ipkt = m;
739			if (ipkt == NULL) {
740				if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
741			} else {
742				ipkt->m_pkthdr.rcvif = ifp;
743				ipkt->m_pkthdr.len = pkt_len;
744				ipkt->m_len = MHLEN;
745
746				while (pkt_len > 0) {
747					if (pkt_len >= MINCLSIZE) {
748						MCLGET(m, M_NOWAIT);
749						if (m->m_flags & M_EXT) {
750							m->m_len = MCLBYTES;
751						} else {
752							m_freem(ipkt);
753							if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
754							goto rx_another;
755						}
756					}
757					m->m_len = min(m->m_len, pkt_len);
758
759	  /*
760	   * NOTE: I'm assuming that all mbufs allocated are of even length,
761	   * except for the last one in an odd-length packet.
762	   */
763
764					CSR_READ_MULTI_2(sc, IO_PORT_REG,
765					    mtod(m, uint16_t *), m->m_len / 2);
766
767					if (m->m_len & 1) {
768						*(mtod(m, caddr_t) + m->m_len - 1) = CSR_READ_1(sc, IO_PORT_REG);
769					}
770					pkt_len -= m->m_len;
771
772					if (pkt_len > 0) {
773						MGET(m->m_next, M_NOWAIT, MT_DATA);
774						if (m->m_next == NULL) {
775							m_freem(ipkt);
776							if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
777							goto rx_another;
778						}
779						m = m->m_next;
780						m->m_len = MLEN;
781					}
782				}
783				eh = mtod(ipkt, struct ether_header *);
784#ifdef EXDEBUG
785	if (debug_mask & Rcvd_Pkts) {
786		if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) {
787			printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":");
788			printf("%6D\n", eh->ether_dhost, ":");
789		} /* QQQ */
790	}
791#endif
792				EX_UNLOCK(sc);
793				(*ifp->if_input)(ifp, ipkt);
794				EX_LOCK(sc);
795				if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
796			}
797		} else {
798			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
799		}
800		CSR_WRITE_2(sc, HOST_ADDR_REG, sc->rx_head);
801rx_another: ;
802	}
803
804	if (sc->rx_head < sc->rx_lower_limit + 2)
805		CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_upper_limit);
806	else
807		CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_head - 2);
808
809	DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit););
810
811	return;
812}
813
814
815static int
816ex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
817{
818	struct ex_softc *	sc = ifp->if_softc;
819	struct ifreq *		ifr = (struct ifreq *)data;
820	int			error = 0;
821
822	DODEBUG(Start_End, printf("%s: ex_ioctl: start ", ifp->if_xname););
823
824	switch(cmd) {
825		case SIOCSIFADDR:
826		case SIOCGIFADDR:
827		case SIOCSIFMTU:
828			error = ether_ioctl(ifp, cmd, data);
829			break;
830
831		case SIOCSIFFLAGS:
832			DODEBUG(Start_End, printf("SIOCSIFFLAGS"););
833			EX_LOCK(sc);
834			if ((ifp->if_flags & IFF_UP) == 0 &&
835			    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
836				ex_stop(sc);
837			} else {
838      				ex_init_locked(sc);
839			}
840			EX_UNLOCK(sc);
841			break;
842		case SIOCADDMULTI:
843		case SIOCDELMULTI:
844			ex_init(sc);
845			error = 0;
846			break;
847		case SIOCSIFMEDIA:
848		case SIOCGIFMEDIA:
849			error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
850			break;
851		default:
852			DODEBUG(Start_End, printf("unknown"););
853			error = EINVAL;
854	}
855
856	DODEBUG(Start_End, printf("\n%s: ex_ioctl: finish\n", ifp->if_xname););
857
858	return(error);
859}
860
861static void
862ex_setmulti(struct ex_softc *sc)
863{
864	struct ifnet *ifp;
865	struct ifmultiaddr *maddr;
866	uint16_t *addr;
867	int count;
868	int timeout, status;
869
870	ifp = sc->ifp;
871
872	count = 0;
873	if_maddr_rlock(ifp);
874	TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
875		if (maddr->ifma_addr->sa_family != AF_LINK)
876			continue;
877		count++;
878	}
879	if_maddr_runlock(ifp);
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		CSR_WRITE_1(sc, CMD_REG, Bank2_Sel);
886		CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | Promisc_Mode);
887		CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3));
888		CSR_WRITE_1(sc, 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		CSR_WRITE_1(sc, CMD_REG, Bank2_Sel);
894		CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | Multi_IA);
895		CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3));
896		CSR_WRITE_1(sc, 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		CSR_WRITE_2(sc, HOST_ADDR_REG, sc->tx_lower_limit);
902		CSR_WRITE_2(sc, IO_PORT_REG, MC_Setup_CMD);
903		CSR_WRITE_2(sc, IO_PORT_REG, 0);
904		CSR_WRITE_2(sc, IO_PORT_REG, 0);
905		CSR_WRITE_2(sc, IO_PORT_REG, (count + 1) * 6);
906
907		if_maddr_rlock(ifp);
908		TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) {
909			if (maddr->ifma_addr->sa_family != AF_LINK)
910				continue;
911
912			addr = (uint16_t*)LLADDR((struct sockaddr_dl *)
913					maddr->ifma_addr);
914			CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
915			CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
916			CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
917		}
918		if_maddr_runlock(ifp);
919
920		/* Program our MAC address as well */
921		/* XXX: Is this necessary?  The Linux driver does this
922		 * but the NetBSD driver does not */
923		addr = (uint16_t*)IF_LLADDR(sc->ifp);
924		CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
925		CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
926		CSR_WRITE_2(sc, IO_PORT_REG, *addr++);
927
928		CSR_READ_2(sc, IO_PORT_REG);
929		CSR_WRITE_2(sc, XMT_BAR, sc->tx_lower_limit);
930		CSR_WRITE_1(sc, CMD_REG, MC_Setup_CMD);
931
932		sc->tx_head = sc->tx_lower_limit;
933		sc->tx_tail = sc->tx_head + XMT_HEADER_LEN + (count + 1) * 6;
934
935		for (timeout=0; timeout<100; timeout++) {
936			DELAY(2);
937			if ((CSR_READ_1(sc, STATUS_REG) & Exec_Int) == 0)
938				continue;
939
940			status = CSR_READ_1(sc, CMD_REG);
941			CSR_WRITE_1(sc, STATUS_REG, Exec_Int);
942			break;
943		}
944
945		sc->tx_head = sc->tx_tail;
946	}
947	else
948	{
949		/* No multicast or promiscuous mode */
950		CSR_WRITE_1(sc, CMD_REG, Bank2_Sel);
951		CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) & 0xDE);
952			/* ~(Multi_IA | Promisc_Mode) */
953		CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3));
954		CSR_WRITE_1(sc, CMD_REG, Bank0_Sel);
955	}
956}
957
958static void
959ex_reset(struct ex_softc *sc)
960{
961
962	DODEBUG(Start_End, printf("ex_reset%d: start\n", unit););
963
964	EX_ASSERT_LOCKED(sc);
965	ex_stop(sc);
966	ex_init_locked(sc);
967
968	DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit););
969
970	return;
971}
972
973static void
974ex_watchdog(void *arg)
975{
976	struct ex_softc *	sc = arg;
977	struct ifnet *ifp = sc->ifp;
978
979	if (sc->tx_timeout && --sc->tx_timeout == 0) {
980		DODEBUG(Start_End, if_printf(ifp, "ex_watchdog: start\n"););
981
982		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
983
984		DODEBUG(Status, printf("OIDLE watchdog\n"););
985
986		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
987		ex_reset(sc);
988		ex_start_locked(ifp);
989
990		DODEBUG(Start_End, if_printf(ifp, "ex_watchdog: finish\n"););
991	}
992
993	callout_reset(&sc->timer, hz, ex_watchdog, sc);
994}
995
996static int
997ex_get_media(struct ex_softc *sc)
998{
999	int	current;
1000	int	media;
1001
1002	media = ex_eeprom_read(sc, EE_W5);
1003
1004	CSR_WRITE_1(sc, CMD_REG, Bank2_Sel);
1005	current = CSR_READ_1(sc, REG3);
1006	CSR_WRITE_1(sc, CMD_REG, Bank0_Sel);
1007
1008	if ((current & TPE_bit) && (media & EE_W5_PORT_TPE))
1009		return(IFM_ETHER|IFM_10_T);
1010	if ((current & BNC_bit) && (media & EE_W5_PORT_BNC))
1011		return(IFM_ETHER|IFM_10_2);
1012
1013	if (media & EE_W5_PORT_AUI)
1014		return (IFM_ETHER|IFM_10_5);
1015
1016	return (IFM_ETHER|IFM_AUTO);
1017}
1018
1019static int
1020ex_ifmedia_upd(ifp)
1021	struct ifnet *		ifp;
1022{
1023	struct ex_softc *       sc = ifp->if_softc;
1024
1025	if (IFM_TYPE(sc->ifmedia.ifm_media) != IFM_ETHER)
1026		return EINVAL;
1027
1028	return (0);
1029}
1030
1031static void
1032ex_ifmedia_sts(ifp, ifmr)
1033	struct ifnet *          ifp;
1034	struct ifmediareq *     ifmr;
1035{
1036	struct ex_softc *       sc = ifp->if_softc;
1037
1038	EX_LOCK(sc);
1039	ifmr->ifm_active = ex_get_media(sc);
1040	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1041	EX_UNLOCK(sc);
1042
1043	return;
1044}
1045
1046u_short
1047ex_eeprom_read(struct ex_softc *sc, int location)
1048{
1049	int i;
1050	u_short data = 0;
1051	int read_cmd = location | EE_READ_CMD;
1052	short ctrl_val = EECS;
1053
1054	CSR_WRITE_1(sc, CMD_REG, Bank2_Sel);
1055	CSR_WRITE_1(sc, EEPROM_REG, EECS);
1056	for (i = 8; i >= 0; i--) {
1057		short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val;
1058		CSR_WRITE_1(sc, EEPROM_REG, outval);
1059		CSR_WRITE_1(sc, EEPROM_REG, outval | EESK);
1060		DELAY(3);
1061		CSR_WRITE_1(sc, EEPROM_REG, outval);
1062		DELAY(2);
1063	}
1064	CSR_WRITE_1(sc, EEPROM_REG, ctrl_val);
1065
1066	for (i = 16; i > 0; i--) {
1067		CSR_WRITE_1(sc, EEPROM_REG, ctrl_val | EESK);
1068		DELAY(3);
1069		data = (data << 1) |
1070		    ((CSR_READ_1(sc, EEPROM_REG) & EEDO) ? 1 : 0);
1071		CSR_WRITE_1(sc, EEPROM_REG, ctrl_val);
1072		DELAY(2);
1073	}
1074
1075	ctrl_val &= ~EECS;
1076	CSR_WRITE_1(sc, EEPROM_REG, ctrl_val | EESK);
1077	DELAY(3);
1078	CSR_WRITE_1(sc, EEPROM_REG, ctrl_val);
1079	DELAY(2);
1080	CSR_WRITE_1(sc, CMD_REG, Bank0_Sel);
1081	return(data);
1082}
1083