if_iy.c revision 1.101 1 /* $NetBSD: if_iy.c,v 1.101 2018/06/22 04:17:42 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.101 2018/06/22 04:17:42 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_NOTRAILERS
312 | IFF_MULTICAST;
313
314 sc->doing_mc_setup = 0;
315
316 ifp->if_ioctl = iyioctl;
317 ifp->if_watchdog = iywatchdog;
318
319 IFQ_SET_READY(&ifp->if_snd);
320
321 (void)eepromreadall(iot, ioh, eaddr, 8);
322 sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev;
323
324 #ifdef DIAGNOSTICS
325 if ((eaddr[EEPPEther0] !=
326 eepromread(iot, ioh, EEPPEther0a)) &&
327 (eaddr[EEPPEther1] !=
328 eepromread(iot, ioh, EEPPEther1a)) &&
329 (eaddr[EEPPEther2] !=
330 eepromread(iot, ioh, EEPPEther2a)))
331
332 aprint_error("EEPROM Ethernet address differs from copy\n");
333 #endif
334
335 myaddr[1] = eaddr[EEPPEther0] & 0xFF;
336 myaddr[0] = eaddr[EEPPEther0] >> 8;
337 myaddr[3] = eaddr[EEPPEther1] & 0xFF;
338 myaddr[2] = eaddr[EEPPEther1] >> 8;
339 myaddr[5] = eaddr[EEPPEther2] & 0xFF;
340 myaddr[4] = eaddr[EEPPEther2] >> 8;
341
342 ifmedia_init(&sc->iy_ifmedia, 0, iy_mediachange, iy_mediastatus);
343 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_2, 0, NULL);
344 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
345 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
346 ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
347 ifmedia_set(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO);
348 /* Attach the interface. */
349 if_attach(ifp);
350 ether_ifattach(ifp, myaddr);
351 aprint_normal(": address %s, rev. %d, %d kB\n",
352 ether_sprintf(myaddr),
353 sc->hard_vers, sc->sram/1024);
354
355 eirq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
356 if (eirq != ia->ia_irq[0].ir_irq)
357 aprint_error("%s: EEPROM irq setting %d ignored\n",
358 device_xname(sc->sc_dev), eirq);
359
360 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
361 IST_EDGE, IPL_NET, iyintr, sc);
362
363 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
364 RND_TYPE_NET, RND_FLAG_DEFAULT);
365
366 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
367 bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
368 }
369
370 void
371 iystop(struct iy_softc *sc)
372 {
373 bus_space_tag_t iot;
374 bus_space_handle_t ioh;
375 #ifdef IYDEBUG
376 u_int p, v;
377 #endif
378
379 iot = sc->sc_iot;
380 ioh = sc->sc_ioh;
381
382 bus_space_write_1(iot, ioh, COMMAND_REG, RCV_DISABLE_CMD);
383
384 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
385 bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS);
386
387 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
388 delay(200);
389 #ifdef IYDEBUG
390 printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n",
391 device_xname(sc->sc_dev), sc->tx_start, sc->tx_end, sc->tx_last);
392 p = sc->tx_last;
393 if (!p)
394 p = sc->tx_start;
395 do {
396 char sbuf[128];
397
398 bus_space_write_2(iot, ioh, HOST_ADDR_REG, p);
399
400 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
401 snprintb(sbuf, sizeof(sbuf), "\020\006Ab\010Dn", v);
402 printf("0x%04x: %s ", p, sbuf);
403
404 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
405 snprintb(sbuf, sizeof(sbuf),
406 "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN"
407 "\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL", v);
408 printf("%s", sbuf);
409
410 p = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
411 printf(" 0x%04x", p);
412
413 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
414 snprintb(sbuf, sizeof(sbuf), "\020\020Ch", v);
415 printf(" %s\n", sbuf);
416
417 } while (v & 0x8000);
418 #endif
419 sc->tx_start = sc->tx_end = sc->rx_size;
420 sc->tx_last = 0;
421 sc->sc_ethercom.ec_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
422 }
423
424 void
425 iyreset(struct iy_softc *sc)
426 {
427 int s;
428 s = splnet();
429 iystop(sc);
430 iyinit(sc);
431 splx(s);
432 }
433
434 void
435 iyinit(struct iy_softc *sc)
436 {
437 int i;
438 unsigned temp;
439 struct ifnet *ifp;
440 bus_space_tag_t iot;
441 bus_space_handle_t ioh;
442
443 iot = sc->sc_iot;
444 ioh = sc->sc_ioh;
445
446 ifp = &sc->sc_ethercom.ec_if;
447 #ifdef IYDEBUG
448 printf("ifp is %p\n", ifp);
449 #endif
450
451 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
452
453 temp = bus_space_read_1(iot, ioh, EEPROM_REG);
454 if (temp & 0x10)
455 bus_space_write_1(iot, ioh, EEPROM_REG, temp & ~0x10);
456
457 for (i=0; i<6; ++i) {
458 bus_space_write_1(iot, ioh, I_ADD(i), CLLADDR(ifp->if_sadl)[i]);
459 }
460
461 temp = bus_space_read_1(iot, ioh, REG1);
462 bus_space_write_1(iot, ioh, REG1,
463 temp | /* XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP | */ RCV_DISCARD_BAD);
464
465 if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
466 temp = MATCH_ALL;
467 } else
468 temp = MATCH_BRDCST;
469
470 bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
471
472 #ifdef IYDEBUG
473 {
474 char sbuf[128];
475
476 snprintb(sbuf, sizeof(sbuf),
477 "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA",
478 temp);
479
480 printf("%s: RECV_MODES set to %s\n", device_xname(sc->sc_dev),
481 sbuf);
482 }
483 #endif
484 /* XXX VOODOO */
485 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
486 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
487 /* XXX END OF VOODOO */
488
489
490 delay(500000); /* for the hardware to test for the connector */
491
492 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
493 #ifdef IYDEBUG
494 {
495 char sbuf[128];
496
497 snprintb(sbuf, sizeof(sbuf),
498 "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
499 temp);
500 printf("%s: media select was %s ", device_xname(sc->sc_dev),
501 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 %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 m0 = m_free(m);
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,
791 sc->tx_last);
792 #endif
793
794 if (sc->tx_start != sc->tx_end) {
795 bus_space_write_2(iot, ioh, HOST_ADDR_REG,
796 sc->tx_last + XMT_COUNT);
797
798 /*
799 * XXX We keep stat in le order, to potentially save
800 * a byte swap.
801 */
802 stat = bus_space_read_stream_2(iot, ioh, MEM_PORT_REG);
803
804 bus_space_write_2(iot, ioh, HOST_ADDR_REG,
805 sc->tx_last + XMT_CHAIN);
806
807 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
808 htole16(last));
809
810 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
811 stat | htole16(CHAIN));
812 #ifdef IYDEBUG
813 printf("%s: setting 0x%x to 0x%x\n",
814 device_xname(sc->sc_dev), sc->tx_last + XMT_COUNT,
815 le16toh(stat) | CHAIN);
816 #endif
817 }
818 stat = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
819
820 /* XXX todo: enable ints here if disabled */
821
822 ++ifp->if_opackets;
823
824 if (sc->tx_start == sc->tx_end) {
825 bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
826 bus_space_write_1(iot, ioh, 0, XMT_CMD);
827 sc->tx_start = last;
828 #ifdef IYDEBUG
829 printf("%s: writing 0x%x to XAR and giving XCMD\n",
830 device_xname(sc->sc_dev), last);
831 #endif
832 } else {
833 bus_space_write_1(iot, ioh, 0, RESUME_XMT_CMD);
834 #ifdef IYDEBUG
835 printf("%s: giving RESUME_XCMD\n",
836 device_xname(sc->sc_dev));
837 #endif
838 }
839 sc->tx_last = last;
840 sc->tx_end = end;
841 }
842 /* and wait only for end of transmission chain */
843 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
844
845 temp = bus_space_read_1(iot, ioh, REG1);
846 bus_space_write_1(iot, ioh, REG1, temp | XMT_CHAIN_INT);
847
848 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
849 }
850
851
852 static inline void
853 eepromwritebit(bus_space_tag_t iot, bus_space_handle_t ioh, int what)
854 {
855 bus_space_write_1(iot, ioh, EEPROM_REG, what);
856 delay(1);
857 bus_space_write_1(iot, ioh, EEPROM_REG, what|EESK);
858 delay(1);
859 bus_space_write_1(iot, ioh, EEPROM_REG, what);
860 delay(1);
861 }
862
863 static inline int
864 eepromreadbit(bus_space_tag_t iot, bus_space_handle_t ioh)
865 {
866 int b;
867
868 bus_space_write_1(iot, ioh, EEPROM_REG, EECS|EESK);
869 delay(1);
870 b = bus_space_read_1(iot, ioh, EEPROM_REG);
871 bus_space_write_1(iot, ioh, EEPROM_REG, EECS);
872 delay(1);
873
874 return ((b & EEDO) != 0);
875 }
876
877 static u_int16_t
878 eepromread(bus_space_tag_t iot, bus_space_handle_t ioh, int offset)
879 {
880 volatile int i;
881 volatile int j;
882 volatile u_int16_t readval;
883
884 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
885 delay(1);
886 bus_space_write_1(iot, ioh, EEPROM_REG, EECS); /* XXXX??? */
887 delay(1);
888
889 eepromwritebit(iot, ioh, EECS|EEDI);
890 eepromwritebit(iot, ioh, EECS|EEDI);
891 eepromwritebit(iot, ioh, EECS);
892
893 for (j=5; j>=0; --j) {
894 if ((offset>>j) & 1)
895 eepromwritebit(iot, ioh, EECS|EEDI);
896 else
897 eepromwritebit(iot, ioh, EECS);
898 }
899
900 for (readval=0, i=0; i<16; ++i) {
901 readval<<=1;
902 readval |= eepromreadbit(iot, ioh);
903 }
904
905 bus_space_write_1(iot, ioh, EEPROM_REG, 0|EESK);
906 delay(1);
907 bus_space_write_1(iot, ioh, EEPROM_REG, 0);
908
909 bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
910
911 return readval;
912 }
913
914 /*
915 * Device timeout/watchdog routine. Entered if the device neglects to generate
916 * an interrupt after a transmit has been started on it.
917 */
918 void
919 iywatchdog(struct ifnet *ifp)
920 {
921 struct iy_softc *sc = ifp->if_softc;
922
923 log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
924 ++sc->sc_ethercom.ec_if.if_oerrors;
925 iyreset(sc);
926 }
927
928 /*
929 * What to do upon receipt of an interrupt.
930 */
931 int
932 iyintr(void *arg)
933 {
934 struct iy_softc *sc;
935 struct ifnet *ifp;
936 bus_space_tag_t iot;
937 bus_space_handle_t ioh;
938
939 u_short status;
940
941 sc = arg;
942 iot = sc->sc_iot;
943 ioh = sc->sc_ioh;
944
945 ifp = &sc->sc_ethercom.ec_if;
946
947 status = bus_space_read_1(iot, ioh, STATUS_REG);
948 #ifdef IYDEBUG
949 if (status & ALL_INTS) {
950 char sbuf[128];
951
952 snprintb(sbuf, sizeof(sbuf), "\020\1RX_STP\2RX\3TX\4EXEC",
953 status);
954 printf("%s: got interrupt %s", device_xname(sc->sc_dev), sbuf);
955
956 if (status & EXEC_INT) {
957 snprintb(sbuf, sizeof(sbuf),
958 "\020\6ABORT", bus_space_read_1(iot, ioh, 0));
959 printf(" event %s\n", sbuf);
960 } else
961 printf("\n");
962 }
963 #endif
964 if ((status & (RX_INT | TX_INT)) == 0)
965 return 0;
966
967 if (status & RX_INT) {
968 iy_intr_rx(sc);
969 bus_space_write_1(iot, ioh, STATUS_REG, RX_INT);
970 }
971 if (status & TX_INT) {
972 /* Tell feeders we may be able to accept more data... */
973 ifp->if_flags &= ~IFF_OACTIVE;
974 /* and get more data. */
975 iystart(ifp);
976 bus_space_write_1(iot, ioh, STATUS_REG, TX_INT);
977 }
978
979 rnd_add_uint32(&sc->rnd_source, status);
980
981 return 1;
982 }
983
984 void
985 iyget(struct iy_softc *sc, bus_space_tag_t iot, bus_space_handle_t ioh,
986 int rxlen)
987 {
988 struct mbuf *m, *top, **mp;
989 struct ifnet *ifp;
990 int len;
991
992 ifp = &sc->sc_ethercom.ec_if;
993
994 MGETHDR(m, M_DONTWAIT, MT_DATA);
995 if (m == 0)
996 goto dropped;
997 m_set_rcvif(m, ifp);
998 m->m_pkthdr.len = rxlen;
999 len = MHLEN;
1000 top = 0;
1001 mp = ⊤
1002
1003 while (rxlen > 0) {
1004 if (top) {
1005 MGET(m, M_DONTWAIT, MT_DATA);
1006 if (m == 0) {
1007 m_freem(top);
1008 goto dropped;
1009 }
1010 len = MLEN;
1011 }
1012 if (rxlen >= MINCLSIZE) {
1013 MCLGET(m, M_DONTWAIT);
1014 if ((m->m_flags & M_EXT) == 0) {
1015 m_free(m);
1016 m_freem(top);
1017 goto dropped;
1018 }
1019 len = MCLBYTES;
1020 }
1021 len = min(rxlen, len);
1022 /*
1023 * XXX ALIGNMENT LOSSAGE HERE.
1024 */
1025 if (len > 1) {
1026 len &= ~1;
1027
1028 bus_space_read_multi_stream_2(iot, ioh, MEM_PORT_REG,
1029 mtod(m, u_int16_t *), len/2);
1030 } else {
1031 #ifdef IYDEBUG
1032 printf("%s: received odd mbuf\n",
1033 device_xname(sc->sc_dev));
1034 #endif
1035 *(mtod(m, char *)) = bus_space_read_stream_2(iot, ioh,
1036 MEM_PORT_REG);
1037 }
1038 m->m_len = len;
1039 rxlen -= len;
1040 *mp = m;
1041 mp = &m->m_next;
1042 }
1043
1044 if (top == NULL)
1045 return;
1046
1047 if_percpuq_enqueue(ifp->if_percpuq, top);
1048 return;
1049
1050 dropped:
1051 ++ifp->if_ierrors;
1052 return;
1053 }
1054
1055 void
1056 iy_intr_rx(struct iy_softc *sc)
1057 {
1058 bus_space_tag_t iot;
1059 bus_space_handle_t ioh;
1060
1061 u_int rxadrs, rxevnt, rxstatus, rxnext, rxlen;
1062
1063 iot = sc->sc_iot;
1064 ioh = sc->sc_ioh;
1065
1066 rxadrs = sc->rx_start;
1067 bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxadrs);
1068 rxevnt = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
1069 rxnext = 0;
1070
1071 while (rxevnt == RCV_DONE) {
1072 rxstatus = le16toh(bus_space_read_stream_2(iot, ioh,
1073 MEM_PORT_REG));
1074 rxnext = le16toh(bus_space_read_stream_2(iot, ioh,
1075 MEM_PORT_REG));
1076 rxlen = le16toh(bus_space_read_stream_2(iot, ioh,
1077 MEM_PORT_REG));
1078 #ifdef IYDEBUG
1079 {
1080 char sbuf[128];
1081
1082 snprintb(sbuf, sizeof(sbuf),
1083 "\020\1RCLD\2IA_MCH\010SHORT\011OVRN\013ALGERR"
1084 "\014CRCERR\015LENERR\016RCVOK\020TYP", rxstatus);
1085
1086 printf("%s: pck at 0x%04x stat %s next 0x%x len 0x%x\n",
1087 device_xname(sc->sc_dev), rxadrs, sbuf, rxnext,
1088 rxlen);
1089 }
1090 #else
1091 __USE(rxstatus);
1092 #endif
1093 iyget(sc, iot, ioh, rxlen);
1094
1095 /* move stop address */
1096 bus_space_write_2(iot, ioh, RCV_STOP_LOW,
1097 rxnext == 0 ? sc->rx_size - 2 : rxnext - 2);
1098
1099 bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxnext);
1100 rxadrs = rxnext;
1101 rxevnt = le16toh(bus_space_read_stream_2(iot, ioh,
1102 MEM_PORT_REG));
1103 }
1104 sc->rx_start = rxnext;
1105 }
1106
1107 void
1108 iy_intr_tx(struct iy_softc *sc)
1109 {
1110 bus_space_tag_t iot;
1111 bus_space_handle_t ioh;
1112 struct ifnet *ifp;
1113 u_int txstatus, txstat2, txlen, txnext;
1114
1115 ifp = &sc->sc_ethercom.ec_if;
1116 iot = sc->sc_iot;
1117 ioh = sc->sc_ioh;
1118
1119 while (sc->tx_start != sc->tx_end) {
1120 bus_space_write_2(iot, ioh, HOST_ADDR_REG, sc->tx_start);
1121 txstatus = le16toh(bus_space_read_stream_2(iot, ioh,
1122 MEM_PORT_REG));
1123
1124 if ((txstatus & (TX_DONE|CMD_MASK)) != (TX_DONE|XMT_CMD))
1125 break;
1126
1127 txstat2 = le16toh(bus_space_read_stream_2(iot, ioh,
1128 MEM_PORT_REG));
1129 txnext = le16toh(bus_space_read_stream_2(iot, ioh,
1130 MEM_PORT_REG));
1131 txlen = le16toh(bus_space_read_stream_2(iot, ioh,
1132 MEM_PORT_REG));
1133 #ifdef IYDEBUG
1134 {
1135 char sbuf[128];
1136
1137 snprintb(sbuf, sizeof(sbuf),
1138 "\020\6MAX_COL\7HRT_BEAT\010TX_DEF"
1139 "\011UND_RUN\012JERR\013LST_CRS"
1140 "\014LTCOL\016TX_OK\020COLL", txstat2);
1141
1142 printf("txstat 0x%x stat2 %s next 0x%x len 0x%x\n",
1143 txstatus, sbuf, txnext, txlen);
1144 }
1145 #endif
1146 if (txlen & CHAIN)
1147 sc->tx_start = txnext;
1148 else
1149 sc->tx_start = sc->tx_end;
1150 ifp->if_flags &= ~IFF_OACTIVE;
1151
1152 if (txstat2 & 0x0020)
1153 ifp->if_collisions += 16;
1154 else
1155 ifp->if_collisions += txstat2 & 0x000f;
1156
1157 if ((txstat2 & 0x2000) == 0)
1158 ++ifp->if_oerrors;
1159 }
1160 }
1161
1162 int
1163 iyioctl(struct ifnet *ifp, u_long cmd, void *data)
1164 {
1165 struct iy_softc *sc;
1166 struct ifaddr *ifa;
1167 struct ifreq *ifr;
1168 int s, error = 0;
1169
1170 sc = ifp->if_softc;
1171 ifa = (struct ifaddr *)data;
1172 ifr = (struct ifreq *)data;
1173
1174 #ifdef IYDEBUG
1175 printf("iyioctl called with ifp %p (%s) cmd 0x%lx data %p\n",
1176 ifp, ifp->if_xname, cmd, data);
1177 #endif
1178
1179 s = splnet();
1180
1181 switch (cmd) {
1182
1183 case SIOCINITIFADDR:
1184 ifp->if_flags |= IFF_UP;
1185
1186 iyinit(sc);
1187 switch (ifa->ifa_addr->sa_family) {
1188 #ifdef INET
1189 case AF_INET:
1190 arp_ifinit(ifp, ifa);
1191 break;
1192 #endif
1193 default:
1194 break;
1195 }
1196 break;
1197
1198 case SIOCSIFFLAGS:
1199 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1200 break;
1201 sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1202 /* XXX re-use ether_ioctl() */
1203 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
1204 case IFF_RUNNING:
1205 /*
1206 * If interface is marked down and it is running, then
1207 * stop it.
1208 */
1209 iystop(sc);
1210 ifp->if_flags &= ~IFF_RUNNING;
1211 break;
1212 case IFF_UP:
1213 /*
1214 * If interface is marked up and it is stopped, then
1215 * start it.
1216 */
1217 iyinit(sc);
1218 break;
1219 default:
1220 /*
1221 * Reset the interface to pick up changes in any other
1222 * flags that affect hardware registers.
1223 */
1224 iystop(sc);
1225 iyinit(sc);
1226 break;
1227 }
1228 #ifdef IYDEBUGX
1229 if (ifp->if_flags & IFF_DEBUG)
1230 sc->sc_debug = IFY_ALL;
1231 else
1232 sc->sc_debug = 0;
1233 #endif
1234 break;
1235
1236 case SIOCADDMULTI:
1237 case SIOCDELMULTI:
1238 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
1239 /*
1240 * Multicast list has changed; set the hardware filter
1241 * accordingly.
1242 */
1243 if (ifp->if_flags & IFF_RUNNING) {
1244 /* XXX can't make it work otherwise */
1245 iyreset(sc);
1246 iy_mc_reset(sc);
1247 }
1248 error = 0;
1249 }
1250 break;
1251
1252 case SIOCSIFMEDIA:
1253 case SIOCGIFMEDIA:
1254 error = ifmedia_ioctl(ifp, ifr, &sc->iy_ifmedia, cmd);
1255 break;
1256 default:
1257 error = ether_ioctl(ifp, cmd, data);
1258 }
1259 splx(s);
1260 return error;
1261 }
1262
1263 int
1264 iy_mediachange(struct ifnet *ifp)
1265 {
1266 struct iy_softc *sc = ifp->if_softc;
1267
1268 if (IFM_TYPE(sc->iy_ifmedia.ifm_media) != IFM_ETHER)
1269 return EINVAL;
1270 switch(IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
1271 case IFM_10_5:
1272 case IFM_10_2:
1273 case IFM_10_T:
1274 case IFM_AUTO:
1275 iystop(sc);
1276 iyinit(sc);
1277 return 0;
1278 default:
1279 return EINVAL;
1280 }
1281 }
1282
1283 void
1284 iy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1285 {
1286 struct iy_softc *sc = ifp->if_softc;
1287
1288 ifmr->ifm_active = sc->iy_media;
1289 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1290 }
1291
1292
1293 static void
1294 iy_mc_setup(struct iy_softc *sc)
1295 {
1296 struct ether_multi *enm;
1297 struct ether_multistep step;
1298 struct ethercom *ecp;
1299 struct ifnet *ifp;
1300 bus_space_tag_t iot;
1301 bus_space_handle_t ioh;
1302 int avail, last /*, end*/ , len;
1303 int timeout;
1304 volatile u_int16_t dum;
1305 u_int8_t temp;
1306
1307
1308 ecp = &sc->sc_ethercom;
1309 ifp = &ecp->ec_if;
1310
1311 iot = sc->sc_iot;
1312 ioh = sc->sc_ioh;
1313
1314 len = 6 * ecp->ec_multicnt;
1315
1316 avail = sc->tx_start - sc->tx_end;
1317 if (avail <= 0)
1318 avail += sc->tx_size;
1319 if (ifp->if_flags & IFF_DEBUG)
1320 printf("%s: iy_mc_setup called, %d addresses, "
1321 "%d/%d bytes needed/avail\n", ifp->if_xname,
1322 ecp->ec_multicnt, len + I595_XMT_HDRLEN, avail);
1323
1324 last = sc->rx_size;
1325
1326 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
1327 bus_space_write_1(iot, ioh, RECV_MODES_REG, MATCH_BRDCST);
1328 /* XXX VOODOO */
1329 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
1330 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
1331 /* XXX END OF VOODOO */
1332 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
1333 bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
1334 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(MC_SETUP_CMD));
1335 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1336 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1337 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(len));
1338
1339 ETHER_FIRST_MULTI(step, ecp, enm);
1340 while(enm) {
1341 /*
1342 * XXX ALIGNMENT LOSSAGE HERE?
1343 */
1344 bus_space_write_multi_stream_2(iot, ioh, MEM_PORT_REG,
1345 (u_int16_t *) enm->enm_addrlo, 3);
1346
1347 ETHER_NEXT_MULTI(step, enm);
1348 }
1349 dum = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
1350 __USE(dum);
1351 bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
1352 bus_space_write_1(iot, ioh, 0, MC_SETUP_CMD);
1353
1354
1355 sc->tx_start = sc->rx_size;
1356 sc->tx_end = sc->rx_size + I595_XMT_HDRLEN + len;
1357
1358 for (timeout=0; timeout<100; timeout++) {
1359 DELAY(2);
1360 if ((bus_space_read_1(iot, ioh, STATUS_REG) & EXEC_INT) == 0)
1361 continue;
1362
1363 temp = bus_space_read_1(iot, ioh, 0);
1364 bus_space_write_1(iot, ioh, STATUS_REG, EXEC_INT);
1365 #ifdef DIAGNOSTIC
1366 if (temp & 0x20) {
1367 aprint_error_dev(sc->sc_dev,
1368 "mc setup failed, %d usec\n", timeout * 2);
1369 } else if (((temp & 0x0f) == 0x03) &&
1370 (ifp->if_flags & IFF_DEBUG)) {
1371 printf("%s: mc setup done, %d usec\n",
1372 device_xname(sc->sc_dev), timeout * 2);
1373 }
1374 #endif
1375 break;
1376 }
1377 sc->tx_start = sc->tx_end;
1378 ifp->if_flags &= ~IFF_OACTIVE;
1379
1380 }
1381
1382 static void
1383 iy_mc_reset(struct iy_softc *sc)
1384 {
1385 struct ether_multi *enm;
1386 struct ether_multistep step;
1387 struct ethercom *ecp;
1388 struct ifnet *ifp;
1389 bus_space_tag_t iot;
1390 bus_space_handle_t ioh;
1391 u_int16_t temp;
1392
1393 ecp = &sc->sc_ethercom;
1394 ifp = &ecp->ec_if;
1395
1396 iot = sc->sc_iot;
1397 ioh = sc->sc_ioh;
1398
1399 if (ecp->ec_multicnt > 63) {
1400 ifp->if_flags |= IFF_ALLMULTI;
1401
1402 } else if (ecp->ec_multicnt > 0) {
1403 /*
1404 * Step through the list of addresses.
1405 */
1406 ETHER_FIRST_MULTI(step, ecp, enm);
1407 while(enm) {
1408 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
1409 ifp->if_flags |= IFF_ALLMULTI;
1410 goto setupmulti;
1411 }
1412 ETHER_NEXT_MULTI(step, enm);
1413 }
1414 /* OK, we really need to do it now: */
1415 #if 0
1416 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE))
1417 != IFF_RUNNING) {
1418 ifp->if_flags |= IFF_OACTIVE;
1419 sc->want_mc_setup = 1;
1420 return;
1421 }
1422 #endif
1423 iy_mc_setup(sc);
1424 } else {
1425 ifp->if_flags &= ~IFF_ALLMULTI;
1426 }
1427
1428 setupmulti:
1429 bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
1430 if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
1431 temp = MATCH_ALL;
1432 } else
1433 temp = MATCH_BRDCST;
1434
1435 bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
1436 /* XXX VOODOO */
1437 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
1438 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
1439 /* XXX END OF VOODOO */
1440
1441 /* XXX TBD: setup hardware for all multicasts */
1442 bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
1443 return;
1444 }
1445
1446 #ifdef IYDEBUGX
1447 void
1448 print_rbd(volatile struct ie_recv_buf_desc *rbd)
1449 {
1450 printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
1451 "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
1452 rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
1453 rbd->mbz);
1454 }
1455 #endif
1456
1457 void
1458 iyprobemem(struct iy_softc *sc)
1459 {
1460 bus_space_tag_t iot;
1461 bus_space_handle_t ioh;
1462 int testing;
1463
1464 iot = sc->sc_iot;
1465 ioh = sc->sc_ioh;
1466
1467 bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
1468 delay(1);
1469 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 4096-2);
1470 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1471
1472 for (testing=65536; testing >= 4096; testing >>= 1) {
1473 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1474 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xdead);
1475 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1476 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xdead) {
1477 #ifdef IYMEMDEBUG
1478 printf("%s: Didn't keep 0xdead at 0x%x\n",
1479 device_xname(sc->sc_dev), testing-2);
1480 #endif
1481 continue;
1482 }
1483
1484 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1485 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xbeef);
1486 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
1487 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xbeef) {
1488 #ifdef IYMEMDEBUG
1489 printf("%s: Didn't keep 0xbeef at 0x%x\n",
1490 device_xname(sc->sc_dev), testing-2);
1491 #endif
1492 continue;
1493 }
1494
1495 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1496 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
1497 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing >> 1);
1498 bus_space_write_2(iot, ioh, MEM_PORT_REG, testing >> 1);
1499 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
1500 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) == (testing >> 1)) {
1501 #ifdef IYMEMDEBUG
1502 printf("%s: 0x%x alias of 0x0\n",
1503 device_xname(sc->sc_dev), testing >> 1);
1504 #endif
1505 continue;
1506 }
1507
1508 break;
1509 }
1510
1511 sc->sram = testing;
1512
1513 switch(testing) {
1514 case 65536:
1515 /* 4 NFS packets + overhead RX, 2 NFS + overhead TX */
1516 sc->rx_size = 44*1024;
1517 break;
1518
1519 case 32768:
1520 /* 2 NFS packets + overhead RX, 1 NFS + overhead TX */
1521 sc->rx_size = 22*1024;
1522 break;
1523
1524 case 16384:
1525 /* 1 NFS packet + overhead RX, 4 big packets TX */
1526 sc->rx_size = 10*1024;
1527 break;
1528 default:
1529 sc->rx_size = testing/2;
1530 break;
1531 }
1532 sc->tx_size = testing - sc->rx_size;
1533 }
1534
1535 static int
1536 eepromreadall(bus_space_tag_t iot, bus_space_handle_t ioh, u_int16_t *wordp,
1537 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