xref: /netbsd-src/sys/dev/isa/if_iy.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /*	$NetBSD: if_iy.c,v 1.109 2019/05/29 10:07:29 msaitoh Exp $	*/
2 /* #define IYDEBUG */
3 /* #define IYMEMDEBUG */
4 
5 /*-
6  * Copyright (c) 1996,2001 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Ignatios Souvatzis.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Supported hardware:
36  *
37  * - Intel EtherExpress Pro/10.
38  * - possibly other boards using the i82595 chip and no special tweaks.
39  */
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: if_iy.c,v 1.109 2019/05/29 10:07:29 msaitoh Exp $");
43 
44 #include "opt_inet.h"
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/mbuf.h>
49 #include <sys/buf.h>
50 #include <sys/protosw.h>
51 #include <sys/socket.h>
52 #include <sys/ioctl.h>
53 #include <sys/errno.h>
54 #include <sys/syslog.h>
55 #include <sys/device.h>
56 #include <sys/endian.h>
57 #include <sys/rndsource.h>
58 
59 #include <net/if.h>
60 #include <net/if_types.h>
61 #include <net/if_dl.h>
62 #include <net/bpf.h>
63 #include <net/if_ether.h>
64 #include <net/if_media.h>
65 
66 #ifdef INET
67 #include <netinet/in.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/in_var.h>
70 #include <netinet/ip.h>
71 #include <netinet/if_inarp.h>
72 #endif
73 
74 
75 #include <sys/cpu.h>
76 #include <sys/bus.h>
77 #include <sys/intr.h>
78 
79 #include <dev/isa/isareg.h>
80 #include <dev/isa/isavar.h>
81 #include <dev/ic/i82595reg.h>
82 
83 /* XXX why isn't this centralized? */
84 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
85 #define bus_space_write_stream_2	bus_space_write_2
86 #define bus_space_write_multi_stream_2	bus_space_write_multi_2
87 #define bus_space_read_stream_2		bus_space_read_2
88 #define bus_space_read_multi_stream_2	bus_space_read_multi_2
89 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
90 
91 /*
92  * Ethernet status, per interface.
93  */
94 struct iy_softc {
95 	device_t sc_dev;
96 	void *sc_ih;
97 
98 	bus_space_tag_t sc_iot;
99 	bus_space_handle_t sc_ioh;
100 
101 	struct ethercom sc_ethercom;
102 
103 	struct ifmedia iy_ifmedia;
104 	int iy_media;
105 
106 	int mappedirq;
107 
108 	int hard_vers;
109 
110 	int promisc;
111 
112 	int sram, tx_size, rx_size;
113 
114 	int tx_start, tx_end, tx_last;
115 	int rx_start;
116 
117 	int doing_mc_setup;
118 #ifdef IYDEBUG
119 	int sc_debug;
120 #endif
121 
122 	krndsource_t rnd_source;
123 };
124 
125 void iywatchdog(struct ifnet *);
126 int iyioctl(struct ifnet *, u_long, void *);
127 int iyintr(void *);
128 void iyinit(struct iy_softc *);
129 void iystop(struct iy_softc *);
130 void iystart(struct ifnet *);
131 
132 void iy_intr_rx(struct iy_softc *);
133 void iy_intr_tx(struct iy_softc *);
134 
135 void iyreset(struct iy_softc *);
136 void iy_readframe(struct iy_softc *, int);
137 void iy_drop_packet_buffer(struct iy_softc *);
138 void iy_find_mem_size(struct iy_softc *);
139 void iyrint(struct iy_softc *);
140 void iytint(struct iy_softc *);
141 void iyxmit(struct iy_softc *);
142 static void iy_mc_setup(struct iy_softc *);
143 static void iy_mc_reset(struct iy_softc *);
144 void iyget(struct iy_softc *, bus_space_tag_t, bus_space_handle_t, int);
145 void iyprobemem(struct iy_softc *);
146 static inline void eepromwritebit(bus_space_tag_t, bus_space_handle_t, int);
147 static inline int eepromreadbit(bus_space_tag_t, bus_space_handle_t);
148 
149 #ifdef IYDEBUGX
150 void print_rbd(volatile struct iy_recv_buf_desc *);
151 
152 int in_ifrint = 0;
153 int in_iftint = 0;
154 #endif
155 
156 int iy_mediachange(struct ifnet *);
157 void iy_mediastatus(struct ifnet *, struct ifmediareq *);
158 
159 int iyprobe(device_t, cfdata_t, void *);
160 void iyattach(device_t, device_t, void *);
161 
162 static uint16_t eepromread(bus_space_tag_t, bus_space_handle_t, int);
163 
164 static int eepromreadall(bus_space_tag_t, bus_space_handle_t, uint16_t *,
165     int);
166 
167 CFATTACH_DECL_NEW(iy, sizeof(struct iy_softc),
168     iyprobe, iyattach, NULL, NULL);
169 
170 static uint8_t eepro_irqmap[] = EEPP_INTMAP;
171 static uint8_t eepro_revirqmap[] = EEPP_RINTMAP;
172 
173 int
174 iyprobe(device_t parent, cfdata_t match, void *aux)
175 {
176 	struct isa_attach_args *ia = aux;
177 	uint16_t eaddr[8];
178 	bus_space_tag_t iot;
179 	bus_space_handle_t ioh;
180 	uint8_t c, d;
181 	int irq;
182 
183 	if (ia->ia_nio < 1)
184 		return 0;
185 	if (ia->ia_nirq < 1)
186 		return 0;
187 
188 	if (ISA_DIRECT_CONFIG(ia))
189 		return 0;
190 
191 	iot = ia->ia_iot;
192 
193 	if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
194 		return 0;
195 
196 	if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh))
197 		return 0;
198 
199 	/* try to find the round robin sig: */
200 
201 	c = bus_space_read_1(iot, ioh, ID_REG);
202 	if ((c & ID_REG_MASK) != ID_REG_SIG)
203 		goto out;
204 
205 	d = bus_space_read_1(iot, ioh, ID_REG);
206 	if ((d & ID_REG_MASK) != ID_REG_SIG)
207 		goto out;
208 
209 	if (((d-c) & R_ROBIN_BITS) != 0x40)
210 		goto out;
211 
212 	d = bus_space_read_1(iot, ioh, ID_REG);
213 	if ((d & ID_REG_MASK) != ID_REG_SIG)
214 		goto out;
215 
216 	if (((d-c) & R_ROBIN_BITS) != 0x80)
217 		goto out;
218 
219 	d = bus_space_read_1(iot, ioh, ID_REG);
220 	if ((d & ID_REG_MASK) != ID_REG_SIG)
221 		goto out;
222 
223 	if (((d-c) & R_ROBIN_BITS) != 0xC0)
224 		goto out;
225 
226 	d = bus_space_read_1(iot, ioh, ID_REG);
227 	if ((d & ID_REG_MASK) != ID_REG_SIG)
228 		goto out;
229 
230 	if (((d-c) & R_ROBIN_BITS) != 0x00)
231 		goto out;
232 
233 #ifdef IYDEBUG
234 		printf("iyprobe verified working ID reg.\n");
235 #endif
236 
237 	if (eepromreadall(iot, ioh, eaddr, 8))
238 		goto out;
239 
240 	if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ)
241 		irq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
242 	else
243 		irq = ia->ia_irq[0].ir_irq;
244 
245 	if (irq >= sizeof(eepro_revirqmap))
246 		goto out;
247 
248 	if (eepro_revirqmap[irq] == 0xff)
249 		goto out;
250 
251 	/* now lets reset the chip */
252 
253 	bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
254 	delay(200);
255 
256 	ia->ia_nio = 1;
257 	ia->ia_io[0].ir_size = 16;
258 
259 	ia->ia_nirq = 1;
260 	ia->ia_irq[0].ir_irq = irq;
261 
262 	ia->ia_niomem = 0;
263 	ia->ia_ndrq = 0;
264 
265 	bus_space_unmap(iot, ioh, 16);
266 	return 1;		/* found */
267 out:
268 	bus_space_unmap(iot, ioh, 16);
269 	return 0;
270 }
271 
272 void
273 iyattach(device_t parent, device_t self, void *aux)
274 {
275 	struct iy_softc *sc = device_private(self);
276 	struct isa_attach_args *ia = aux;
277 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
278 	bus_space_tag_t iot;
279 	bus_space_handle_t ioh;
280 	unsigned temp;
281 	uint16_t eaddr[8];
282 	uint8_t myaddr[ETHER_ADDR_LEN];
283 	int eirq;
284 
285 	iot = ia->ia_iot;
286 
287 	if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh)) {
288 		aprint_error(": can't map i/o space\n");
289 		return;
290 	}
291 
292 	sc->sc_iot = iot;
293 	sc->sc_ioh = ioh;
294 
295 	sc->mappedirq = eepro_revirqmap[ia->ia_irq[0].ir_irq];
296 
297 	/* now let's reset the chip */
298 
299 	bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
300 	delay(200);
301 
302 	iyprobemem(sc);
303 
304 	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
305 	ifp->if_softc = sc;
306 	ifp->if_start = iystart;
307 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
308 
309 	sc->doing_mc_setup = 0;
310 
311 	ifp->if_ioctl = iyioctl;
312 	ifp->if_watchdog = iywatchdog;
313 
314 	IFQ_SET_READY(&ifp->if_snd);
315 
316 	(void)eepromreadall(iot, ioh, eaddr, 8);
317 	sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev;
318 
319 #ifdef DIAGNOSTICS
320 	if ((eaddr[EEPPEther0] !=
321 	     eepromread(iot, ioh, EEPPEther0a)) &&
322 	    (eaddr[EEPPEther1] !=
323 	     eepromread(iot, ioh, EEPPEther1a)) &&
324 	    (eaddr[EEPPEther2] !=
325 	     eepromread(iot, ioh, EEPPEther2a)))
326 
327 		aprint_error("EEPROM Ethernet address differs from copy\n");
328 #endif
329 
330 	myaddr[1] = eaddr[EEPPEther0] & 0xFF;
331 	myaddr[0] = eaddr[EEPPEther0] >> 8;
332 	myaddr[3] = eaddr[EEPPEther1] & 0xFF;
333 	myaddr[2] = eaddr[EEPPEther1] >> 8;
334 	myaddr[5] = eaddr[EEPPEther2] & 0xFF;
335 	myaddr[4] = eaddr[EEPPEther2] >> 8;
336 
337 	/* Initialize ifmedia structures. */
338 	sc->sc_ethercom.ec_ifmedia = &sc->iy_ifmedia;
339 	ifmedia_init(&sc->iy_ifmedia, 0, iy_mediachange, iy_mediastatus);
340 	ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_2, 0, NULL);
341 	ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
342 	ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
343 	ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
344 	ifmedia_set(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO);
345 	/* Attach the interface. */
346 	if_attach(ifp);
347 	ether_ifattach(ifp, myaddr);
348 	aprint_normal(": address %s, rev. %d, %d kB\n",
349 	    ether_sprintf(myaddr),
350 	    sc->hard_vers, sc->sram/1024);
351 
352 	eirq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
353 	if (eirq != ia->ia_irq[0].ir_irq)
354 		aprint_error("%s: EEPROM irq setting %d ignored\n",
355 		    device_xname(sc->sc_dev), eirq);
356 
357 	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
358 	    IST_EDGE, IPL_NET, iyintr, sc);
359 
360 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
361 			  RND_TYPE_NET, RND_FLAG_DEFAULT);
362 
363 	temp = bus_space_read_1(iot, ioh, INT_NO_REG);
364 	bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
365 }
366 
367 void
368 iystop(struct iy_softc *sc)
369 {
370 	bus_space_tag_t iot;
371 	bus_space_handle_t ioh;
372 #ifdef IYDEBUG
373 	u_int p, v;
374 #endif
375 
376 	iot = sc->sc_iot;
377 	ioh = sc->sc_ioh;
378 
379 	bus_space_write_1(iot, ioh, COMMAND_REG, RCV_DISABLE_CMD);
380 
381 	bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
382 	bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS);
383 
384 	bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
385 	delay(200);
386 #ifdef IYDEBUG
387 	printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n",
388 	    device_xname(sc->sc_dev), sc->tx_start, sc->tx_end, sc->tx_last);
389 	p = sc->tx_last;
390 	if (!p)
391 		p = sc->tx_start;
392 	do {
393 		char sbuf[128];
394 
395 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, p);
396 
397 		v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
398 		snprintb(sbuf, sizeof(sbuf), "\020\006Ab\010Dn", v);
399 		printf("0x%04x: %s ", p, sbuf);
400 
401 		v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
402 		snprintb(sbuf, sizeof(sbuf),
403 		    "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN"
404 		    "\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL", v);
405 		printf("%s", sbuf);
406 
407 		p = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
408 		printf(" 0x%04x", p);
409 
410 		v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
411 		snprintb(sbuf, sizeof(sbuf), "\020\020Ch", v);
412 		printf(" %s\n", sbuf);
413 
414 	} while (v & 0x8000);
415 #endif
416 	sc->tx_start = sc->tx_end = sc->rx_size;
417 	sc->tx_last = 0;
418 	sc->sc_ethercom.ec_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
419 }
420 
421 void
422 iyreset(struct iy_softc *sc)
423 {
424 	int s;
425 	s = splnet();
426 	iystop(sc);
427 	iyinit(sc);
428 	splx(s);
429 }
430 
431 void
432 iyinit(struct iy_softc *sc)
433 {
434 	int i;
435 	unsigned temp;
436 	struct ifnet *ifp;
437 	bus_space_tag_t iot;
438 	bus_space_handle_t ioh;
439 
440 	iot = sc->sc_iot;
441 	ioh = sc->sc_ioh;
442 
443 	ifp = &sc->sc_ethercom.ec_if;
444 #ifdef IYDEBUG
445 	printf("ifp is %p\n", ifp);
446 #endif
447 
448 	bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
449 
450 	temp = bus_space_read_1(iot, ioh, EEPROM_REG);
451 	if (temp & 0x10)
452 		bus_space_write_1(iot, ioh, EEPROM_REG, temp & ~0x10);
453 
454 	for (i=0; i<6; ++i) {
455 		bus_space_write_1(iot, ioh, I_ADD(i), CLLADDR(ifp->if_sadl)[i]);
456 	}
457 
458 	temp = bus_space_read_1(iot, ioh, REG1);
459 	bus_space_write_1(iot, ioh, REG1,
460 	    temp | /* XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP | */ RCV_DISCARD_BAD);
461 
462 	if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))
463 		temp = MATCH_ALL;
464 	else
465 		temp = MATCH_BRDCST;
466 
467 	bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
468 
469 #ifdef IYDEBUG
470 	{
471 		char sbuf[128];
472 
473 		snprintb(sbuf, sizeof(sbuf),
474 		    "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA",
475 		    temp);
476 
477 		printf("%s: RECV_MODES set to %s\n", device_xname(sc->sc_dev),
478 		    sbuf);
479 	}
480 #endif
481 	/* XXX VOODOO */
482 	temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
483 	bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
484 	/* XXX END OF VOODOO */
485 
486 
487 	delay(500000); /* for the hardware to test for the connector */
488 
489 	temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
490 #ifdef IYDEBUG
491 	{
492 		char sbuf[128];
493 
494 		snprintb(sbuf, sizeof(sbuf),
495 		    "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
496 		    temp);
497 		printf("%s: media select was %s ", device_xname(sc->sc_dev),
498 		    sbuf);
499 	}
500 #endif
501 	temp = (temp & TEST_MODE_MASK);
502 
503 	switch (IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
504 	case IFM_10_5:
505 		temp &= ~ (BNC_BIT | TPE_BIT);
506 		break;
507 
508 	case IFM_10_2:
509 		temp = (temp & ~TPE_BIT) | BNC_BIT;
510 		break;
511 
512 	case IFM_10_T:
513 		temp = (temp & ~BNC_BIT) | TPE_BIT;
514 		break;
515 	default:
516 		;
517 		/* nothing; leave as it is */
518 	}
519 	switch (temp & (BNC_BIT | TPE_BIT)) {
520 	case BNC_BIT:
521 		sc->iy_media = IFM_ETHER | IFM_10_2;
522 		break;
523 	case TPE_BIT:
524 		sc->iy_media = IFM_ETHER | IFM_10_T;
525 		break;
526 	default:
527 		sc->iy_media = IFM_ETHER | IFM_10_5;
528 	}
529 
530 	bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
531 #ifdef IYDEBUG
532 	{
533 		char sbuf[128];
534 
535 		snprintb(sbuf, sizeof(sbuf),
536 		    "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
537 		    temp);
538 		printf("changed to %s\n", sbuf);
539 	}
540 #endif
541 
542 	bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
543 	bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
544 	bus_space_write_1(iot, ioh, 0, BANK_SEL(1));
545 
546 	temp = bus_space_read_1(iot, ioh, INT_NO_REG);
547 	bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
548 
549 #ifdef IYDEBUG
550 	{
551 		char sbuf[128];
552 
553 		snprintb(sbuf, sizeof(sbuf),
554 		    "\020\4bad_irq\010flash/boot present", temp);
555 
556 		printf("%s: int no was %s\n", device_xname(sc->sc_dev), sbuf);
557 
558 		temp = bus_space_read_1(iot, ioh, INT_NO_REG);
559 		snprintb(sbuf, sizeof(sbuf),
560 		    "\020\4bad_irq\010flash/boot present", temp);
561 		printf("%s: int no now %s\n", device_xname(sc->sc_dev), sbuf);
562 	}
563 #endif
564 
565 	bus_space_write_1(iot, ioh, RCV_LOWER_LIMIT_REG, 0);
566 	bus_space_write_1(iot, ioh, RCV_UPPER_LIMIT_REG, (sc->rx_size -2) >>8);
567 	bus_space_write_1(iot, ioh, XMT_LOWER_LIMIT_REG, sc->rx_size >>8);
568 	bus_space_write_1(iot, ioh, XMT_UPPER_LIMIT_REG, (sc->sram - 2) >>8);
569 
570 	temp = bus_space_read_1(iot, ioh, REG1);
571 #ifdef IYDEBUG
572 	{
573 		char sbuf[128];
574 
575 		snprintb(sbuf, sizeof(sbuf), "\020\2WORD_WIDTH\010INT_ENABLE",
576 		    temp);
577 
578 		printf("%s: HW access is %s\n", device_xname(sc->sc_dev), sbuf);
579 	}
580 #endif
581 	bus_space_write_1(iot, ioh, REG1, temp | INT_ENABLE); /* XXX what about WORD_WIDTH? */
582 
583 #ifdef IYDEBUG
584 	{
585 		char sbuf[128];
586 
587 		temp = bus_space_read_1(iot, ioh, REG1);
588 		snprintb(sbuf, sizeof(sbuf), "\020\2WORD_WIDTH\010INT_ENABLE",
589 		    temp);
590 		printf("%s: HW access is %s\n", device_xname(sc->sc_dev), sbuf);
591 	}
592 #endif
593 
594 	bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
595 
596 	bus_space_write_1(iot, ioh, INT_MASK_REG,
597 	    ALL_INTS & ~(RX_BIT | TX_BIT));
598 	bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS); /* clear ints */
599 
600 	bus_space_write_1(iot, ioh, RCV_COPY_THRESHOLD, 0);
601 
602 	bus_space_write_2(iot, ioh, RCV_START_LOW, 0);
603 	bus_space_write_2(iot, ioh, RCV_STOP_LOW,  sc->rx_size - 2);
604 	sc->rx_start = 0;
605 
606 	bus_space_write_1(iot, ioh, 0, SEL_RESET_CMD);
607 	delay(200);
608 
609 	bus_space_write_2(iot, ioh, XMT_ADDR_REG, sc->rx_size);
610 
611 	sc->tx_start = sc->tx_end = sc->rx_size;
612 	sc->tx_last = 0;
613 
614 	bus_space_write_1(iot, ioh, 0, RCV_ENABLE_CMD);
615 
616 	ifp->if_flags |= IFF_RUNNING;
617 	ifp->if_flags &= ~IFF_OACTIVE;
618 }
619 
620 void
621 iystart(struct ifnet *ifp)
622 {
623 	struct iy_softc *sc;
624 
625 
626 	struct mbuf *m0, *m;
627 	u_int len, pad, last, end;
628 	u_int llen, residual;
629 	int avail;
630 	char *data;
631 	unsigned temp;
632 	uint16_t resval, stat;
633 	bus_space_tag_t iot;
634 	bus_space_handle_t ioh;
635 
636 #ifdef IYDEBUG
637 	printf("iystart called\n");
638 #endif
639 	sc = ifp->if_softc;
640 
641 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
642 		return;
643 
644 	iy_intr_tx(sc);
645 
646 	iot = sc->sc_iot;
647 	ioh = sc->sc_ioh;
648 
649 	for (;;) {
650 		IFQ_POLL(&ifp->if_snd, m0);
651 		if (m0 == NULL)
652 			break;
653 #ifdef IYDEBUG
654 		printf("%s: trying to write another packet to the hardware\n",
655 		    device_xname(sc->sc_dev));
656 #endif
657 
658 		/* We need to use m->m_pkthdr.len, so require the header */
659 		if ((m0->m_flags & M_PKTHDR) == 0)
660 			panic("iystart: no header mbuf");
661 
662 		len = m0->m_pkthdr.len;
663 		pad = len & 1;
664 
665 #ifdef IYDEBUG
666 		printf("%s: length is %d.\n", device_xname(sc->sc_dev), len);
667 #endif
668 		if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
669 			pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
670 		}
671 
672 		if (len + pad > ETHER_MAX_LEN) {
673 			/* packet is obviously too large: toss it */
674 			++ifp->if_oerrors;
675 			IFQ_DEQUEUE(&ifp->if_snd, m0);
676 			m_freem(m0);
677 			continue;
678 		}
679 
680 		bpf_mtap(ifp, m0, BPF_D_OUT);
681 
682 		avail = sc->tx_start - sc->tx_end;
683 		if (avail <= 0)
684 			avail += sc->tx_size;
685 
686 #ifdef IYDEBUG
687 		printf("%s: avail is %d.\n", device_xname(sc->sc_dev), avail);
688 #endif
689 		/*
690 		 * we MUST RUN at splnet here  ---
691 		 * XXX todo: or even turn off the boards ints ??? hm...
692 		 */
693 
694 		/* See if there is room to put another packet in the buffer. */
695 
696 		if ((len+pad+2*I595_XMT_HDRLEN) > avail) {
697 #ifdef IYDEBUG
698 			printf("%s: len = %d, avail = %d, setting OACTIVE\n",
699 			    device_xname(sc->sc_dev), len, avail);
700 #endif
701 			/* mark interface as full ... */
702 			ifp->if_flags |= IFF_OACTIVE;
703 
704 			/* and wait for any transmission result */
705 			bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
706 
707 			temp = bus_space_read_1(iot, ioh, REG1);
708 			bus_space_write_1(iot, ioh, REG1,
709 				temp & ~XMT_CHAIN_INT);
710 
711 			bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
712 
713 			return;
714 		}
715 
716 		/* we know it fits in the hardware now, so dequeue it */
717 		IFQ_DEQUEUE(&ifp->if_snd, m0);
718 
719 		last = sc->tx_end;
720 		end = last + pad + len + I595_XMT_HDRLEN;
721 
722 		if (end >= sc->sram) {
723 			if ((sc->sram - last) <= I595_XMT_HDRLEN) {
724 				/* keep header in one piece */
725 				last = sc->rx_size;
726 				end = last + pad + len + I595_XMT_HDRLEN;
727 			} else
728 				end -= sc->tx_size;
729 		}
730 
731 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
732 		bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
733 			htole16(XMT_CMD));
734 
735 		bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
736 		bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
737 
738 		bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
739 			htole16(len + pad));
740 
741 		residual = resval = 0;
742 
743 		while ((m = m0)!=0) {
744 			data = mtod(m, void *);
745 			llen = m->m_len;
746 			if (residual) {
747 #ifdef IYDEBUG
748 				printf("%s: merging residual with next mbuf.\n",
749 				    device_xname(sc->sc_dev));
750 #endif
751 				resval |= *data << 8;
752 				bus_space_write_stream_2(iot, ioh,
753 					MEM_PORT_REG, resval);
754 				--llen;
755 				++data;
756 			}
757 			/*
758 			 * XXX ALIGNMENT LOSSAGE HERE.
759 			 */
760 			if (llen > 1)
761 				bus_space_write_multi_stream_2(iot, ioh,
762 					MEM_PORT_REG, (uint16_t *) data,
763 					llen>>1);
764 			residual = llen & 1;
765 			if (residual) {
766 				resval = *(data + llen - 1);
767 #ifdef IYDEBUG
768 				printf("%s: got odd mbuf to send.\n",
769 				    device_xname(sc->sc_dev));
770 #endif
771 			}
772 
773 			m0 = m_free(m);
774 		}
775 
776 		if (residual)
777 			bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
778 				resval);
779 
780 		pad >>= 1;
781 		while (pad-- > 0)
782 			bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, 0);
783 
784 #ifdef IYDEBUG
785 		printf("%s: new last = 0x%x, end = 0x%x.\n",
786 		    device_xname(sc->sc_dev), last, end);
787 		printf("%s: old start = 0x%x, end = 0x%x, last = 0x%x\n",
788 		    device_xname(sc->sc_dev), sc->tx_start, sc->tx_end,
789 		    sc->tx_last);
790 #endif
791 
792 		if (sc->tx_start != sc->tx_end) {
793 			bus_space_write_2(iot, ioh, HOST_ADDR_REG,
794 				sc->tx_last + XMT_COUNT);
795 
796 			/*
797 			 * XXX We keep stat in le order, to potentially save
798 			 * a byte swap.
799 			 */
800 			stat = bus_space_read_stream_2(iot, ioh, MEM_PORT_REG);
801 
802 			bus_space_write_2(iot, ioh, HOST_ADDR_REG,
803 				sc->tx_last + XMT_CHAIN);
804 
805 			bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
806 				htole16(last));
807 
808 			bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
809 				stat | htole16(CHAIN));
810 #ifdef IYDEBUG
811 			printf("%s: setting 0x%x to 0x%x\n",
812 			    device_xname(sc->sc_dev), sc->tx_last + XMT_COUNT,
813 			    le16toh(stat) | CHAIN);
814 #endif
815 		}
816 		/* dummy read */
817 		stat = bus_space_read_2(iot, ioh, MEM_PORT_REG);
818 
819 		/* XXX todo: enable ints here if disabled */
820 
821 		++ifp->if_opackets;
822 
823 		if (sc->tx_start == sc->tx_end) {
824 			bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
825 			bus_space_write_1(iot, ioh, 0, XMT_CMD);
826 			sc->tx_start = last;
827 #ifdef IYDEBUG
828 			printf("%s: writing 0x%x to XAR and giving XCMD\n",
829 			    device_xname(sc->sc_dev), last);
830 #endif
831 		} else {
832 			bus_space_write_1(iot, ioh, 0, RESUME_XMT_CMD);
833 #ifdef IYDEBUG
834 			printf("%s: giving RESUME_XCMD\n",
835 			    device_xname(sc->sc_dev));
836 #endif
837 		}
838 		sc->tx_last = last;
839 		sc->tx_end = end;
840 	}
841 	/* and wait only for end of transmission chain */
842 	bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
843 
844 	temp = bus_space_read_1(iot, ioh, REG1);
845 	bus_space_write_1(iot, ioh, REG1, temp | XMT_CHAIN_INT);
846 
847 	bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
848 }
849 
850 
851 static inline void
852 eepromwritebit(bus_space_tag_t iot, bus_space_handle_t ioh, int what)
853 {
854 	bus_space_write_1(iot, ioh, EEPROM_REG, what);
855 	delay(1);
856 	bus_space_write_1(iot, ioh, EEPROM_REG, what | EESK);
857 	delay(1);
858 	bus_space_write_1(iot, ioh, EEPROM_REG, what);
859 	delay(1);
860 }
861 
862 static inline int
863 eepromreadbit(bus_space_tag_t iot, bus_space_handle_t ioh)
864 {
865 	int b;
866 
867 	bus_space_write_1(iot, ioh, EEPROM_REG, EECS | EESK);
868 	delay(1);
869 	b = bus_space_read_1(iot, ioh, EEPROM_REG);
870 	bus_space_write_1(iot, ioh, EEPROM_REG, EECS);
871 	delay(1);
872 
873 	return ((b & EEDO) != 0);
874 }
875 
876 static uint16_t
877 eepromread(bus_space_tag_t iot, bus_space_handle_t ioh, int offset)
878 {
879 	volatile int i;
880 	volatile int j;
881 	volatile uint16_t readval;
882 
883 	bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
884 	delay(1);
885 	bus_space_write_1(iot, ioh, EEPROM_REG, EECS); /* XXXX??? */
886 	delay(1);
887 
888 	eepromwritebit(iot, ioh, EECS | EEDI);
889 	eepromwritebit(iot, ioh, EECS | EEDI);
890 	eepromwritebit(iot, ioh, EECS);
891 
892 	for (j=5; j>=0; --j) {
893 		if ((offset>>j) & 1)
894 			eepromwritebit(iot, ioh, EECS | EEDI);
895 		else
896 			eepromwritebit(iot, ioh, EECS);
897 	}
898 
899 	for (readval=0, i=0; i<16; ++i) {
900 		readval<<=1;
901 		readval |= eepromreadbit(iot, ioh);
902 	}
903 
904 	bus_space_write_1(iot, ioh, EEPROM_REG, 0 | EESK);
905 	delay(1);
906 	bus_space_write_1(iot, ioh, EEPROM_REG, 0);
907 
908 	bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
909 
910 	return readval;
911 }
912 
913 /*
914  * Device timeout/watchdog routine.  Entered if the device neglects to generate
915  * an interrupt after a transmit has been started on it.
916  */
917 void
918 iywatchdog(struct ifnet *ifp)
919 {
920 	struct iy_softc *sc = ifp->if_softc;
921 
922 	log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
923 	++sc->sc_ethercom.ec_if.if_oerrors;
924 	iyreset(sc);
925 }
926 
927 /*
928  * What to do upon receipt of an interrupt.
929  */
930 int
931 iyintr(void *arg)
932 {
933 	struct iy_softc *sc;
934 	struct ifnet *ifp;
935 	bus_space_tag_t iot;
936 	bus_space_handle_t ioh;
937 
938 	u_short status;
939 
940 	sc = arg;
941 	iot = sc->sc_iot;
942 	ioh = sc->sc_ioh;
943 
944 	ifp = &sc->sc_ethercom.ec_if;
945 
946 	status = bus_space_read_1(iot, ioh, STATUS_REG);
947 #ifdef IYDEBUG
948 	if (status & ALL_INTS) {
949 		char sbuf[128];
950 
951 		snprintb(sbuf, sizeof(sbuf), "\020\1RX_STP\2RX\3TX\4EXEC",
952 		    status);
953 		printf("%s: got interrupt %s", device_xname(sc->sc_dev), sbuf);
954 
955 		if (status & EXEC_INT) {
956 			snprintb(sbuf, sizeof(sbuf),
957 			     "\020\6ABORT", bus_space_read_1(iot, ioh, 0));
958 			printf(" event %s\n", sbuf);
959 		} else
960 			printf("\n");
961 	}
962 #endif
963 	if ((status & (RX_INT | TX_INT)) == 0)
964 		return 0;
965 
966 	if (status & RX_INT) {
967 		iy_intr_rx(sc);
968 		bus_space_write_1(iot, ioh, STATUS_REG, RX_INT);
969 	}
970 	if (status & TX_INT) {
971 		/* Tell feeders we may be able to accept more data... */
972 		ifp->if_flags &= ~IFF_OACTIVE;
973 		/* and get more data. */
974 		iystart(ifp);
975 		bus_space_write_1(iot, ioh, STATUS_REG, TX_INT);
976 	}
977 
978 	rnd_add_uint32(&sc->rnd_source, status);
979 
980 	return 1;
981 }
982 
983 void
984 iyget(struct iy_softc *sc, bus_space_tag_t iot, bus_space_handle_t ioh,
985     int rxlen)
986 {
987 	struct mbuf *m, *top, **mp;
988 	struct ifnet *ifp;
989 	int len;
990 
991 	ifp = &sc->sc_ethercom.ec_if;
992 
993 	MGETHDR(m, M_DONTWAIT, MT_DATA);
994 	if (m == 0)
995 		goto dropped;
996 	m_set_rcvif(m, ifp);
997 	m->m_pkthdr.len = rxlen;
998 	len = MHLEN;
999 	top = 0;
1000 	mp = &top;
1001 
1002 	while (rxlen > 0) {
1003 		if (top) {
1004 			MGET(m, M_DONTWAIT, MT_DATA);
1005 			if (m == 0) {
1006 				m_freem(top);
1007 				goto dropped;
1008 			}
1009 			len = MLEN;
1010 		}
1011 		if (rxlen >= MINCLSIZE) {
1012 			MCLGET(m, M_DONTWAIT);
1013 			if ((m->m_flags & M_EXT) == 0) {
1014 				m_free(m);
1015 				m_freem(top);
1016 				goto dropped;
1017 			}
1018 			len = MCLBYTES;
1019 		}
1020 		len = uimin(rxlen, len);
1021 		/*
1022 		 * XXX ALIGNMENT LOSSAGE HERE.
1023 		 */
1024 		if (len > 1) {
1025 			len &= ~1;
1026 
1027 			bus_space_read_multi_stream_2(iot, ioh, MEM_PORT_REG,
1028 			    mtod(m, uint16_t *), len / 2);
1029 		} else {
1030 #ifdef IYDEBUG
1031 			printf("%s: received odd mbuf\n",
1032 			    device_xname(sc->sc_dev));
1033 #endif
1034 			*(mtod(m, char *)) = bus_space_read_stream_2(iot, ioh,
1035 			    MEM_PORT_REG);
1036 		}
1037 		m->m_len = len;
1038 		rxlen -= len;
1039 		*mp = m;
1040 		mp = &m->m_next;
1041 	}
1042 
1043 	if (top == NULL)
1044 		return;
1045 
1046 	if_percpuq_enqueue(ifp->if_percpuq, top);
1047 	return;
1048 
1049 dropped:
1050 	++ifp->if_ierrors;
1051 	return;
1052 }
1053 
1054 void
1055 iy_intr_rx(struct iy_softc *sc)
1056 {
1057 	bus_space_tag_t iot;
1058 	bus_space_handle_t ioh;
1059 
1060 	u_int rxadrs, rxevnt, rxstatus, rxnext, rxlen;
1061 
1062 	iot = sc->sc_iot;
1063 	ioh = sc->sc_ioh;
1064 
1065 	rxadrs = sc->rx_start;
1066 	bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxadrs);
1067 	rxevnt = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
1068 	rxnext = 0;
1069 
1070 	while (rxevnt == RCV_DONE) {
1071 		rxstatus = le16toh(bus_space_read_stream_2(iot, ioh,
1072 				MEM_PORT_REG));
1073 		rxnext = le16toh(bus_space_read_stream_2(iot, ioh,
1074 				MEM_PORT_REG));
1075 		rxlen = le16toh(bus_space_read_stream_2(iot, ioh,
1076 				MEM_PORT_REG));
1077 #ifdef IYDEBUG
1078 		{
1079 			char sbuf[128];
1080 
1081 			snprintb(sbuf, sizeof(sbuf),
1082 			    "\020\1RCLD\2IA_MCH\010SHORT\011OVRN\013ALGERR"
1083 			    "\014CRCERR\015LENERR\016RCVOK\020TYP", rxstatus);
1084 
1085 			printf("%s: pck at 0x%04x stat %s next 0x%x len 0x%x\n",
1086 			    device_xname(sc->sc_dev), rxadrs, sbuf, rxnext,
1087 			    rxlen);
1088 		}
1089 #else
1090 		__USE(rxstatus);
1091 #endif
1092 		iyget(sc, iot, ioh, rxlen);
1093 
1094 		/* move stop address */
1095 		bus_space_write_2(iot, ioh, RCV_STOP_LOW,
1096 			    rxnext == 0 ? sc->rx_size - 2 : rxnext - 2);
1097 
1098 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxnext);
1099 		rxadrs = rxnext;
1100 		rxevnt = le16toh(bus_space_read_stream_2(iot, ioh,
1101 				MEM_PORT_REG));
1102 	}
1103 	sc->rx_start = rxnext;
1104 }
1105 
1106 void
1107 iy_intr_tx(struct iy_softc *sc)
1108 {
1109 	bus_space_tag_t iot;
1110 	bus_space_handle_t ioh;
1111 	struct ifnet *ifp;
1112 	u_int txstatus, txstat2, txlen, txnext;
1113 
1114 	ifp = &sc->sc_ethercom.ec_if;
1115 	iot = sc->sc_iot;
1116 	ioh = sc->sc_ioh;
1117 
1118 	while (sc->tx_start != sc->tx_end) {
1119 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, sc->tx_start);
1120 		txstatus = le16toh(bus_space_read_stream_2(iot, ioh,
1121 			MEM_PORT_REG));
1122 
1123 		if ((txstatus & (TX_DONE | CMD_MASK)) != (TX_DONE | XMT_CMD))
1124 			break;
1125 
1126 		txstat2 = le16toh(bus_space_read_stream_2(iot, ioh,
1127 				MEM_PORT_REG));
1128 		txnext = le16toh(bus_space_read_stream_2(iot, ioh,
1129 				MEM_PORT_REG));
1130 		txlen = le16toh(bus_space_read_stream_2(iot, ioh,
1131 				MEM_PORT_REG));
1132 #ifdef IYDEBUG
1133 		{
1134 			char sbuf[128];
1135 
1136 			snprintb(sbuf, sizeof(sbuf),
1137 			    "\020\6MAX_COL\7HRT_BEAT\010TX_DEF"
1138 			    "\011UND_RUN\012JERR\013LST_CRS"
1139 			    "\014LTCOL\016TX_OK\020COLL", txstat2);
1140 
1141 			printf("txstat 0x%x stat2 %s next 0x%x len 0x%x\n",
1142 			       txstatus, sbuf, txnext, txlen);
1143 		}
1144 #endif
1145 		if (txlen & CHAIN)
1146 			sc->tx_start = txnext;
1147 		else
1148 			sc->tx_start = sc->tx_end;
1149 		ifp->if_flags &= ~IFF_OACTIVE;
1150 
1151 		if (txstat2 & 0x0020)
1152 			ifp->if_collisions += 16;
1153 		else
1154 			ifp->if_collisions += txstat2 & 0x000f;
1155 
1156 		if ((txstat2 & 0x2000) == 0)
1157 			++ifp->if_oerrors;
1158 	}
1159 }
1160 
1161 int
1162 iyioctl(struct ifnet *ifp, u_long cmd, void *data)
1163 {
1164 	struct iy_softc *sc;
1165 	struct ifaddr *ifa;
1166 	int s, error = 0;
1167 
1168 	sc = ifp->if_softc;
1169 	ifa = (struct ifaddr *)data;
1170 
1171 #ifdef IYDEBUG
1172 	printf("iyioctl called with ifp %p (%s) cmd 0x%lx data %p\n",
1173 	    ifp, ifp->if_xname, cmd, data);
1174 #endif
1175 
1176 	s = splnet();
1177 
1178 	switch (cmd) {
1179 
1180 	case SIOCINITIFADDR:
1181 		ifp->if_flags |= IFF_UP;
1182 
1183 		iyinit(sc);
1184 		switch (ifa->ifa_addr->sa_family) {
1185 #ifdef INET
1186 		case AF_INET:
1187 			arp_ifinit(ifp, ifa);
1188 			break;
1189 #endif
1190 		default:
1191 			break;
1192 		}
1193 		break;
1194 
1195 	case SIOCSIFFLAGS:
1196 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1197 			break;
1198 		sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1199 		/* XXX re-use ether_ioctl() */
1200 		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
1201 		case IFF_RUNNING:
1202 			/*
1203 			 * If interface is marked down and it is running, then
1204 			 * stop it.
1205 			 */
1206 			iystop(sc);
1207 			ifp->if_flags &= ~IFF_RUNNING;
1208 			break;
1209 		case IFF_UP:
1210 			/*
1211 			 * If interface is marked up and it is stopped, then
1212 			 * start it.
1213 			 */
1214 			iyinit(sc);
1215 			break;
1216 		default:
1217 			/*
1218 			 * Reset the interface to pick up changes in any other
1219 			 * flags that affect hardware registers.
1220 			 */
1221 			iystop(sc);
1222 			iyinit(sc);
1223 			break;
1224 		}
1225 #ifdef IYDEBUGX
1226 		if (ifp->if_flags & IFF_DEBUG)
1227 			sc->sc_debug = IFY_ALL;
1228 		else
1229 			sc->sc_debug = 0;
1230 #endif
1231 		break;
1232 
1233 	case SIOCADDMULTI:
1234 	case SIOCDELMULTI:
1235 		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
1236 			/*
1237 			 * Multicast list has changed; set the hardware filter
1238 			 * accordingly.
1239 			 */
1240 			if (ifp->if_flags & IFF_RUNNING) {
1241 				/* XXX can't make it work otherwise */
1242 				iyreset(sc);
1243 				iy_mc_reset(sc);
1244 			}
1245 			error = 0;
1246 		}
1247 		break;
1248 
1249 	default:
1250 		error = ether_ioctl(ifp, cmd, data);
1251 	}
1252 	splx(s);
1253 	return error;
1254 }
1255 
1256 int
1257 iy_mediachange(struct ifnet *ifp)
1258 {
1259 	struct iy_softc *sc = ifp->if_softc;
1260 
1261 	if (IFM_TYPE(sc->iy_ifmedia.ifm_media) != IFM_ETHER)
1262 	    return EINVAL;
1263 	switch (IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
1264 	case IFM_10_5:
1265 	case IFM_10_2:
1266 	case IFM_10_T:
1267 	case IFM_AUTO:
1268 	    iystop(sc);
1269 	    iyinit(sc);
1270 	    return 0;
1271 	default:
1272 	    return EINVAL;
1273 	}
1274 }
1275 
1276 void
1277 iy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1278 {
1279 	struct iy_softc *sc = ifp->if_softc;
1280 
1281 	ifmr->ifm_active = sc->iy_media;
1282 	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1283 }
1284 
1285 
1286 static void
1287 iy_mc_setup(struct iy_softc *sc)
1288 {
1289 	struct ether_multi *enm;
1290 	struct ether_multistep step;
1291 	struct ethercom *ecp;
1292 	struct ifnet *ifp;
1293 	bus_space_tag_t iot;
1294 	bus_space_handle_t ioh;
1295 	int avail, last /*, end*/ , len;
1296 	int timeout;
1297 	volatile uint16_t dum;
1298 	uint8_t temp;
1299 
1300 
1301 	ecp = &sc->sc_ethercom;
1302 	ifp = &ecp->ec_if;
1303 
1304 	iot = sc->sc_iot;
1305 	ioh = sc->sc_ioh;
1306 
1307 	len = 6 * ecp->ec_multicnt;
1308 
1309 	avail = sc->tx_start - sc->tx_end;
1310 	if (avail <= 0)
1311 		avail += sc->tx_size;
1312 	if (ifp->if_flags & IFF_DEBUG)
1313 		printf("%s: iy_mc_setup called, %d addresses, "
1314 		    "%d/%d bytes needed/avail\n", ifp->if_xname,
1315 		    ecp->ec_multicnt, len + I595_XMT_HDRLEN, avail);
1316 
1317 	last = sc->rx_size;
1318 
1319 	bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
1320 	bus_space_write_1(iot, ioh, RECV_MODES_REG, MATCH_BRDCST);
1321 	/* XXX VOODOO */
1322 	temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
1323 	bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
1324 	/* XXX END OF VOODOO */
1325 	bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
1326 	bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
1327 	bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(MC_SETUP_CMD));
1328 	bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1329 	bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1330 	bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(len));
1331 
1332 	ETHER_LOCK(ecp);
1333 	ETHER_FIRST_MULTI(step, ecp, enm);
1334 	while (enm) {
1335 		/*
1336 		 * XXX ALIGNMENT LOSSAGE HERE?
1337 		 */
1338 		bus_space_write_multi_stream_2(iot, ioh, MEM_PORT_REG,
1339 		    (uint16_t *) enm->enm_addrlo, 3);
1340 
1341 		ETHER_NEXT_MULTI(step, enm);
1342 	}
1343 	ETHER_UNLOCK(ecp);
1344 	dum = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
1345 	__USE(dum);
1346 	bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
1347 	bus_space_write_1(iot, ioh, 0, MC_SETUP_CMD);
1348 
1349 
1350 	sc->tx_start =	sc->rx_size;
1351 	sc->tx_end = sc->rx_size + I595_XMT_HDRLEN + len;
1352 
1353 	for (timeout=0; timeout<100; timeout++) {
1354 		DELAY(2);
1355 		if ((bus_space_read_1(iot, ioh, STATUS_REG) & EXEC_INT) == 0)
1356 			continue;
1357 
1358 		temp = bus_space_read_1(iot, ioh, 0);
1359 		bus_space_write_1(iot, ioh, STATUS_REG, EXEC_INT);
1360 #ifdef DIAGNOSTIC
1361 		if (temp & 0x20) {
1362 			aprint_error_dev(sc->sc_dev,
1363 			    "mc setup failed, %d usec\n", timeout * 2);
1364 		} else if (((temp & 0x0f) == 0x03) &&
1365 			    (ifp->if_flags & IFF_DEBUG)) {
1366 				printf("%s: mc setup done, %d usec\n",
1367 			    device_xname(sc->sc_dev), timeout * 2);
1368 		}
1369 #endif
1370 		break;
1371 	}
1372 	sc->tx_start = sc->tx_end;
1373 	ifp->if_flags &= ~IFF_OACTIVE;
1374 
1375 }
1376 
1377 static void
1378 iy_mc_reset(struct iy_softc *sc)
1379 {
1380 	struct ether_multi *enm;
1381 	struct ether_multistep step;
1382 	struct ethercom *ecp;
1383 	struct ifnet *ifp;
1384 	bus_space_tag_t iot;
1385 	bus_space_handle_t ioh;
1386 	uint16_t temp;
1387 
1388 	ecp = &sc->sc_ethercom;
1389 	ifp = &ecp->ec_if;
1390 
1391 	iot = sc->sc_iot;
1392 	ioh = sc->sc_ioh;
1393 
1394 	if (ecp->ec_multicnt > 63) {
1395 		ifp->if_flags |= IFF_ALLMULTI;
1396 
1397 	} else if (ecp->ec_multicnt > 0) {
1398 		/*
1399 		 * Step through the list of addresses.
1400 		 */
1401 		ETHER_LOCK(ecp);
1402 		ETHER_FIRST_MULTI(step, ecp, enm);
1403 		while (enm) {
1404 			if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
1405 				ifp->if_flags |= IFF_ALLMULTI;
1406 				ETHER_UNLOCK(ecp);
1407 				goto setupmulti;
1408 			}
1409 			ETHER_NEXT_MULTI(step, enm);
1410 		}
1411 		ETHER_UNLOCK(ecp);
1412 		/* OK, we really need to do it now: */
1413 #if 0
1414 		if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE))
1415 		    != IFF_RUNNING) {
1416 			ifp->if_flags |= IFF_OACTIVE;
1417 			sc->want_mc_setup = 1;
1418 			return;
1419 		}
1420 #endif
1421 		iy_mc_setup(sc);
1422 	} else {
1423 		ifp->if_flags &= ~IFF_ALLMULTI;
1424 	}
1425 
1426 setupmulti:
1427 	bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
1428 	if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))
1429 		temp = MATCH_ALL;
1430 	else
1431 		temp = MATCH_BRDCST;
1432 
1433 	bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
1434 	/* XXX VOODOO */
1435 	temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
1436 	bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
1437 	/* XXX END OF VOODOO */
1438 
1439 	/* XXX TBD: setup hardware for all multicasts */
1440 	bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
1441 	return;
1442 }
1443 
1444 #ifdef IYDEBUGX
1445 void
1446 print_rbd(volatile struct ie_recv_buf_desc *rbd)
1447 {
1448 	printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
1449 	    "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
1450 	    rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
1451 	    rbd->mbz);
1452 }
1453 #endif
1454 
1455 void
1456 iyprobemem(struct iy_softc *sc)
1457 {
1458 	bus_space_tag_t iot;
1459 	bus_space_handle_t ioh;
1460 	int testing;
1461 
1462 	iot = sc->sc_iot;
1463 	ioh = sc->sc_ioh;
1464 
1465 	bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
1466 	delay(1);
1467 	bus_space_write_2(iot, ioh, HOST_ADDR_REG, 4096-2);
1468 	bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1469 
1470 	for (testing=65536; testing >= 4096; testing >>= 1) {
1471 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1472 		bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xdead);
1473 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1474 		if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xdead) {
1475 #ifdef IYMEMDEBUG
1476 			printf("%s: Didn't keep 0xdead at 0x%x\n",
1477 			    device_xname(sc->sc_dev), testing-2);
1478 #endif
1479 			continue;
1480 		}
1481 
1482 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1483 		bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xbeef);
1484 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1485 		if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xbeef) {
1486 #ifdef IYMEMDEBUG
1487 			printf("%s: Didn't keep 0xbeef at 0x%x\n",
1488 			    device_xname(sc->sc_dev), testing-2);
1489 #endif
1490 			continue;
1491 		}
1492 
1493 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1494 		bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1495 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing >> 1);
1496 		bus_space_write_2(iot, ioh, MEM_PORT_REG, testing >> 1);
1497 		bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1498 		if (bus_space_read_2(iot, ioh, MEM_PORT_REG) == (testing >> 1)) {
1499 #ifdef IYMEMDEBUG
1500 			printf("%s: 0x%x alias of 0x0\n",
1501 			    device_xname(sc->sc_dev), testing >> 1);
1502 #endif
1503 			continue;
1504 		}
1505 
1506 		break;
1507 	}
1508 
1509 	sc->sram = testing;
1510 
1511 	switch (testing) {
1512 		case 65536:
1513 			/* 4 NFS packets + overhead RX, 2 NFS + overhead TX  */
1514 			sc->rx_size = 44*1024;
1515 			break;
1516 
1517 		case 32768:
1518 			/* 2 NFS packets + overhead RX, 1 NFS + overhead TX  */
1519 			sc->rx_size = 22*1024;
1520 			break;
1521 
1522 		case 16384:
1523 			/* 1 NFS packet + overhead RX, 4 big packets TX */
1524 			sc->rx_size = 10*1024;
1525 			break;
1526 		default:
1527 			sc->rx_size = testing/2;
1528 			break;
1529 	}
1530 	sc->tx_size = testing - sc->rx_size;
1531 }
1532 
1533 static int
1534 eepromreadall(bus_space_tag_t iot, bus_space_handle_t ioh, uint16_t *wordp,
1535     int maxi)
1536 {
1537 	int i;
1538 	uint16_t checksum, tmp;
1539 
1540 	checksum = 0;
1541 
1542 	for (i=0; i<EEPP_LENGTH; ++i) {
1543 		tmp = eepromread(iot, ioh, i);
1544 		checksum += tmp;
1545 		if (i<maxi)
1546 			wordp[i] = tmp;
1547 	}
1548 
1549 	if (checksum != EEPP_CHKSUM) {
1550 #ifdef IYDEBUG
1551 		printf("wrong EEPROM checksum 0x%x should be 0x%x\n",
1552 		    checksum, EEPP_CHKSUM);
1553 #endif
1554 		return 1;
1555 	}
1556 	return 0;
1557 }
1558