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