if_iy.c revision 1.35.2.2 1 /* $NetBSD: if_iy.c,v 1.35.2.2 2000/11/22 16:03:46 bouyer Exp $ */
2 /* #define IYDEBUG */
3 /* #define IYMEMDEBUG */
4
5 /*-
6 * Copyright (c) 1996 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 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
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 (void)eepromreadall(iot, ioh, eaddr, 8);
330 sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev;
331
332 #ifdef DIAGNOSTICS
333 if ((eaddr[EEPPEther0] !=
334 eepromread(iot, ioh, EEPPEther0a)) &&
335 (eaddr[EEPPEther1] !=
336 eepromread(iot, ioh, EEPPEther1a)) &&
337 (eaddr[EEPPEther2] !=
338 eepromread(iot, ioh, EEPPEther2a)))
339
340 printf("EEPROM Ethernet address differs from copy\n");
341 #endif
342
343 myaddr[1] = eaddr[EEPPEther0] & 0xFF;
344 myaddr[0] = eaddr[EEPPEther0] >> 8;
345 myaddr[3] = eaddr[EEPPEther1] & 0xFF;
346 myaddr[2] = eaddr[EEPPEther1] >> 8;
347 myaddr[5] = eaddr[EEPPEther2] & 0xFF;
348 myaddr[4] = eaddr[EEPPEther2] >> 8;
349
350 ifmedia_init(&sc->iy_ifmedia, 0, iy_mediachange, iy_mediastatus);
351 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_2, 0, NULL);
352 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
353 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
354 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
355 ifmedia_set(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO);
356 /* Attach the interface. */
357 if_attach(ifp);
358 ether_ifattach(ifp, myaddr);
359 printf(": address %s, rev. %d, %d kB\n",
360 ether_sprintf(myaddr),
361 sc->hard_vers, sc->sram/1024);
362
363 eirq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
364 if (eirq != ia->ia_irq)
365 printf("%s: EEPROM irq setting %d ignored\n",
366 sc->sc_dev.dv_xname, eirq);
367
368 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
369 IPL_NET, iyintr, sc);
370
371 #if NRND > 0
372 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
373 RND_TYPE_NET, 0);
374 #endif
375
376 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
377 bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
378 }
379
380 void
381 iystop(sc)
382 struct iy_softc *sc;
383 {
384 bus_space_tag_t iot;
385 bus_space_handle_t ioh;
386 #ifdef IYDEBUG
387 u_int p, v;
388 #endif
389
390 iot = sc->sc_iot;
391 ioh = sc->sc_ioh;
392
393 bus_space_write_1(iot, ioh, COMMAND_REG, RCV_DISABLE_CMD);
394
395 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
396 bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS);
397
398 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
399 delay(200);
400 #ifdef IYDEBUG
401 printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n",
402 sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last);
403 p = sc->tx_last;
404 if (!p)
405 p = sc->tx_start;
406 do {
407 char sbuf[128];
408
409 bus_space_write_2(iot, ioh, HOST_ADDR_REG, p);
410
411 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
412 bitmask_snprintf(v, "\020\006Ab\010Dn", sbuf, sizeof(sbuf));
413 printf("0x%04x: %s ", p, sbuf);
414
415 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
416 bitmask_snprintf(v, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL",
417 sbuf, sizeof(sbuf));
418 printf("0x%s", sbuf);
419
420 p = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
421 printf(" 0x%04x", p);
422
423 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
424 bitmask_snprintf(v, "\020\020Ch", sbuf, sizeof(sbuf));
425 printf(" 0x%s\n", sbuf);
426
427 } while (v & 0x8000);
428 #endif
429 sc->tx_start = sc->tx_end = sc->rx_size;
430 sc->tx_last = 0;
431 sc->sc_ethercom.ec_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
432 }
433
434 void
435 iyreset(sc)
436 struct iy_softc *sc;
437 {
438 int s;
439 s = splnet();
440 iystop(sc);
441 iyinit(sc);
442 splx(s);
443 }
444
445 void
446 iyinit(sc)
447 struct iy_softc *sc;
448 {
449 int i;
450 unsigned temp;
451 struct ifnet *ifp;
452 bus_space_tag_t iot;
453 bus_space_handle_t ioh;
454
455 iot = sc->sc_iot;
456 ioh = sc->sc_ioh;
457
458 ifp = &sc->sc_ethercom.ec_if;
459 #ifdef IYDEBUG
460 printf("ifp is %p\n", ifp);
461 #endif
462
463 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
464
465 temp = bus_space_read_1(iot, ioh, EEPROM_REG);
466 if (temp & 0x10)
467 bus_space_write_1(iot, ioh, EEPROM_REG, temp & ~0x10);
468
469 for (i=0; i<6; ++i) {
470 bus_space_write_1(iot, ioh, I_ADD(i), LLADDR(ifp->if_sadl)[i]);
471 }
472
473 temp = bus_space_read_1(iot, ioh, REG1);
474 bus_space_write_1(iot, ioh, REG1,
475 temp | XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP | RCV_DISCARD_BAD);
476
477 if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
478 temp = MATCH_ALL;
479 } else if (sc->sc_ethercom.ec_multicnt) {
480 temp = MATCH_MULTI;
481 } else
482 temp = MATCH_ID;
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 /* nothing; leave as it is */
529 }
530 switch (temp & (BNC_BIT | TPE_BIT)) {
531 case BNC_BIT:
532 sc->iy_media = IFM_ETHER | IFM_10_2;
533 break;
534 case TPE_BIT:
535 sc->iy_media = IFM_ETHER | IFM_10_T;
536 break;
537 default:
538 sc->iy_media = IFM_ETHER | IFM_10_5;
539 }
540
541 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
542 #ifdef IYDEBUG
543 {
544 char sbuf[128];
545
546 bitmask_snprintf(temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
547 sbuf, sizeof(sbuf));
548 printf("changed to 0x%s\n", sbuf);
549 }
550 #endif
551
552 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
553 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
554 bus_space_write_1(iot, ioh, 0, BANK_SEL(1));
555
556 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
557 bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
558
559 #ifdef IYDEBUG
560 {
561 char sbuf[128];
562
563 bitmask_snprintf(temp, "\020\4bad_irq\010flash/boot present",
564 sbuf, sizeof(sbuf));
565 printf("%s: int no was %s\n", sc->sc_dev.dv_xname, sbuf);
566
567 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
568 bitmask_snprintf(temp, "\020\4bad_irq\010flash/boot present",
569 sbuf, sizeof(sbuf));
570 printf("%s: int no now %s\n", sc->sc_dev.dv_xname, sbuf);
571 }
572 #endif
573
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 >> 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_2(iot, ioh, RCV_START_LOW, 0);
609 bus_space_write_2(iot, ioh, RCV_STOP_LOW, sc->rx_size - 2);
610 sc->rx_start = 0;
611
612 bus_space_write_1(iot, ioh, 0, SEL_RESET_CMD);
613 delay(200);
614
615 bus_space_write_2(iot, ioh, XMT_ADDR_REG, sc->rx_size);
616
617 sc->tx_start = sc->tx_end = sc->rx_size;
618 sc->tx_last = 0;
619
620 bus_space_write_1(iot, ioh, 0, RCV_ENABLE_CMD);
621
622 ifp->if_flags |= IFF_RUNNING;
623 ifp->if_flags &= ~IFF_OACTIVE;
624 }
625
626 void
627 iystart(ifp)
628 struct ifnet *ifp;
629 {
630 struct iy_softc *sc;
631
632
633 struct mbuf *m0, *m;
634 u_int len, pad, last, end;
635 u_int llen, residual;
636 int avail;
637 caddr_t data;
638 u_int16_t resval, stat;
639 bus_space_tag_t iot;
640 bus_space_handle_t ioh;
641
642 #ifdef IYDEBUG
643 printf("iystart called\n");
644 #endif
645 sc = ifp->if_softc;
646
647 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
648 return;
649
650 iot = sc->sc_iot;
651 ioh = sc->sc_ioh;
652
653 while ((m0 = ifp->if_snd.ifq_head) != NULL) {
654 #ifdef IYDEBUG
655 printf("%s: trying to write another packet to the hardware\n",
656 sc->sc_dev.dv_xname);
657 #endif
658
659 /* We need to use m->m_pkthdr.len, so require the header */
660 if ((m0->m_flags & M_PKTHDR) == 0)
661 panic("iystart: no header mbuf");
662
663 len = m0->m_pkthdr.len;
664 pad = len & 1;
665
666 #ifdef IYDEBUG
667 printf("%s: length is %d.\n", sc->sc_dev.dv_xname, len);
668 #endif
669 if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
670 pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
671 }
672
673 if (len + pad > ETHER_MAX_LEN) {
674 /* packet is obviously too large: toss it */
675 ++ifp->if_oerrors;
676 IF_DEQUEUE(&ifp->if_snd, m0);
677 m_freem(m0);
678 continue;
679 }
680
681 #if NBPFILTER > 0
682 if (ifp->if_bpf)
683 bpf_mtap(ifp->if_bpf, m0);
684 #endif
685
686 avail = sc->tx_start - sc->tx_end;
687 if (avail <= 0)
688 avail += sc->tx_size;
689
690 #ifdef IYDEBUG
691 printf("%s: avail is %d.\n", sc->sc_dev.dv_xname, avail);
692 #endif
693 /*
694 * we MUST RUN at splnet here ---
695 * XXX todo: or even turn off the boards ints ??? hm...
696 */
697
698 /* See if there is room to put another packet in the buffer. */
699
700 if ((len+pad+2*I595_XMT_HDRLEN) > avail) {
701 #ifdef IYDEBUG
702 printf("%s: len = %d, avail = %d, setting OACTIVE\n",
703 sc->sc_dev.dv_xname, len, avail);
704 #endif
705 ifp->if_flags |= IFF_OACTIVE;
706 return;
707 }
708
709 /* we know it fits in the hardware now, so dequeue it */
710 IF_DEQUEUE(&ifp->if_snd, m0);
711
712 last = sc->tx_end;
713 end = last + pad + len + I595_XMT_HDRLEN;
714
715 if (end >= sc->sram) {
716 if ((sc->sram - last) <= I595_XMT_HDRLEN) {
717 /* keep header in one piece */
718 last = sc->rx_size;
719 end = last + pad + len + I595_XMT_HDRLEN;
720 } else
721 end -= sc->tx_size;
722 }
723
724 bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
725 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
726 htole16(XMT_CMD));
727
728 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
729 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
730
731 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
732 htole16(len + pad));
733
734 residual = resval = 0;
735
736 while ((m = m0)!=0) {
737 data = mtod(m, caddr_t);
738 llen = m->m_len;
739 if (residual) {
740 #ifdef IYDEBUG
741 printf("%s: merging residual with next mbuf.\n",
742 sc->sc_dev.dv_xname);
743 #endif
744 resval |= *data << 8;
745 bus_space_write_stream_2(iot, ioh,
746 MEM_PORT_REG, resval);
747 --llen;
748 ++data;
749 }
750 if (llen > 1)
751 bus_space_write_multi_stream_2(iot, ioh,
752 MEM_PORT_REG, data, llen>>1);
753 residual = llen & 1;
754 if (residual) {
755 resval = *(data + llen - 1);
756 #ifdef IYDEBUG
757 printf("%s: got odd mbuf to send.\n",
758 sc->sc_dev.dv_xname);
759 #endif
760 }
761
762 MFREE(m, m0);
763 }
764
765 if (residual)
766 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
767 resval);
768
769 pad >>= 1;
770 while (pad-- > 0)
771 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, 0);
772
773 #ifdef IYDEBUG
774 printf("%s: new last = 0x%x, end = 0x%x.\n",
775 sc->sc_dev.dv_xname, last, end);
776 printf("%s: old start = 0x%x, end = 0x%x, last = 0x%x\n",
777 sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last);
778 #endif
779
780 if (sc->tx_start != sc->tx_end) {
781 bus_space_write_2(iot, ioh, HOST_ADDR_REG,
782 sc->tx_last + XMT_COUNT);
783
784 /*
785 * XXX We keep stat in le order, to potentially save
786 * a byte swap.
787 */
788 stat = bus_space_read_stream_2(iot, ioh, MEM_PORT_REG);
789
790 bus_space_write_2(iot, ioh, HOST_ADDR_REG,
791 sc->tx_last + XMT_CHAIN);
792
793 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
794 htole16(last));
795
796 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
797 stat | htole16(CHAIN));
798 #ifdef IYDEBUG
799 printf("%s: setting 0x%x to 0x%x\n",
800 sc->sc_dev.dv_xname, sc->tx_last + XMT_COUNT,
801 le16toh(stat) | CHAIN);
802 #endif
803 }
804 stat = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
805
806 /* XXX todo: enable ints here if disabled */
807
808 ++ifp->if_opackets;
809
810 if (sc->tx_start == sc->tx_end) {
811 bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
812 bus_space_write_1(iot, ioh, 0, XMT_CMD);
813 sc->tx_start = last;
814 #ifdef IYDEBUG
815 printf("%s: writing 0x%x to XAR and giving XCMD\n",
816 sc->sc_dev.dv_xname, last);
817 #endif
818 } else {
819 bus_space_write_1(iot, ioh, 0, RESUME_XMT_CMD);
820 #ifdef IYDEBUG
821 printf("%s: giving RESUME_XCMD\n",
822 sc->sc_dev.dv_xname);
823 #endif
824 }
825 sc->tx_last = last;
826 sc->tx_end = end;
827 }
828 }
829
830
831 static __inline void
832 eepromwritebit(iot, ioh, what)
833 bus_space_tag_t iot;
834 bus_space_handle_t ioh;
835 int what;
836 {
837 bus_space_write_1(iot, ioh, EEPROM_REG, what);
838 delay(1);
839 bus_space_write_1(iot, ioh, EEPROM_REG, what|EESK);
840 delay(1);
841 bus_space_write_1(iot, ioh, EEPROM_REG, what);
842 delay(1);
843 }
844
845 static __inline int
846 eepromreadbit(iot, ioh)
847 bus_space_tag_t iot;
848 bus_space_handle_t ioh;
849 {
850 int b;
851
852 bus_space_write_1(iot, ioh, EEPROM_REG, EECS|EESK);
853 delay(1);
854 b = bus_space_read_1(iot, ioh, EEPROM_REG);
855 bus_space_write_1(iot, ioh, EEPROM_REG, EECS);
856 delay(1);
857
858 return ((b & EEDO) != 0);
859 }
860
861 static u_int16_t
862 eepromread(iot, ioh, offset)
863 bus_space_tag_t iot;
864 bus_space_handle_t ioh;
865 int offset;
866 {
867 volatile int i;
868 volatile int j;
869 volatile u_int16_t readval;
870
871 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
872 delay(1);
873 bus_space_write_1(iot, ioh, EEPROM_REG, EECS); /* XXXX??? */
874 delay(1);
875
876 eepromwritebit(iot, ioh, EECS|EEDI);
877 eepromwritebit(iot, ioh, EECS|EEDI);
878 eepromwritebit(iot, ioh, EECS);
879
880 for (j=5; j>=0; --j) {
881 if ((offset>>j) & 1)
882 eepromwritebit(iot, ioh, EECS|EEDI);
883 else
884 eepromwritebit(iot, ioh, EECS);
885 }
886
887 for (readval=0, i=0; i<16; ++i) {
888 readval<<=1;
889 readval |= eepromreadbit(iot, ioh);
890 }
891
892 bus_space_write_1(iot, ioh, EEPROM_REG, 0|EESK);
893 delay(1);
894 bus_space_write_1(iot, ioh, EEPROM_REG, 0);
895
896 bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
897
898 return readval;
899 }
900
901 /*
902 * Device timeout/watchdog routine. Entered if the device neglects to generate
903 * an interrupt after a transmit has been started on it.
904 */
905 void
906 iywatchdog(ifp)
907 struct ifnet *ifp;
908 {
909 struct iy_softc *sc = ifp->if_softc;
910
911 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
912 ++sc->sc_ethercom.ec_if.if_oerrors;
913 iyreset(sc);
914 }
915
916 /*
917 * What to do upon receipt of an interrupt.
918 */
919 int
920 iyintr(arg)
921 void *arg;
922 {
923 struct iy_softc *sc = arg;
924 bus_space_tag_t iot;
925 bus_space_handle_t ioh;
926
927 u_short status;
928
929 iot = sc->sc_iot;
930 ioh = sc->sc_ioh;
931
932 status = bus_space_read_1(iot, ioh, STATUS_REG);
933 #ifdef IYDEBUG
934 if (status & ALL_INTS) {
935 char sbuf[128];
936
937 bitmask_snprintf(status, "\020\1RX_STP\2RX\3TX\4EXEC",
938 sbuf, sizeof(sbuf));
939 printf("%s: got interupt %s", sc->sc_dev.dv_xname, sbuf);
940
941 if (status & EXEC_INT) {
942 bitmask_snprintf(bus_space_read_1(iot, ioh, 0),
943 "\020\6ABORT", sbuf, sizeof(sbuf));
944 printf(" event %s\n", sbuf);
945 } else
946 printf("\n");
947 }
948 #endif
949 if ((status & (RX_INT | TX_INT)) == 0)
950 return 0;
951
952 if (status & RX_INT) {
953 iy_intr_rx(sc);
954 bus_space_write_1(iot, ioh, STATUS_REG, RX_INT);
955 }
956 if (status & TX_INT) {
957 iy_intr_tx(sc);
958 bus_space_write_1(iot, ioh, STATUS_REG, TX_INT);
959 }
960
961 #if NRND > 0
962 rnd_add_uint32(&sc->rnd_source, status);
963 #endif
964
965 return 1;
966 }
967
968 void
969 iyget(sc, iot, ioh, rxlen)
970 struct iy_softc *sc;
971 bus_space_tag_t iot;
972 bus_space_handle_t ioh;
973 int rxlen;
974 {
975 struct mbuf *m, *top, **mp;
976 struct ifnet *ifp;
977 int len;
978
979 ifp = &sc->sc_ethercom.ec_if;
980
981 MGETHDR(m, M_DONTWAIT, MT_DATA);
982 if (m == 0)
983 goto dropped;
984 m->m_pkthdr.rcvif = ifp;
985 m->m_pkthdr.len = rxlen;
986 len = MHLEN;
987 top = 0;
988 mp = ⊤
989
990 while (rxlen > 0) {
991 if (top) {
992 MGET(m, M_DONTWAIT, MT_DATA);
993 if (m == 0) {
994 m_freem(top);
995 goto dropped;
996 }
997 len = MLEN;
998 }
999 if (rxlen >= MINCLSIZE) {
1000 MCLGET(m, M_DONTWAIT);
1001 if ((m->m_flags & M_EXT) == 0) {
1002 m_free(m);
1003 m_freem(top);
1004 goto dropped;
1005 }
1006 len = MCLBYTES;
1007 }
1008 len = min(rxlen, len);
1009 if (len > 1) {
1010 len &= ~1;
1011
1012 bus_space_read_multi_stream_2(iot, ioh, MEM_PORT_REG,
1013 mtod(m, caddr_t), len/2);
1014 } else {
1015 #ifdef IYDEBUG
1016 printf("%s: received odd mbuf\n", sc->sc_dev.dv_xname);
1017 #endif
1018 *(mtod(m, caddr_t)) = bus_space_read_stream_2(iot, ioh,
1019 MEM_PORT_REG);
1020 }
1021 m->m_len = len;
1022 rxlen -= len;
1023 *mp = m;
1024 mp = &m->m_next;
1025 }
1026 /* XXX receive the top here */
1027 ++ifp->if_ipackets;
1028
1029 #if NBPFILTER > 0
1030 if (ifp->if_bpf)
1031 bpf_mtap(ifp->if_bpf, top);
1032 #endif
1033 (*ifp->if_input)(ifp, top);
1034 return;
1035
1036 dropped:
1037 ++ifp->if_ierrors;
1038 return;
1039 }
1040
1041 void
1042 iy_intr_rx(sc)
1043 struct iy_softc *sc;
1044 {
1045 struct ifnet *ifp;
1046 bus_space_tag_t iot;
1047 bus_space_handle_t ioh;
1048
1049 u_int rxadrs, rxevnt, rxstatus, rxnext, rxlen;
1050
1051 iot = sc->sc_iot;
1052 ioh = sc->sc_ioh;
1053 ifp = &sc->sc_ethercom.ec_if;
1054
1055 rxadrs = sc->rx_start;
1056 bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxadrs);
1057 rxevnt = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
1058 rxnext = 0;
1059
1060 while (rxevnt == RCV_DONE) {
1061 rxstatus = le16toh(bus_space_read_stream_2(iot, ioh,
1062 MEM_PORT_REG));
1063 rxnext = le16toh(bus_space_read_stream_2(iot, ioh,
1064 MEM_PORT_REG));
1065 rxlen = le16toh(bus_space_read_stream_2(iot, ioh,
1066 MEM_PORT_REG));
1067 #ifdef IYDEBUG
1068 {
1069 char sbuf[128];
1070
1071 bitmask_snprintf(rxstatus, "\020\1RCLD\2IA_MCH\010SHORT\011OVRN\013ALGERR\014CRCERR\015LENERR\016RCVOK\020TYP",
1072 sbuf, sizeof(sbuf));
1073 printf("%s: pck at 0x%04x stat %s next 0x%x len 0x%x\n",
1074 sc->sc_dev.dv_xname, rxadrs, sbuf, rxnext, rxlen);
1075 }
1076 #endif
1077 iyget(sc, iot, ioh, rxlen);
1078
1079 /* move stop address */
1080 bus_space_write_2(iot, ioh, RCV_STOP_LOW,
1081 rxnext == 0 ? sc->rx_size - 2 : rxnext - 2);
1082
1083 bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxnext);
1084 rxadrs = rxnext;
1085 rxevnt = le16toh(bus_space_read_stream_2(iot, ioh,
1086 MEM_PORT_REG));
1087 }
1088 sc->rx_start = rxnext;
1089 }
1090
1091 void
1092 iy_intr_tx(sc)
1093 struct iy_softc *sc;
1094 {
1095 bus_space_tag_t iot;
1096 bus_space_handle_t ioh;
1097 struct ifnet *ifp;
1098 u_int txstatus, txstat2, txlen, txnext;
1099
1100 ifp = &sc->sc_ethercom.ec_if;
1101 iot = sc->sc_iot;
1102 ioh = sc->sc_ioh;
1103
1104 while (sc->tx_start != sc->tx_end) {
1105 bus_space_write_2(iot, ioh, HOST_ADDR_REG, sc->tx_start);
1106 txstatus = le16toh(bus_space_read_stream_2(iot, ioh,
1107 MEM_PORT_REG));
1108
1109 if ((txstatus & (TX_DONE|CMD_MASK)) != (TX_DONE|XMT_CMD))
1110 break;
1111
1112 txstat2 = le16toh(bus_space_read_stream_2(iot, ioh,
1113 MEM_PORT_REG));
1114 txnext = le16toh(bus_space_read_stream_2(iot, ioh,
1115 MEM_PORT_REG));
1116 txlen = le16toh(bus_space_read_stream_2(iot, ioh,
1117 MEM_PORT_REG));
1118 #ifdef IYDEBUG
1119 {
1120 char sbuf[128];
1121
1122 bitmask_snprintf(txstat2, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL",
1123 sbuf, sizeof(sbuf));
1124 printf("txstat 0x%x stat2 0x%s next 0x%x len 0x%x\n",
1125 txstatus, sbuf, txnext, txlen);
1126 }
1127 #endif
1128 if (txlen & CHAIN)
1129 sc->tx_start = txnext;
1130 else
1131 sc->tx_start = sc->tx_end;
1132 ifp->if_flags &= ~IFF_OACTIVE;
1133
1134 if ((txstat2 & 0x2000) == 0)
1135 ++ifp->if_oerrors;
1136 if (txstat2 & 0x000f)
1137 ifp->if_oerrors += txstat2 & 0x000f;
1138 }
1139 ifp->if_flags &= ~IFF_OACTIVE;
1140 }
1141
1142 int
1143 iyioctl(ifp, cmd, data)
1144 struct ifnet *ifp;
1145 u_long cmd;
1146 caddr_t data;
1147 {
1148 struct iy_softc *sc;
1149 struct ifaddr *ifa;
1150 struct ifreq *ifr;
1151 int s, error = 0;
1152
1153 sc = ifp->if_softc;
1154 ifa = (struct ifaddr *)data;
1155 ifr = (struct ifreq *)data;
1156
1157 #ifdef IYDEBUG
1158 printf("iyioctl called with ifp 0x%p (%s) cmd 0x%lx data 0x%p\n",
1159 ifp, ifp->if_xname, cmd, data);
1160 #endif
1161
1162 s = splnet();
1163
1164 switch (cmd) {
1165
1166 case SIOCSIFADDR:
1167 ifp->if_flags |= IFF_UP;
1168
1169 switch (ifa->ifa_addr->sa_family) {
1170 #ifdef INET
1171 case AF_INET:
1172 iyinit(sc);
1173 arp_ifinit(ifp, ifa);
1174 break;
1175 #endif
1176 #ifdef NS
1177 /* XXX - This code is probably wrong. */
1178 case AF_NS:
1179 {
1180 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
1181
1182 if (ns_nullhost(*ina))
1183 ina->x_host = *(union ns_host *)
1184 LLADDR(ifp->if_sadl);
1185 else
1186 bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
1187 ETHER_ADDR_LEN);
1188 /* Set new address. */
1189 iyinit(sc);
1190 break;
1191 }
1192 #endif /* NS */
1193 default:
1194 iyinit(sc);
1195 break;
1196 }
1197 break;
1198
1199 case SIOCSIFFLAGS:
1200 sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1201 if ((ifp->if_flags & IFF_UP) == 0 &&
1202 (ifp->if_flags & IFF_RUNNING) != 0) {
1203 /*
1204 * If interface is marked down and it is running, then
1205 * stop it.
1206 */
1207 iystop(sc);
1208 ifp->if_flags &= ~IFF_RUNNING;
1209 } else if ((ifp->if_flags & IFF_UP) != 0 &&
1210 (ifp->if_flags & IFF_RUNNING) == 0) {
1211 /*
1212 * If interface is marked up and it is stopped, then
1213 * start it.
1214 */
1215 iyinit(sc);
1216 } else {
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 }
1224 #ifdef IYDEBUGX
1225 if (ifp->if_flags & IFF_DEBUG)
1226 sc->sc_debug = IFY_ALL;
1227 else
1228 sc->sc_debug = 0;
1229 #endif
1230 break;
1231
1232 case SIOCADDMULTI:
1233 case SIOCDELMULTI:
1234 error = (cmd == SIOCADDMULTI) ?
1235 ether_addmulti(ifr, &sc->sc_ethercom):
1236 ether_delmulti(ifr, &sc->sc_ethercom);
1237
1238 if (error == ENETRESET) {
1239 /*
1240 * Multicast list has changed; set the hardware filter
1241 * accordingly.
1242 */
1243 iyreset(sc); /* XXX can't make it work otherwise */
1244 iy_mc_reset(sc);
1245 error = 0;
1246 }
1247 break;
1248
1249 case SIOCSIFMEDIA:
1250 case SIOCGIFMEDIA:
1251 error = ifmedia_ioctl(ifp, ifr, &sc->iy_ifmedia, cmd);
1252 break;
1253 default:
1254 error = EINVAL;
1255 }
1256 splx(s);
1257 return error;
1258 }
1259
1260 int
1261 iy_mediachange(ifp)
1262 struct ifnet *ifp;
1263 {
1264 struct iy_softc *sc = ifp->if_softc;
1265
1266 if (IFM_TYPE(sc->iy_ifmedia.ifm_media) != IFM_ETHER)
1267 return EINVAL;
1268 switch(IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
1269 case IFM_10_5:
1270 case IFM_10_2:
1271 case IFM_10_T:
1272 case IFM_AUTO:
1273 iystop(sc);
1274 iyinit(sc);
1275 return 0;
1276 default:
1277 return EINVAL;
1278 }
1279 }
1280
1281 void
1282 iy_mediastatus(ifp, ifmr)
1283 struct ifnet *ifp;
1284 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
1293 static void
1294 iy_mc_setup(sc)
1295 struct iy_softc *sc;
1296 {
1297 struct ether_multi *enm;
1298 struct ether_multistep step;
1299 struct ethercom *ecp;
1300 struct ifnet *ifp;
1301 bus_space_tag_t iot;
1302 bus_space_handle_t ioh;
1303 int avail, last /*, end*/ , len;
1304 int timeout;
1305 volatile u_int16_t dum;
1306 u_int8_t temp;
1307
1308
1309 ecp = &sc->sc_ethercom;
1310 ifp = &ecp->ec_if;
1311
1312 iot = sc->sc_iot;
1313 ioh = sc->sc_ioh;
1314
1315 len = 6 * ecp->ec_multicnt + 6;
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_MULTI);
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 bus_space_write_multi_stream_2(iot, ioh, MEM_PORT_REG,
1341 LLADDR(ifp->if_sadl), 3);
1342
1343 ETHER_FIRST_MULTI(step, ecp, enm);
1344 while(enm) {
1345 bus_space_write_multi_stream_2(iot, ioh, MEM_PORT_REG,
1346 enm->enm_addrlo, 3);
1347
1348 ETHER_NEXT_MULTI(step, enm);
1349 }
1350 dum = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
1351 bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
1352 bus_space_write_1(iot, ioh, 0, MC_SETUP_CMD);
1353
1354
1355 sc->tx_start = sc->rx_size;
1356 sc->tx_end = sc->rx_size + I595_XMT_HDRLEN + len;
1357
1358 for (timeout=0; timeout<100; timeout++) {
1359 DELAY(2);
1360 if ((bus_space_read_1(iot, ioh, STATUS_REG) & EXEC_INT) == 0)
1361 continue;
1362
1363 temp = bus_space_read_1(iot, ioh, 0);
1364 bus_space_write_1(iot, ioh, STATUS_REG, EXEC_INT);
1365 #ifdef DIAGNOSTIC
1366 if (temp & 0x20) {
1367 printf("%s: mc setup failed, %d usec\n",
1368 sc->sc_dev.dv_xname, timeout * 2);
1369 } else if (((temp & 0x0f) == 0x03) &&
1370 (ifp->if_flags & IFF_DEBUG)) {
1371 printf("%s: mc setup done, %d usec\n",
1372 sc->sc_dev.dv_xname, timeout * 2);
1373 }
1374 #endif
1375 break;
1376 }
1377 sc->tx_start = sc->tx_end;
1378 ifp->if_flags &= ~IFF_OACTIVE;
1379
1380 }
1381
1382 static void
1383 iy_mc_reset(sc)
1384 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 u_int16_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_FIRST_MULTI(step, ecp, enm);
1408 while(enm) {
1409 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
1410 ifp->if_flags |= IFF_ALLMULTI;
1411 goto setupmulti;
1412 }
1413 ETHER_NEXT_MULTI(step, enm);
1414 }
1415 /* OK, we really need to do it now: */
1416 #if 0
1417 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE))
1418 != IFF_RUNNING) {
1419 ifp->if_flags |= IFF_OACTIVE;
1420 sc->want_mc_setup = 1;
1421 return;
1422 }
1423 #endif
1424 iy_mc_setup(sc);
1425 } else {
1426 ifp->if_flags &= ~IFF_ALLMULTI;
1427 }
1428
1429 setupmulti:
1430 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
1431 if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
1432 temp = MATCH_ALL;
1433 } else if (sc->sc_ethercom.ec_multicnt) {
1434 temp = MATCH_MULTI;
1435 } else
1436 temp = MATCH_ID;
1437
1438 bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
1439 /* XXX VOODOO */
1440 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
1441 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
1442 /* XXX END OF VOODOO */
1443
1444 /* XXX TBD: setup hardware for all multicasts */
1445 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
1446 return;
1447 }
1448
1449 #ifdef IYDEBUGX
1450 void
1451 print_rbd(rbd)
1452 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
1461 void
1462 iyprobemem(sc)
1463 struct iy_softc *sc;
1464 {
1465 bus_space_tag_t iot;
1466 bus_space_handle_t ioh;
1467 int testing;
1468
1469 iot = sc->sc_iot;
1470 ioh = sc->sc_ioh;
1471
1472 bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
1473 delay(1);
1474 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 4096-2);
1475 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1476
1477 for (testing=65536; testing >= 4096; testing >>= 1) {
1478 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1479 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xdead);
1480 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1481 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xdead) {
1482 #ifdef IYMEMDEBUG
1483 printf("%s: Didn't keep 0xdead at 0x%x\n",
1484 sc->sc_dev.dv_xname, testing-2);
1485 #endif
1486 continue;
1487 }
1488
1489 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1490 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xbeef);
1491 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1492 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xbeef) {
1493 #ifdef IYMEMDEBUG
1494 printf("%s: Didn't keep 0xbeef at 0x%x\n",
1495 sc->sc_dev.dv_xname, testing-2);
1496 #endif
1497 continue;
1498 }
1499
1500 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1501 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1502 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing >> 1);
1503 bus_space_write_2(iot, ioh, MEM_PORT_REG, testing >> 1);
1504 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1505 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) == (testing >> 1)) {
1506 #ifdef IYMEMDEBUG
1507 printf("%s: 0x%x alias of 0x0\n",
1508 sc->sc_dev.dv_xname, testing >> 1);
1509 #endif
1510 continue;
1511 }
1512
1513 break;
1514 }
1515
1516 sc->sram = testing;
1517
1518 switch(testing) {
1519 case 65536:
1520 /* 4 NFS packets + overhead RX, 2 NFS + overhead TX */
1521 sc->rx_size = 44*1024;
1522 break;
1523
1524 case 32768:
1525 /* 2 NFS packets + overhead RX, 1 NFS + overhead TX */
1526 sc->rx_size = 22*1024;
1527 break;
1528
1529 case 16384:
1530 /* 1 NFS packet + overhead RX, 4 big packets TX */
1531 sc->rx_size = 10*1024;
1532 break;
1533 default:
1534 sc->rx_size = testing/2;
1535 break;
1536 }
1537 sc->tx_size = testing - sc->rx_size;
1538 }
1539
1540 static int
1541 eepromreadall(iot, ioh, wordp, maxi)
1542 bus_space_tag_t iot;
1543 bus_space_handle_t ioh;
1544 u_int16_t *wordp;
1545 int maxi;
1546 {
1547 int i;
1548 u_int16_t checksum, tmp;
1549
1550 checksum = 0;
1551
1552 for (i=0; i<EEPP_LENGTH; ++i) {
1553 tmp = eepromread(iot, ioh, i);
1554 checksum += tmp;
1555 if (i<maxi)
1556 wordp[i] = tmp;
1557 }
1558
1559 if (checksum != EEPP_CHKSUM) {
1560 #ifdef IYDEBUG
1561 printf("wrong EEPROM checksum 0x%x should be 0x%x\n",
1562 checksum, EEPP_CHKSUM);
1563 #endif
1564 return 1;
1565 }
1566 return 0;
1567 }
1568