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