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