if_iy.c revision 1.104 1 /* $NetBSD: if_iy.c,v 1.104 2019/02/05 06:17:02 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.104 2019/02/05 06:17:02 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
64 #include <net/if_ether.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 #if defined(SIOCSIFMEDIA)
76 #include <net/if_media.h>
77 #endif
78
79 #include <sys/cpu.h>
80 #include <sys/bus.h>
81 #include <sys/intr.h>
82
83 #include <dev/isa/isareg.h>
84 #include <dev/isa/isavar.h>
85 #include <dev/ic/i82595reg.h>
86
87 /* XXX why isn't this centralized? */
88 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
89 #define bus_space_write_stream_2 bus_space_write_2
90 #define bus_space_write_multi_stream_2 bus_space_write_multi_2
91 #define bus_space_read_stream_2 bus_space_read_2
92 #define bus_space_read_multi_stream_2 bus_space_read_multi_2
93 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
94
95 /*
96 * Ethernet status, per interface.
97 */
98 struct iy_softc {
99 device_t sc_dev;
100 void *sc_ih;
101
102 bus_space_tag_t sc_iot;
103 bus_space_handle_t sc_ioh;
104
105 struct ethercom sc_ethercom;
106
107 struct ifmedia iy_ifmedia;
108 int iy_media;
109
110 int mappedirq;
111
112 int hard_vers;
113
114 int promisc;
115
116 int sram, tx_size, rx_size;
117
118 int tx_start, tx_end, tx_last;
119 int rx_start;
120
121 int doing_mc_setup;
122 #ifdef IYDEBUG
123 int sc_debug;
124 #endif
125
126 krndsource_t rnd_source;
127 };
128
129 void iywatchdog(struct ifnet *);
130 int iyioctl(struct ifnet *, u_long, void *);
131 int iyintr(void *);
132 void iyinit(struct iy_softc *);
133 void iystop(struct iy_softc *);
134 void iystart(struct ifnet *);
135
136 void iy_intr_rx(struct iy_softc *);
137 void iy_intr_tx(struct iy_softc *);
138
139 void iyreset(struct iy_softc *);
140 void iy_readframe(struct iy_softc *, int);
141 void iy_drop_packet_buffer(struct iy_softc *);
142 void iy_find_mem_size(struct iy_softc *);
143 void iyrint(struct iy_softc *);
144 void iytint(struct iy_softc *);
145 void iyxmit(struct iy_softc *);
146 static void iy_mc_setup(struct iy_softc *);
147 static void iy_mc_reset(struct iy_softc *);
148 void iyget(struct iy_softc *, bus_space_tag_t, bus_space_handle_t, int);
149 void iyprobemem(struct iy_softc *);
150 static inline void eepromwritebit(bus_space_tag_t, bus_space_handle_t, int);
151 static inline int eepromreadbit(bus_space_tag_t, bus_space_handle_t);
152
153 #ifdef IYDEBUGX
154 void print_rbd(volatile struct iy_recv_buf_desc *);
155
156 int in_ifrint = 0;
157 int in_iftint = 0;
158 #endif
159
160 int iy_mediachange(struct ifnet *);
161 void iy_mediastatus(struct ifnet *, struct ifmediareq *);
162
163 int iyprobe(device_t, cfdata_t, void *);
164 void iyattach(device_t, device_t, void *);
165
166 static u_int16_t eepromread(bus_space_tag_t, bus_space_handle_t, int);
167
168 static int eepromreadall(bus_space_tag_t, bus_space_handle_t, u_int16_t *,
169 int);
170
171 CFATTACH_DECL_NEW(iy, sizeof(struct iy_softc),
172 iyprobe, iyattach, NULL, NULL);
173
174 static u_int8_t eepro_irqmap[] = EEPP_INTMAP;
175 static u_int8_t eepro_revirqmap[] = EEPP_RINTMAP;
176
177 int
178 iyprobe(device_t parent, cfdata_t match, void *aux)
179 {
180 struct isa_attach_args *ia = aux;
181 u_int16_t eaddr[8];
182 bus_space_tag_t iot;
183 bus_space_handle_t ioh;
184 u_int8_t c, d;
185 int irq;
186
187 if (ia->ia_nio < 1)
188 return (0);
189 if (ia->ia_nirq < 1)
190 return (0);
191
192 if (ISA_DIRECT_CONFIG(ia))
193 return (0);
194
195 iot = ia->ia_iot;
196
197 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
198 return 0;
199
200 if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh))
201 return 0;
202
203 /* try to find the round robin sig: */
204
205 c = bus_space_read_1(iot, ioh, ID_REG);
206 if ((c & ID_REG_MASK) != ID_REG_SIG)
207 goto out;
208
209 d = bus_space_read_1(iot, ioh, ID_REG);
210 if ((d & ID_REG_MASK) != ID_REG_SIG)
211 goto out;
212
213 if (((d-c) & R_ROBIN_BITS) != 0x40)
214 goto out;
215
216 d = bus_space_read_1(iot, ioh, ID_REG);
217 if ((d & ID_REG_MASK) != ID_REG_SIG)
218 goto out;
219
220 if (((d-c) & R_ROBIN_BITS) != 0x80)
221 goto out;
222
223 d = bus_space_read_1(iot, ioh, ID_REG);
224 if ((d & ID_REG_MASK) != ID_REG_SIG)
225 goto out;
226
227 if (((d-c) & R_ROBIN_BITS) != 0xC0)
228 goto out;
229
230 d = bus_space_read_1(iot, ioh, ID_REG);
231 if ((d & ID_REG_MASK) != ID_REG_SIG)
232 goto out;
233
234 if (((d-c) & R_ROBIN_BITS) != 0x00)
235 goto out;
236
237 #ifdef IYDEBUG
238 printf("iyprobe verified working ID reg.\n");
239 #endif
240
241 if (eepromreadall(iot, ioh, eaddr, 8))
242 goto out;
243
244 if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ)
245 irq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
246 else
247 irq = ia->ia_irq[0].ir_irq;
248
249 if (irq >= sizeof(eepro_revirqmap))
250 goto out;
251
252 if (eepro_revirqmap[irq] == 0xff)
253 goto out;
254
255 /* now lets reset the chip */
256
257 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
258 delay(200);
259
260 ia->ia_nio = 1;
261 ia->ia_io[0].ir_size = 16;
262
263 ia->ia_nirq = 1;
264 ia->ia_irq[0].ir_irq = irq;
265
266 ia->ia_niomem = 0;
267 ia->ia_ndrq = 0;
268
269 bus_space_unmap(iot, ioh, 16);
270 return 1; /* found */
271 out:
272 bus_space_unmap(iot, ioh, 16);
273 return 0;
274 }
275
276 void
277 iyattach(device_t parent, device_t self, void *aux)
278 {
279 struct iy_softc *sc = device_private(self);
280 struct isa_attach_args *ia = aux;
281 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
282 bus_space_tag_t iot;
283 bus_space_handle_t ioh;
284 unsigned temp;
285 u_int16_t eaddr[8];
286 u_int8_t myaddr[ETHER_ADDR_LEN];
287 int eirq;
288
289 iot = ia->ia_iot;
290
291 if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh)) {
292 aprint_error(": can't map i/o space\n");
293 return;
294 }
295
296 sc->sc_iot = iot;
297 sc->sc_ioh = ioh;
298
299 sc->mappedirq = eepro_revirqmap[ia->ia_irq[0].ir_irq];
300
301 /* now let's reset the chip */
302
303 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
304 delay(200);
305
306 iyprobemem(sc);
307
308 strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
309 ifp->if_softc = sc;
310 ifp->if_start = iystart;
311 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
312
313 sc->doing_mc_setup = 0;
314
315 ifp->if_ioctl = iyioctl;
316 ifp->if_watchdog = iywatchdog;
317
318 IFQ_SET_READY(&ifp->if_snd);
319
320 (void)eepromreadall(iot, ioh, eaddr, 8);
321 sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev;
322
323 #ifdef DIAGNOSTICS
324 if ((eaddr[EEPPEther0] !=
325 eepromread(iot, ioh, EEPPEther0a)) &&
326 (eaddr[EEPPEther1] !=
327 eepromread(iot, ioh, EEPPEther1a)) &&
328 (eaddr[EEPPEther2] !=
329 eepromread(iot, ioh, EEPPEther2a)))
330
331 aprint_error("EEPROM Ethernet address differs from copy\n");
332 #endif
333
334 myaddr[1] = eaddr[EEPPEther0] & 0xFF;
335 myaddr[0] = eaddr[EEPPEther0] >> 8;
336 myaddr[3] = eaddr[EEPPEther1] & 0xFF;
337 myaddr[2] = eaddr[EEPPEther1] >> 8;
338 myaddr[5] = eaddr[EEPPEther2] & 0xFF;
339 myaddr[4] = eaddr[EEPPEther2] >> 8;
340
341 ifmedia_init(&sc->iy_ifmedia, 0, iy_mediachange, iy_mediastatus);
342 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_2, 0, NULL);
343 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
344 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
345 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
346 ifmedia_set(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO);
347 /* Attach the interface. */
348 if_attach(ifp);
349 ether_ifattach(ifp, myaddr);
350 aprint_normal(": address %s, rev. %d, %d kB\n",
351 ether_sprintf(myaddr),
352 sc->hard_vers, sc->sram/1024);
353
354 eirq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
355 if (eirq != ia->ia_irq[0].ir_irq)
356 aprint_error("%s: EEPROM irq setting %d ignored\n",
357 device_xname(sc->sc_dev), eirq);
358
359 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
360 IST_EDGE, IPL_NET, iyintr, sc);
361
362 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
363 RND_TYPE_NET, RND_FLAG_DEFAULT);
364
365 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
366 bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
367 }
368
369 void
370 iystop(struct iy_softc *sc)
371 {
372 bus_space_tag_t iot;
373 bus_space_handle_t ioh;
374 #ifdef IYDEBUG
375 u_int p, v;
376 #endif
377
378 iot = sc->sc_iot;
379 ioh = sc->sc_ioh;
380
381 bus_space_write_1(iot, ioh, COMMAND_REG, RCV_DISABLE_CMD);
382
383 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
384 bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS);
385
386 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
387 delay(200);
388 #ifdef IYDEBUG
389 printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n",
390 device_xname(sc->sc_dev), sc->tx_start, sc->tx_end, sc->tx_last);
391 p = sc->tx_last;
392 if (!p)
393 p = sc->tx_start;
394 do {
395 char sbuf[128];
396
397 bus_space_write_2(iot, ioh, HOST_ADDR_REG, p);
398
399 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
400 snprintb(sbuf, sizeof(sbuf), "\020\006Ab\010Dn", v);
401 printf("0x%04x: %s ", p, sbuf);
402
403 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
404 snprintb(sbuf, sizeof(sbuf),
405 "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN"
406 "\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL", v);
407 printf("%s", sbuf);
408
409 p = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
410 printf(" 0x%04x", p);
411
412 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
413 snprintb(sbuf, sizeof(sbuf), "\020\020Ch", v);
414 printf(" %s\n", sbuf);
415
416 } while (v & 0x8000);
417 #endif
418 sc->tx_start = sc->tx_end = sc->rx_size;
419 sc->tx_last = 0;
420 sc->sc_ethercom.ec_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
421 }
422
423 void
424 iyreset(struct iy_softc *sc)
425 {
426 int s;
427 s = splnet();
428 iystop(sc);
429 iyinit(sc);
430 splx(s);
431 }
432
433 void
434 iyinit(struct iy_softc *sc)
435 {
436 int i;
437 unsigned temp;
438 struct ifnet *ifp;
439 bus_space_tag_t iot;
440 bus_space_handle_t ioh;
441
442 iot = sc->sc_iot;
443 ioh = sc->sc_ioh;
444
445 ifp = &sc->sc_ethercom.ec_if;
446 #ifdef IYDEBUG
447 printf("ifp is %p\n", ifp);
448 #endif
449
450 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
451
452 temp = bus_space_read_1(iot, ioh, EEPROM_REG);
453 if (temp & 0x10)
454 bus_space_write_1(iot, ioh, EEPROM_REG, temp & ~0x10);
455
456 for (i=0; i<6; ++i) {
457 bus_space_write_1(iot, ioh, I_ADD(i), CLLADDR(ifp->if_sadl)[i]);
458 }
459
460 temp = bus_space_read_1(iot, ioh, REG1);
461 bus_space_write_1(iot, ioh, REG1,
462 temp | /* XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP | */ RCV_DISCARD_BAD);
463
464 if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
465 temp = MATCH_ALL;
466 } else
467 temp = MATCH_BRDCST;
468
469 bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
470
471 #ifdef IYDEBUG
472 {
473 char sbuf[128];
474
475 snprintb(sbuf, sizeof(sbuf),
476 "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA",
477 temp);
478
479 printf("%s: RECV_MODES set to %s\n", device_xname(sc->sc_dev),
480 sbuf);
481 }
482 #endif
483 /* XXX VOODOO */
484 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
485 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
486 /* XXX END OF VOODOO */
487
488
489 delay(500000); /* for the hardware to test for the connector */
490
491 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
492 #ifdef IYDEBUG
493 {
494 char sbuf[128];
495
496 snprintb(sbuf, sizeof(sbuf),
497 "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
498 temp);
499 printf("%s: media select was %s ", device_xname(sc->sc_dev),
500 sbuf);
501 }
502 #endif
503 temp = (temp & TEST_MODE_MASK);
504
505 switch(IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
506 case IFM_10_5:
507 temp &= ~ (BNC_BIT | TPE_BIT);
508 break;
509
510 case IFM_10_2:
511 temp = (temp & ~TPE_BIT) | BNC_BIT;
512 break;
513
514 case IFM_10_T:
515 temp = (temp & ~BNC_BIT) | TPE_BIT;
516 break;
517 default:
518 ;
519 /* nothing; leave as it is */
520 }
521 switch (temp & (BNC_BIT | TPE_BIT)) {
522 case BNC_BIT:
523 sc->iy_media = IFM_ETHER | IFM_10_2;
524 break;
525 case TPE_BIT:
526 sc->iy_media = IFM_ETHER | IFM_10_T;
527 break;
528 default:
529 sc->iy_media = IFM_ETHER | IFM_10_5;
530 }
531
532 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
533 #ifdef IYDEBUG
534 {
535 char sbuf[128];
536
537 snprintb(sbuf, sizeof(sbuf),
538 "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
539 temp);
540 printf("changed to %s\n", sbuf);
541 }
542 #endif
543
544 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
545 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
546 bus_space_write_1(iot, ioh, 0, BANK_SEL(1));
547
548 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
549 bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
550
551 #ifdef IYDEBUG
552 {
553 char sbuf[128];
554
555 snprintb(sbuf, sizeof(sbuf),
556 "\020\4bad_irq\010flash/boot present", temp);
557
558 printf("%s: int no was %s\n", device_xname(sc->sc_dev), sbuf);
559
560 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
561 snprintb(sbuf, sizeof(sbuf),
562 "\020\4bad_irq\010flash/boot present", temp);
563 printf("%s: int no now %s\n", device_xname(sc->sc_dev), sbuf);
564 }
565 #endif
566
567 bus_space_write_1(iot, ioh, RCV_LOWER_LIMIT_REG, 0);
568 bus_space_write_1(iot, ioh, RCV_UPPER_LIMIT_REG, (sc->rx_size -2) >>8);
569 bus_space_write_1(iot, ioh, XMT_LOWER_LIMIT_REG, sc->rx_size >>8);
570 bus_space_write_1(iot, ioh, XMT_UPPER_LIMIT_REG, (sc->sram - 2) >>8);
571
572 temp = bus_space_read_1(iot, ioh, REG1);
573 #ifdef IYDEBUG
574 {
575 char sbuf[128];
576
577 snprintb(sbuf, sizeof(sbuf), "\020\2WORD_WIDTH\010INT_ENABLE",
578 temp);
579
580 printf("%s: HW access is %s\n", device_xname(sc->sc_dev), sbuf);
581 }
582 #endif
583 bus_space_write_1(iot, ioh, REG1, temp | INT_ENABLE); /* XXX what about WORD_WIDTH? */
584
585 #ifdef IYDEBUG
586 {
587 char sbuf[128];
588
589 temp = bus_space_read_1(iot, ioh, REG1);
590 snprintb(sbuf, sizeof(sbuf), "\020\2WORD_WIDTH\010INT_ENABLE",
591 temp);
592 printf("%s: HW access is %s\n", device_xname(sc->sc_dev), sbuf);
593 }
594 #endif
595
596 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
597
598 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS & ~(RX_BIT|TX_BIT));
599 bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS); /* clear ints */
600
601 bus_space_write_1(iot, ioh, RCV_COPY_THRESHOLD, 0);
602
603 bus_space_write_2(iot, ioh, RCV_START_LOW, 0);
604 bus_space_write_2(iot, ioh, RCV_STOP_LOW, sc->rx_size - 2);
605 sc->rx_start = 0;
606
607 bus_space_write_1(iot, ioh, 0, SEL_RESET_CMD);
608 delay(200);
609
610 bus_space_write_2(iot, ioh, XMT_ADDR_REG, sc->rx_size);
611
612 sc->tx_start = sc->tx_end = sc->rx_size;
613 sc->tx_last = 0;
614
615 bus_space_write_1(iot, ioh, 0, RCV_ENABLE_CMD);
616
617 ifp->if_flags |= IFF_RUNNING;
618 ifp->if_flags &= ~IFF_OACTIVE;
619 }
620
621 void
622 iystart(struct ifnet *ifp)
623 {
624 struct iy_softc *sc;
625
626
627 struct mbuf *m0, *m;
628 u_int len, pad, last, end;
629 u_int llen, residual;
630 int avail;
631 char *data;
632 unsigned temp;
633 u_int16_t resval, stat;
634 bus_space_tag_t iot;
635 bus_space_handle_t ioh;
636
637 #ifdef IYDEBUG
638 printf("iystart called\n");
639 #endif
640 sc = ifp->if_softc;
641
642 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
643 return;
644
645 iy_intr_tx(sc);
646
647 iot = sc->sc_iot;
648 ioh = sc->sc_ioh;
649
650 for (;;) {
651 IFQ_POLL(&ifp->if_snd, m0);
652 if (m0 == NULL)
653 break;
654 #ifdef IYDEBUG
655 printf("%s: trying to write another packet to the hardware\n",
656 device_xname(sc->sc_dev));
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", device_xname(sc->sc_dev), 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 IFQ_DEQUEUE(&ifp->if_snd, m0);
677 m_freem(m0);
678 continue;
679 }
680
681 bpf_mtap(ifp, m0, BPF_D_OUT);
682
683 avail = sc->tx_start - sc->tx_end;
684 if (avail <= 0)
685 avail += sc->tx_size;
686
687 #ifdef IYDEBUG
688 printf("%s: avail is %d.\n", device_xname(sc->sc_dev), avail);
689 #endif
690 /*
691 * we MUST RUN at splnet here ---
692 * XXX todo: or even turn off the boards ints ??? hm...
693 */
694
695 /* See if there is room to put another packet in the buffer. */
696
697 if ((len+pad+2*I595_XMT_HDRLEN) > avail) {
698 #ifdef IYDEBUG
699 printf("%s: len = %d, avail = %d, setting OACTIVE\n",
700 device_xname(sc->sc_dev), len, avail);
701 #endif
702 /* mark interface as full ... */
703 ifp->if_flags |= IFF_OACTIVE;
704
705 /* and wait for any transmission result */
706 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
707
708 temp = bus_space_read_1(iot, ioh, REG1);
709 bus_space_write_1(iot, ioh, REG1,
710 temp & ~XMT_CHAIN_INT);
711
712 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
713
714 return;
715 }
716
717 /* we know it fits in the hardware now, so dequeue it */
718 IFQ_DEQUEUE(&ifp->if_snd, m0);
719
720 last = sc->tx_end;
721 end = last + pad + len + I595_XMT_HDRLEN;
722
723 if (end >= sc->sram) {
724 if ((sc->sram - last) <= I595_XMT_HDRLEN) {
725 /* keep header in one piece */
726 last = sc->rx_size;
727 end = last + pad + len + I595_XMT_HDRLEN;
728 } else
729 end -= sc->tx_size;
730 }
731
732 bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
733 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
734 htole16(XMT_CMD));
735
736 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
737 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
738
739 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
740 htole16(len + pad));
741
742 residual = resval = 0;
743
744 while ((m = m0)!=0) {
745 data = mtod(m, void *);
746 llen = m->m_len;
747 if (residual) {
748 #ifdef IYDEBUG
749 printf("%s: merging residual with next mbuf.\n",
750 device_xname(sc->sc_dev));
751 #endif
752 resval |= *data << 8;
753 bus_space_write_stream_2(iot, ioh,
754 MEM_PORT_REG, resval);
755 --llen;
756 ++data;
757 }
758 /*
759 * XXX ALIGNMENT LOSSAGE HERE.
760 */
761 if (llen > 1)
762 bus_space_write_multi_stream_2(iot, ioh,
763 MEM_PORT_REG, (u_int16_t *) data,
764 llen>>1);
765 residual = llen & 1;
766 if (residual) {
767 resval = *(data + llen - 1);
768 #ifdef IYDEBUG
769 printf("%s: got odd mbuf to send.\n",
770 device_xname(sc->sc_dev));
771 #endif
772 }
773
774 m0 = m_free(m);
775 }
776
777 if (residual)
778 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
779 resval);
780
781 pad >>= 1;
782 while (pad-- > 0)
783 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, 0);
784
785 #ifdef IYDEBUG
786 printf("%s: new last = 0x%x, end = 0x%x.\n",
787 device_xname(sc->sc_dev), last, end);
788 printf("%s: old start = 0x%x, end = 0x%x, last = 0x%x\n",
789 device_xname(sc->sc_dev), sc->tx_start, sc->tx_end,
790 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,
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, u_int16_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 struct ifreq *ifr;
1167 int s, error = 0;
1168
1169 sc = ifp->if_softc;
1170 ifa = (struct ifaddr *)data;
1171 ifr = (struct ifreq *)data;
1172
1173 #ifdef IYDEBUG
1174 printf("iyioctl called with ifp %p (%s) cmd 0x%lx data %p\n",
1175 ifp, ifp->if_xname, cmd, data);
1176 #endif
1177
1178 s = splnet();
1179
1180 switch (cmd) {
1181
1182 case SIOCINITIFADDR:
1183 ifp->if_flags |= IFF_UP;
1184
1185 iyinit(sc);
1186 switch (ifa->ifa_addr->sa_family) {
1187 #ifdef INET
1188 case AF_INET:
1189 arp_ifinit(ifp, ifa);
1190 break;
1191 #endif
1192 default:
1193 break;
1194 }
1195 break;
1196
1197 case SIOCSIFFLAGS:
1198 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1199 break;
1200 sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1201 /* XXX re-use ether_ioctl() */
1202 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
1203 case IFF_RUNNING:
1204 /*
1205 * If interface is marked down and it is running, then
1206 * stop it.
1207 */
1208 iystop(sc);
1209 ifp->if_flags &= ~IFF_RUNNING;
1210 break;
1211 case IFF_UP:
1212 /*
1213 * If interface is marked up and it is stopped, then
1214 * start it.
1215 */
1216 iyinit(sc);
1217 break;
1218 default:
1219 /*
1220 * Reset the interface to pick up changes in any other
1221 * flags that affect hardware registers.
1222 */
1223 iystop(sc);
1224 iyinit(sc);
1225 break;
1226 }
1227 #ifdef IYDEBUGX
1228 if (ifp->if_flags & IFF_DEBUG)
1229 sc->sc_debug = IFY_ALL;
1230 else
1231 sc->sc_debug = 0;
1232 #endif
1233 break;
1234
1235 case SIOCADDMULTI:
1236 case SIOCDELMULTI:
1237 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
1238 /*
1239 * Multicast list has changed; set the hardware filter
1240 * accordingly.
1241 */
1242 if (ifp->if_flags & IFF_RUNNING) {
1243 /* XXX can't make it work otherwise */
1244 iyreset(sc);
1245 iy_mc_reset(sc);
1246 }
1247 error = 0;
1248 }
1249 break;
1250
1251 case SIOCSIFMEDIA:
1252 case SIOCGIFMEDIA:
1253 error = ifmedia_ioctl(ifp, ifr, &sc->iy_ifmedia, cmd);
1254 break;
1255 default:
1256 error = ether_ioctl(ifp, cmd, data);
1257 }
1258 splx(s);
1259 return error;
1260 }
1261
1262 int
1263 iy_mediachange(struct ifnet *ifp)
1264 {
1265 struct iy_softc *sc = ifp->if_softc;
1266
1267 if (IFM_TYPE(sc->iy_ifmedia.ifm_media) != IFM_ETHER)
1268 return EINVAL;
1269 switch(IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
1270 case IFM_10_5:
1271 case IFM_10_2:
1272 case IFM_10_T:
1273 case IFM_AUTO:
1274 iystop(sc);
1275 iyinit(sc);
1276 return 0;
1277 default:
1278 return EINVAL;
1279 }
1280 }
1281
1282 void
1283 iy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1284 {
1285 struct iy_softc *sc = ifp->if_softc;
1286
1287 ifmr->ifm_active = sc->iy_media;
1288 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1289 }
1290
1291
1292 static void
1293 iy_mc_setup(struct iy_softc *sc)
1294 {
1295 struct ether_multi *enm;
1296 struct ether_multistep step;
1297 struct ethercom *ecp;
1298 struct ifnet *ifp;
1299 bus_space_tag_t iot;
1300 bus_space_handle_t ioh;
1301 int avail, last /*, end*/ , len;
1302 int timeout;
1303 volatile u_int16_t dum;
1304 u_int8_t temp;
1305
1306
1307 ecp = &sc->sc_ethercom;
1308 ifp = &ecp->ec_if;
1309
1310 iot = sc->sc_iot;
1311 ioh = sc->sc_ioh;
1312
1313 len = 6 * ecp->ec_multicnt;
1314
1315 avail = sc->tx_start - sc->tx_end;
1316 if (avail <= 0)
1317 avail += sc->tx_size;
1318 if (ifp->if_flags & IFF_DEBUG)
1319 printf("%s: iy_mc_setup called, %d addresses, "
1320 "%d/%d bytes needed/avail\n", ifp->if_xname,
1321 ecp->ec_multicnt, len + I595_XMT_HDRLEN, avail);
1322
1323 last = sc->rx_size;
1324
1325 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
1326 bus_space_write_1(iot, ioh, RECV_MODES_REG, MATCH_BRDCST);
1327 /* XXX VOODOO */
1328 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
1329 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
1330 /* XXX END OF VOODOO */
1331 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
1332 bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
1333 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(MC_SETUP_CMD));
1334 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1335 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1336 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(len));
1337
1338 ETHER_FIRST_MULTI(step, ecp, enm);
1339 while(enm) {
1340 /*
1341 * XXX ALIGNMENT LOSSAGE HERE?
1342 */
1343 bus_space_write_multi_stream_2(iot, ioh, MEM_PORT_REG,
1344 (u_int16_t *) enm->enm_addrlo, 3);
1345
1346 ETHER_NEXT_MULTI(step, enm);
1347 }
1348 dum = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
1349 __USE(dum);
1350 bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
1351 bus_space_write_1(iot, ioh, 0, MC_SETUP_CMD);
1352
1353
1354 sc->tx_start = sc->rx_size;
1355 sc->tx_end = sc->rx_size + I595_XMT_HDRLEN + len;
1356
1357 for (timeout=0; timeout<100; timeout++) {
1358 DELAY(2);
1359 if ((bus_space_read_1(iot, ioh, STATUS_REG) & EXEC_INT) == 0)
1360 continue;
1361
1362 temp = bus_space_read_1(iot, ioh, 0);
1363 bus_space_write_1(iot, ioh, STATUS_REG, EXEC_INT);
1364 #ifdef DIAGNOSTIC
1365 if (temp & 0x20) {
1366 aprint_error_dev(sc->sc_dev,
1367 "mc setup failed, %d usec\n", timeout * 2);
1368 } else if (((temp & 0x0f) == 0x03) &&
1369 (ifp->if_flags & IFF_DEBUG)) {
1370 printf("%s: mc setup done, %d usec\n",
1371 device_xname(sc->sc_dev), timeout * 2);
1372 }
1373 #endif
1374 break;
1375 }
1376 sc->tx_start = sc->tx_end;
1377 ifp->if_flags &= ~IFF_OACTIVE;
1378
1379 }
1380
1381 static void
1382 iy_mc_reset(struct iy_softc *sc)
1383 {
1384 struct ether_multi *enm;
1385 struct ether_multistep step;
1386 struct ethercom *ecp;
1387 struct ifnet *ifp;
1388 bus_space_tag_t iot;
1389 bus_space_handle_t ioh;
1390 u_int16_t temp;
1391
1392 ecp = &sc->sc_ethercom;
1393 ifp = &ecp->ec_if;
1394
1395 iot = sc->sc_iot;
1396 ioh = sc->sc_ioh;
1397
1398 if (ecp->ec_multicnt > 63) {
1399 ifp->if_flags |= IFF_ALLMULTI;
1400
1401 } else if (ecp->ec_multicnt > 0) {
1402 /*
1403 * Step through the list of addresses.
1404 */
1405 ETHER_FIRST_MULTI(step, ecp, enm);
1406 while(enm) {
1407 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
1408 ifp->if_flags |= IFF_ALLMULTI;
1409 goto setupmulti;
1410 }
1411 ETHER_NEXT_MULTI(step, enm);
1412 }
1413 /* OK, we really need to do it now: */
1414 #if 0
1415 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE))
1416 != IFF_RUNNING) {
1417 ifp->if_flags |= IFF_OACTIVE;
1418 sc->want_mc_setup = 1;
1419 return;
1420 }
1421 #endif
1422 iy_mc_setup(sc);
1423 } else {
1424 ifp->if_flags &= ~IFF_ALLMULTI;
1425 }
1426
1427 setupmulti:
1428 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
1429 if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
1430 temp = MATCH_ALL;
1431 } else
1432 temp = MATCH_BRDCST;
1433
1434 bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
1435 /* XXX VOODOO */
1436 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
1437 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
1438 /* XXX END OF VOODOO */
1439
1440 /* XXX TBD: setup hardware for all multicasts */
1441 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
1442 return;
1443 }
1444
1445 #ifdef IYDEBUGX
1446 void
1447 print_rbd(volatile struct ie_recv_buf_desc *rbd)
1448 {
1449 printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
1450 "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
1451 rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
1452 rbd->mbz);
1453 }
1454 #endif
1455
1456 void
1457 iyprobemem(struct iy_softc *sc)
1458 {
1459 bus_space_tag_t iot;
1460 bus_space_handle_t ioh;
1461 int testing;
1462
1463 iot = sc->sc_iot;
1464 ioh = sc->sc_ioh;
1465
1466 bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
1467 delay(1);
1468 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 4096-2);
1469 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1470
1471 for (testing=65536; testing >= 4096; testing >>= 1) {
1472 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1473 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xdead);
1474 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1475 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xdead) {
1476 #ifdef IYMEMDEBUG
1477 printf("%s: Didn't keep 0xdead at 0x%x\n",
1478 device_xname(sc->sc_dev), testing-2);
1479 #endif
1480 continue;
1481 }
1482
1483 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1484 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xbeef);
1485 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1486 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xbeef) {
1487 #ifdef IYMEMDEBUG
1488 printf("%s: Didn't keep 0xbeef at 0x%x\n",
1489 device_xname(sc->sc_dev), testing-2);
1490 #endif
1491 continue;
1492 }
1493
1494 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1495 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1496 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing >> 1);
1497 bus_space_write_2(iot, ioh, MEM_PORT_REG, testing >> 1);
1498 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1499 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) == (testing >> 1)) {
1500 #ifdef IYMEMDEBUG
1501 printf("%s: 0x%x alias of 0x0\n",
1502 device_xname(sc->sc_dev), testing >> 1);
1503 #endif
1504 continue;
1505 }
1506
1507 break;
1508 }
1509
1510 sc->sram = testing;
1511
1512 switch(testing) {
1513 case 65536:
1514 /* 4 NFS packets + overhead RX, 2 NFS + overhead TX */
1515 sc->rx_size = 44*1024;
1516 break;
1517
1518 case 32768:
1519 /* 2 NFS packets + overhead RX, 1 NFS + overhead TX */
1520 sc->rx_size = 22*1024;
1521 break;
1522
1523 case 16384:
1524 /* 1 NFS packet + overhead RX, 4 big packets TX */
1525 sc->rx_size = 10*1024;
1526 break;
1527 default:
1528 sc->rx_size = testing/2;
1529 break;
1530 }
1531 sc->tx_size = testing - sc->rx_size;
1532 }
1533
1534 static int
1535 eepromreadall(bus_space_tag_t iot, bus_space_handle_t ioh, u_int16_t *wordp,
1536 int maxi)
1537 {
1538 int i;
1539 u_int16_t checksum, tmp;
1540
1541 checksum = 0;
1542
1543 for (i=0; i<EEPP_LENGTH; ++i) {
1544 tmp = eepromread(iot, ioh, i);
1545 checksum += tmp;
1546 if (i<maxi)
1547 wordp[i] = tmp;
1548 }
1549
1550 if (checksum != EEPP_CHKSUM) {
1551 #ifdef IYDEBUG
1552 printf("wrong EEPROM checksum 0x%x should be 0x%x\n",
1553 checksum, EEPP_CHKSUM);
1554 #endif
1555 return 1;
1556 }
1557 return 0;
1558 }
1559