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