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