Annotation of src/sys/dev/pcmcia/if_xi.c, Revision 1.36
1.36 ! mycroft 1: /* $NetBSD: if_xi.c,v 1.35 2004/08/06 20:38:09 mycroft Exp $ */
1.1 gmcgarry 2: /* OpenBSD: if_xe.c,v 1.9 1999/09/16 11:28:42 niklas Exp */
1.5 thorpej 3:
4: /*
5: * XXX THIS DRIVER IS BROKEN WRT. MULTICAST LISTS AND PROMISC/ALLMULTI
6: * XXX FLAGS!
7: */
1.1 gmcgarry 8:
9: /*
10: * Copyright (c) 1999 Niklas Hallqvist, Brandon Creighton, Job de Haas
11: * All rights reserved.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by Niklas Hallqvist,
24: * Brandon Creighton and Job de Haas.
25: * 4. The name of the author may not be used to endorse or promote products
26: * derived from this software without specific prior written permission
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * A driver for Xircom CreditCard PCMCIA Ethernet adapters.
42: */
43:
44: /*
45: * Known Bugs:
46: *
47: * 1) Promiscuous mode doesn't work on at least the CE2.
48: * 2) Slow. ~450KB/s. Memory access would be better.
49: */
1.18 lukem 50:
51: #include <sys/cdefs.h>
1.36 ! mycroft 52: __KERNEL_RCSID(0, "$NetBSD: if_xi.c,v 1.35 2004/08/06 20:38:09 mycroft Exp $");
1.1 gmcgarry 53:
54: #include "opt_inet.h"
1.31 martin 55: #include "opt_ipx.h"
1.1 gmcgarry 56: #include "bpfilter.h"
57:
58: #include <sys/param.h>
59: #include <sys/systm.h>
60: #include <sys/device.h>
61: #include <sys/ioctl.h>
62: #include <sys/mbuf.h>
63: #include <sys/malloc.h>
64: #include <sys/socket.h>
65:
1.11 gmcgarry 66: #include "rnd.h"
67: #if NRND > 0
68: #include <sys/rnd.h>
69: #endif
70:
1.1 gmcgarry 71: #include <net/if.h>
72: #include <net/if_dl.h>
73: #include <net/if_media.h>
74: #include <net/if_types.h>
75: #include <net/if_ether.h>
76:
77: #ifdef INET
78: #include <netinet/in.h>
79: #include <netinet/in_systm.h>
80: #include <netinet/in_var.h>
81: #include <netinet/ip.h>
82: #include <netinet/if_inarp.h>
83: #endif
84:
85: #ifdef IPX
86: #include <netipx/ipx.h>
87: #include <netipx/ipx_if.h>
88: #endif
89:
90: #ifdef NS
91: #include <netns/ns.h>
92: #include <netns/ns_if.h>
93: #endif
94:
95: #if NBPFILTER > 0
96: #include <net/bpf.h>
97: #include <net/bpfdesc.h>
98: #endif
99:
100: /*
101: * Maximum number of bytes to read per interrupt. Linux recommends
102: * somewhere between 2000-22000.
103: * XXX This is currently a hard maximum.
104: */
105: #define MAX_BYTES_INTR 12000
106:
107: #include <dev/mii/mii.h>
108: #include <dev/mii/miivar.h>
109:
110: #include <dev/pcmcia/pcmciareg.h>
111: #include <dev/pcmcia/pcmciavar.h>
112: #include <dev/pcmcia/pcmciadevs.h>
113:
114: #include <dev/pcmcia/if_xireg.h>
115:
116: #ifdef __GNUC__
117: #define INLINE __inline
118: #else
119: #define INLINE
120: #endif /* __GNUC__ */
121:
1.35 mycroft 122: /*#define XIDEBUG*/
123: /*#define XIDEBUG_VALUE XID_CONFIG*/
124:
1.1 gmcgarry 125: #ifdef XIDEBUG
126: #define DPRINTF(cat, x) if (xidebug & (cat)) printf x
127:
128: #define XID_CONFIG 0x1
129: #define XID_MII 0x2
130: #define XID_INTR 0x4
131: #define XID_FIFO 0x8
132:
133: #ifdef XIDEBUG_VALUE
134: int xidebug = XIDEBUG_VALUE;
135: #else
136: int xidebug = 0;
137: #endif
138: #else
139: #define DPRINTF(cat, x) (void)0
140: #endif
141:
142: int xi_pcmcia_match __P((struct device *, struct cfdata *, void *));
143: void xi_pcmcia_attach __P((struct device *, struct device *, void *));
144: int xi_pcmcia_detach __P((struct device *, int));
145: int xi_pcmcia_activate __P((struct device *, enum devact));
146:
147: /*
148: * In case this chipset ever turns up out of pcmcia attachments (very
149: * unlikely) do the driver splitup.
150: */
151: struct xi_softc {
152: struct device sc_dev; /* Generic device info */
153: struct ethercom sc_ethercom; /* Ethernet common part */
154:
155: struct mii_data sc_mii; /* MII media information */
156:
157: bus_space_tag_t sc_bst; /* Bus cookie */
158: bus_space_handle_t sc_bsh; /* Bus I/O handle */
1.19 soren 159: bus_size_t sc_offset; /* Offset of registers */
1.1 gmcgarry 160:
161: u_int8_t sc_rev; /* Chip revision */
162: u_int32_t sc_flags; /* Misc. flags */
163: int sc_all_mcasts; /* Receive all multicasts */
164: u_int8_t sc_enaddr[ETHER_ADDR_LEN];
1.11 gmcgarry 165: #if NRND > 0
166: rndsource_element_t sc_rnd_source;
167: #endif
1.1 gmcgarry 168: };
169:
170: struct xi_pcmcia_softc {
1.2 gmcgarry 171: struct xi_softc sc_xi; /* Generic device info */
1.1 gmcgarry 172:
173: /* PCMCIA-specific goo */
174: struct pcmcia_function *sc_pf; /* PCMCIA function */
175: struct pcmcia_io_handle sc_pcioh; /* iospace info */
176: int sc_io_window; /* io window info */
177: void *sc_ih; /* Interrupt handler */
1.11 gmcgarry 178: void *sc_powerhook; /* power hook descriptor */
1.1 gmcgarry 179: int sc_resource; /* resource allocated */
180: #define XI_RES_PCIC 1
1.11 gmcgarry 181: #define XI_RES_IO_ALLOC 2
182: #define XI_RES_IO_MAP 4
1.1 gmcgarry 183: #define XI_RES_MI 8
1.35 mycroft 184: #define XI_RES_RND 16
1.1 gmcgarry 185: };
186:
1.25 thorpej 187: CFATTACH_DECL(xi_pcmcia, sizeof(struct xi_pcmcia_softc),
1.26 thorpej 188: xi_pcmcia_match, xi_pcmcia_attach, xi_pcmcia_detach, xi_pcmcia_activate);
1.1 gmcgarry 189:
190: static int xi_pcmcia_cis_quirks __P((struct pcmcia_function *));
191: static void xi_cycle_power __P((struct xi_softc *));
192: static int xi_ether_ioctl __P((struct ifnet *, u_long cmd, caddr_t));
193: static void xi_full_reset __P((struct xi_softc *));
194: static void xi_init __P((struct xi_softc *));
195: static int xi_intr __P((void *));
196: static int xi_ioctl __P((struct ifnet *, u_long, caddr_t));
197: static int xi_mdi_read __P((struct device *, int, int));
198: static void xi_mdi_write __P((struct device *, int, int, int));
199: static int xi_mediachange __P((struct ifnet *));
200: static void xi_mediastatus __P((struct ifnet *, struct ifmediareq *));
201: static int xi_pcmcia_funce_enaddr __P((struct device *, u_int8_t *));
202: static int xi_pcmcia_lan_nid_ciscallback __P((struct pcmcia_tuple *, void *));
1.3 gmcgarry 203: static int xi_pcmcia_manfid_ciscallback __P((struct pcmcia_tuple *, void *));
1.1 gmcgarry 204: static u_int16_t xi_get __P((struct xi_softc *));
205: static void xi_reset __P((struct xi_softc *));
206: static void xi_set_address __P((struct xi_softc *));
207: static void xi_start __P((struct ifnet *));
208: static void xi_statchg __P((struct device *));
209: static void xi_stop __P((struct xi_softc *));
210: static void xi_watchdog __P((struct ifnet *));
1.9 jdolecek 211: const struct xi_pcmcia_product *xi_pcmcia_identify __P((struct device *,
1.3 gmcgarry 212: struct pcmcia_attach_args *));
1.11 gmcgarry 213: static int xi_pcmcia_enable __P((struct xi_pcmcia_softc *));
214: static void xi_pcmcia_disable __P((struct xi_pcmcia_softc *));
215: static void xi_pcmcia_power __P((int, void *));
1.1 gmcgarry 216:
217: /* flags */
1.3 gmcgarry 218: #define XIFLAGS_MOHAWK 0x001 /* 100Mb capabilities (has phy) */
219: #define XIFLAGS_DINGO 0x002 /* realport cards ??? */
220: #define XIFLAGS_MODEM 0x004 /* modem also present */
1.1 gmcgarry 221:
1.9 jdolecek 222: const struct xi_pcmcia_product {
1.1 gmcgarry 223: u_int32_t xpp_vendor; /* vendor ID */
224: u_int32_t xpp_product; /* product ID */
225: int xpp_expfunc; /* expected function number */
226: int xpp_flags; /* initial softc flags */
227: } xi_pcmcia_products[] = {
228: #ifdef NOT_SUPPORTED
1.3 gmcgarry 229: { PCMCIA_VENDOR_XIRCOM, 0x0141,
1.34 mycroft 230: 0, 0 },
1.1 gmcgarry 231: #endif
1.3 gmcgarry 232: { PCMCIA_VENDOR_XIRCOM, 0x0141,
1.34 mycroft 233: 0, 0 },
1.3 gmcgarry 234: { PCMCIA_VENDOR_XIRCOM, 0x0142,
1.34 mycroft 235: 0, 0 },
1.3 gmcgarry 236: { PCMCIA_VENDOR_XIRCOM, 0x0143,
1.34 mycroft 237: 0, XIFLAGS_MOHAWK },
1.3 gmcgarry 238: { PCMCIA_VENDOR_COMPAQ2, 0x0143,
1.34 mycroft 239: 0, XIFLAGS_MOHAWK },
1.3 gmcgarry 240: { PCMCIA_VENDOR_INTEL, 0x0143,
1.34 mycroft 241: 0, XIFLAGS_MOHAWK | XIFLAGS_MODEM },
1.17 christos 242: { PCMCIA_VENDOR_XIRCOM, PCMCIA_PRODUCT_XIRCOM_XE2000,
1.34 mycroft 243: 0, XIFLAGS_MOHAWK },
1.17 christos 244: { PCMCIA_VENDOR_XIRCOM, PCMCIA_PRODUCT_XIRCOM_REM56,
1.34 mycroft 245: 0, XIFLAGS_MOHAWK | XIFLAGS_DINGO | XIFLAGS_MODEM },
1.3 gmcgarry 246: #ifdef NOT_SUPPORTED
247: { PCMCIA_VENDOR_XIRCOM, 0x1141,
1.34 mycroft 248: 0, XIFLAGS_MODEM },
1.3 gmcgarry 249: #endif
250: { PCMCIA_VENDOR_XIRCOM, 0x1142,
1.34 mycroft 251: 0, XIFLAGS_MODEM },
1.3 gmcgarry 252: { PCMCIA_VENDOR_XIRCOM, 0x1143,
1.34 mycroft 253: 0, XIFLAGS_MODEM },
1.3 gmcgarry 254: { PCMCIA_VENDOR_XIRCOM, 0x1144,
1.34 mycroft 255: 0, XIFLAGS_MODEM },
1.3 gmcgarry 256: { PCMCIA_VENDOR_XIRCOM, 0x1145,
1.34 mycroft 257: 0, XIFLAGS_MOHAWK | XIFLAGS_MODEM },
1.3 gmcgarry 258: { PCMCIA_VENDOR_XIRCOM, 0x1146,
1.34 mycroft 259: 0, XIFLAGS_MOHAWK | XIFLAGS_DINGO | XIFLAGS_MODEM },
1.3 gmcgarry 260: { PCMCIA_VENDOR_XIRCOM, 0x1147,
1.34 mycroft 261: 0, XIFLAGS_MOHAWK | XIFLAGS_DINGO | XIFLAGS_MODEM },
1.1 gmcgarry 262: };
263:
264:
1.9 jdolecek 265: const struct xi_pcmcia_product *
1.3 gmcgarry 266: xi_pcmcia_identify(dev, pa)
267: struct device *dev;
1.1 gmcgarry 268: struct pcmcia_attach_args *pa;
269: {
1.9 jdolecek 270: const struct xi_pcmcia_product *xpp;
1.3 gmcgarry 271: u_int8_t id;
272: u_int32_t prod;
1.34 mycroft 273: int n;
1.3 gmcgarry 274:
275: /*
276: * The Xircom ethernet cards swap the revision and product fields
277: * inside the CIS, which makes identification just a little
278: * bit different.
279: */
280: pcmcia_scan_cis(dev, xi_pcmcia_manfid_ciscallback, &id);
281:
282: prod = (pa->product & ~0xff) | id;
283:
1.4 gmcgarry 284: DPRINTF(XID_CONFIG, ("product=0x%x\n", prod));
1.1 gmcgarry 285:
1.34 mycroft 286: for (xpp = xi_pcmcia_products,
287: n = sizeof(xi_pcmcia_products) / sizeof(xi_pcmcia_products[0]);
288: n; xpp++, n--) {
1.1 gmcgarry 289: if (pa->manufacturer == xpp->xpp_vendor &&
1.34 mycroft 290: prod == xpp->xpp_product &&
291: pa->pf->number == xpp->xpp_expfunc)
1.1 gmcgarry 292: return (xpp);
1.34 mycroft 293: }
1.1 gmcgarry 294: return (NULL);
295: }
296:
297: /*
1.11 gmcgarry 298: * The quirks are done here instead of the traditional framework because
299: * of the difficulty in identifying the devices.
1.1 gmcgarry 300: */
301: static int
302: xi_pcmcia_cis_quirks(pf)
303: struct pcmcia_function *pf;
304: {
305: struct pcmcia_config_entry *cfe;
306:
307: /* Tell the pcmcia framework where the CCR is. */
308: pf->ccr_base = 0x800;
309: pf->ccr_mask = 0x67;
310:
311: /* Fake a cfe. */
312: SIMPLEQ_FIRST(&pf->cfe_head) = cfe = (struct pcmcia_config_entry *)
1.20 tsutsui 313: malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT|M_ZERO);
1.1 gmcgarry 314:
315: if (cfe == NULL)
316: return -1;
317:
318: /*
319: * XXX Use preprocessor symbols instead.
320: * Enable ethernet & its interrupts, wiring them to -INT
321: * No I/O base.
322: */
323: cfe->number = 0x5;
324: cfe->flags = 0; /* XXX Check! */
325: cfe->iftype = PCMCIA_IFTYPE_IO;
326: cfe->num_iospace = 0;
327: cfe->num_memspace = 0;
328: cfe->irqmask = 0x8eb0;
329:
330: return 0;
331: }
332:
333: int
334: xi_pcmcia_match(parent, match, aux)
335: struct device *parent;
336: struct cfdata *match;
337: void *aux;
338: {
339: struct pcmcia_attach_args *pa = aux;
340:
1.3 gmcgarry 341: if (pa->manufacturer == PCMCIA_VENDOR_COMPAQ2 &&
342: pa->product == PCMCIA_PRODUCT_COMPAQ2_CPQ_10_100)
343: return (1);
344:
345: if (pa->manufacturer == PCMCIA_VENDOR_INTEL &&
1.35 mycroft 346: pa->product == PCMCIA_PRODUCT_INTEL_EEPRO100)
1.3 gmcgarry 347: return (1);
348:
1.35 mycroft 349: if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM) {
350: if (pa->product == 0x110a)
351: return (2); /* prevent attach to com_pcmcia */
352: if ((pa->product & (XIMEDIA_ETHER << 8)) != 0)
353: return (1);
354: }
1.3 gmcgarry 355:
1.1 gmcgarry 356: return (0);
357: }
358:
359: void
360: xi_pcmcia_attach(parent, self, aux)
361: struct device *parent, *self;
362: void *aux;
363: {
364: struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)self;
1.2 gmcgarry 365: struct xi_softc *sc = &psc->sc_xi;
1.1 gmcgarry 366: struct pcmcia_attach_args *pa = aux;
367: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.9 jdolecek 368: const struct xi_pcmcia_product *xpp;
1.1 gmcgarry 369:
1.34 mycroft 370: aprint_normal("\n");
371:
1.1 gmcgarry 372: if (xi_pcmcia_cis_quirks(pa->pf) < 0) {
1.34 mycroft 373: aprint_error("%s: function enable failed\n", self->dv_xname);
1.1 gmcgarry 374: return;
375: }
376:
377: /* Enable the card */
378: psc->sc_pf = pa->pf;
1.22 lukem 379: pcmcia_function_init(psc->sc_pf, SIMPLEQ_FIRST(&psc->sc_pf->cfe_head));
1.1 gmcgarry 380: if (pcmcia_function_enable(psc->sc_pf)) {
1.34 mycroft 381: aprint_error("%s: function enable failed\n", self->dv_xname);
1.1 gmcgarry 382: goto fail;
383: }
384: psc->sc_resource |= XI_RES_PCIC;
385:
1.36 ! mycroft 386: delay(10000);
! 387: xpp = xi_pcmcia_identify(parent, pa);
! 388: if (xpp == NULL) {
! 389: aprint_error("%s: unrecognised model\n", self->dv_xname);
! 390: goto fail;
! 391: }
! 392: sc->sc_flags = xpp->xpp_flags;
! 393:
1.1 gmcgarry 394: /* allocate/map ISA I/O space */
1.11 gmcgarry 395: if (pcmcia_io_alloc(psc->sc_pf, 0, XI_IOSIZE, XI_IOSIZE,
1.1 gmcgarry 396: &psc->sc_pcioh) != 0) {
1.34 mycroft 397: aprint_error("%s: I/O allocation failed\n", self->dv_xname);
1.1 gmcgarry 398: goto fail;
399: }
1.11 gmcgarry 400: psc->sc_resource |= XI_RES_IO_ALLOC;
401:
1.1 gmcgarry 402: sc->sc_bst = psc->sc_pcioh.iot;
403: sc->sc_bsh = psc->sc_pcioh.ioh;
404: sc->sc_offset = 0;
405:
1.11 gmcgarry 406: if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_AUTO, 0, XI_IOSIZE,
407: &psc->sc_pcioh, &psc->sc_io_window)) {
1.34 mycroft 408: aprint_error("%s: can't map I/O space\n", self->dv_xname);
1.11 gmcgarry 409: goto fail;
1.3 gmcgarry 410: }
1.11 gmcgarry 411: psc->sc_resource |= XI_RES_IO_MAP;
1.1 gmcgarry 412:
413: /*
1.11 gmcgarry 414: * Configuration as advised by DINGO documentation.
1.1 gmcgarry 415: * Dingo has some extra configuration registers in the CCR space.
416: */
1.3 gmcgarry 417: if (sc->sc_flags & XIFLAGS_DINGO) {
1.1 gmcgarry 418: struct pcmcia_mem_handle pcmh;
419: int ccr_window;
1.30 martin 420: bus_size_t ccr_offset;
1.1 gmcgarry 421:
1.11 gmcgarry 422: /* get access to the DINGO CCR space */
1.1 gmcgarry 423: if (pcmcia_mem_alloc(psc->sc_pf, PCMCIA_CCR_SIZE_DINGO,
424: &pcmh)) {
1.2 gmcgarry 425: DPRINTF(XID_CONFIG, ("xi: bad mem alloc\n"));
1.1 gmcgarry 426: goto fail;
427: }
428: if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR,
429: psc->sc_pf->ccr_base, PCMCIA_CCR_SIZE_DINGO,
430: &pcmh, &ccr_offset, &ccr_window)) {
1.2 gmcgarry 431: DPRINTF(XID_CONFIG, ("xi: bad mem map\n"));
1.1 gmcgarry 432: pcmcia_mem_free(psc->sc_pf, &pcmh);
433: goto fail;
434: }
435:
1.11 gmcgarry 436: /* enable the second function - usually modem */
1.1 gmcgarry 437: bus_space_write_1(pcmh.memt, pcmh.memh,
438: ccr_offset + PCMCIA_CCR_DCOR0, PCMCIA_CCR_DCOR0_SFINT);
439: bus_space_write_1(pcmh.memt, pcmh.memh,
440: ccr_offset + PCMCIA_CCR_DCOR1,
441: PCMCIA_CCR_DCOR1_FORCE_LEVIREQ | PCMCIA_CCR_DCOR1_D6);
442: bus_space_write_1(pcmh.memt, pcmh.memh,
443: ccr_offset + PCMCIA_CCR_DCOR2, 0);
444: bus_space_write_1(pcmh.memt, pcmh.memh,
445: ccr_offset + PCMCIA_CCR_DCOR3, 0);
446: bus_space_write_1(pcmh.memt, pcmh.memh,
447: ccr_offset + PCMCIA_CCR_DCOR4, 0);
448:
449: /* We don't need them anymore and can free them (I think). */
450: pcmcia_mem_unmap(psc->sc_pf, ccr_window);
451: pcmcia_mem_free(psc->sc_pf, &pcmh);
452: }
1.11 gmcgarry 453:
1.1 gmcgarry 454: /*
1.11 gmcgarry 455: * Get the ethernet address from FUNCE/LAN_NID tuple.
1.1 gmcgarry 456: */
457: xi_pcmcia_funce_enaddr(parent, sc->sc_enaddr);
458: if (!sc->sc_enaddr) {
1.34 mycroft 459: aprint_error("%s: unable to get ethernet address\n",
460: self->dv_xname);
1.1 gmcgarry 461: goto fail;
462: }
463:
1.34 mycroft 464: printf("%s: Ethernet address %s\n", self->dv_xname,
1.1 gmcgarry 465: ether_sprintf(sc->sc_enaddr));
466:
467: ifp = &sc->sc_ethercom.ec_if;
1.34 mycroft 468: memcpy(ifp->if_xname, self->dv_xname, IFNAMSIZ);
1.1 gmcgarry 469: ifp->if_softc = sc;
470: ifp->if_start = xi_start;
471: ifp->if_ioctl = xi_ioctl;
472: ifp->if_watchdog = xi_watchdog;
473: ifp->if_flags =
474: IFF_BROADCAST | IFF_NOTRAILERS | IFF_SIMPLEX | IFF_MULTICAST;
1.7 thorpej 475: IFQ_SET_READY(&ifp->if_snd);
1.1 gmcgarry 476:
477: /* Reset and initialize the card. */
478: xi_full_reset(sc);
479:
480: /*
481: * Initialize our media structures and probe the MII.
482: */
483: sc->sc_mii.mii_ifp = ifp;
484: sc->sc_mii.mii_readreg = xi_mdi_read;
485: sc->sc_mii.mii_writereg = xi_mdi_write;
486: sc->sc_mii.mii_statchg = xi_statchg;
487: ifmedia_init(&sc->sc_mii.mii_media, 0, xi_mediachange,
488: xi_mediastatus);
489: DPRINTF(XID_MII | XID_CONFIG,
1.2 gmcgarry 490: ("xi: bmsr %x\n", xi_mdi_read(&sc->sc_dev, 0, 1)));
1.1 gmcgarry 491: mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
492: MII_OFFSET_ANY, 0);
493: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL)
494: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO, 0,
495: NULL);
496: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
497:
1.11 gmcgarry 498: /* 802.1q capability */
499: sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
500: /* Attach the interface. */
1.1 gmcgarry 501: if_attach(ifp);
502: ether_ifattach(ifp, sc->sc_enaddr);
503: psc->sc_resource |= XI_RES_MI;
504:
1.11 gmcgarry 505: #if NRND > 0
1.34 mycroft 506: rnd_attach_source(&sc->sc_rnd_source, self->dv_xname,
1.11 gmcgarry 507: RND_TYPE_NET, 0);
1.35 mycroft 508: psc->sc_resource |= XI_RES_RND;
1.11 gmcgarry 509: #endif
510:
1.1 gmcgarry 511: /*
512: * Reset and initialize the card again for DINGO (as found in Linux
513: * driver). Without this Dingo will get a watchdog timeout the first
514: * time. The ugly media tickling seems to be necessary for getting
515: * autonegotiation to work too.
516: */
1.3 gmcgarry 517: if (sc->sc_flags & XIFLAGS_DINGO) {
1.1 gmcgarry 518: xi_full_reset(sc);
519: xi_init(sc);
520: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
521: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
522: xi_stop(sc);
523: }
524:
1.11 gmcgarry 525: psc->sc_powerhook = powerhook_establish(xi_pcmcia_power, sc);
526:
527: pcmcia_function_disable(psc->sc_pf);
528: psc->sc_resource &= ~XI_RES_PCIC;
1.1 gmcgarry 529:
530: return;
531:
532: fail:
1.11 gmcgarry 533: if ((psc->sc_resource & XI_RES_IO_MAP) != 0) {
1.1 gmcgarry 534: pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
1.11 gmcgarry 535: psc->sc_resource &= ~XI_RES_IO_MAP;
536: }
537: if ((psc->sc_resource & XI_RES_IO_ALLOC) != 0) {
538: pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
539: psc->sc_resource &= ~XI_RES_IO_ALLOC;
1.1 gmcgarry 540: }
541: if (psc->sc_resource & XI_RES_PCIC) {
542: pcmcia_function_disable(pa->pf);
543: psc->sc_resource &= ~XI_RES_PCIC;
544: }
545: }
546:
547: int
548: xi_pcmcia_detach(self, flags)
549: struct device *self;
550: int flags;
551: {
552: struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)self;
1.2 gmcgarry 553: struct xi_softc *sc = &psc->sc_xi;
1.1 gmcgarry 554: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
555:
556: DPRINTF(XID_CONFIG, ("xi_pcmcia_detach()\n"));
557:
1.11 gmcgarry 558: if (psc->sc_powerhook != NULL)
559: powerhook_disestablish(psc->sc_powerhook);
1.1 gmcgarry 560:
1.11 gmcgarry 561: #if NRND > 0
1.35 mycroft 562: if ((psc->sc_resource & XI_RES_RND) != 0)
563: rnd_detach_source(&sc->sc_rnd_source);
1.11 gmcgarry 564: #endif
1.1 gmcgarry 565:
566: if ((psc->sc_resource & XI_RES_MI) != 0) {
567: mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
568: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
569: ether_ifdetach(ifp);
570: if_detach(ifp);
571: psc->sc_resource &= ~XI_RES_MI;
572: }
1.11 gmcgarry 573: if (psc->sc_resource & XI_RES_IO_MAP) {
1.1 gmcgarry 574: pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
1.11 gmcgarry 575: psc->sc_resource &= ~XI_RES_IO_MAP;
576: }
577: if ((psc->sc_resource & XI_RES_IO_ALLOC) != 0) {
1.1 gmcgarry 578: pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
1.11 gmcgarry 579: psc->sc_resource &= ~XI_RES_IO_ALLOC;
1.1 gmcgarry 580: }
1.11 gmcgarry 581:
582: xi_pcmcia_disable(psc);
583:
1.1 gmcgarry 584: free(SIMPLEQ_FIRST(&psc->sc_pf->cfe_head), M_DEVBUF);
585:
586: return 0;
587: }
588:
589: int
590: xi_pcmcia_activate(self, act)
591: struct device *self;
592: enum devact act;
593: {
594: struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)self;
1.2 gmcgarry 595: struct xi_softc *sc = &psc->sc_xi;
1.1 gmcgarry 596: int s, rv=0;
597:
598: DPRINTF(XID_CONFIG, ("xi_pcmcia_activate()\n"));
599:
600: s = splnet();
601: switch (act) {
602: case DVACT_ACTIVATE:
603: rv = EOPNOTSUPP;
604: break;
605:
606: case DVACT_DEACTIVATE:
607: if_deactivate(&sc->sc_ethercom.ec_if);
608: break;
609: }
610: splx(s);
611: return (rv);
612: }
613:
1.11 gmcgarry 614: static int
615: xi_pcmcia_enable(psc)
616: struct xi_pcmcia_softc *psc;
617: {
618: struct xi_softc *sc = &psc->sc_xi;
619:
620: DPRINTF(XID_CONFIG,("xi_pcmcia_enable()\n"));
621:
1.16 bouyer 622: if (pcmcia_function_enable(psc->sc_pf))
623: return (1);
624: psc->sc_resource |= XI_RES_PCIC;
625:
1.11 gmcgarry 626: /* establish the interrupt. */
627: psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, xi_intr, sc);
628: if (psc->sc_ih == NULL) {
629: printf("%s: couldn't establish interrupt\n",
630: sc->sc_dev.dv_xname);
1.16 bouyer 631: pcmcia_function_disable(psc->sc_pf);
632: psc->sc_resource &= ~XI_RES_PCIC;
1.11 gmcgarry 633: return (1);
634: }
635:
636: xi_full_reset(sc);
637:
638: return (0);
639: }
640:
641:
642: static void
643: xi_pcmcia_disable(psc)
644: struct xi_pcmcia_softc *psc;
645: {
646: DPRINTF(XID_CONFIG,("xi_pcmcia_disable()\n"));
647:
648: if (psc->sc_resource & XI_RES_PCIC) {
1.16 bouyer 649: pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
1.11 gmcgarry 650: pcmcia_function_disable(psc->sc_pf);
651: psc->sc_resource &= ~XI_RES_PCIC;
652: }
653: }
654:
655:
656: static void
657: xi_pcmcia_power(why, arg)
658: int why;
659: void *arg;
660: {
661: struct xi_pcmcia_softc *psc = arg;
662: struct xi_softc *sc = &psc->sc_xi;
663: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
664: int s;
665:
666: DPRINTF(XID_CONFIG,("xi_pcmcia_power()\n"));
667:
668: s = splnet();
669:
670: switch (why) {
671: case PWR_SUSPEND:
672: case PWR_STANDBY:
673: if (ifp->if_flags & IFF_RUNNING) {
674: xi_stop(sc);
675: }
676: ifp->if_flags &= ~IFF_RUNNING;
677: ifp->if_timer = 0;
678: break;
679: case PWR_RESUME:
680: if ((ifp->if_flags & IFF_RUNNING) == 0) {
681: xi_init(sc);
682: }
683: ifp->if_flags |= IFF_RUNNING;
684: break;
685: case PWR_SOFTSUSPEND:
686: case PWR_SOFTSTANDBY:
687: case PWR_SOFTRESUME:
688: break;
689: }
690: splx(s);
691: }
692:
1.1 gmcgarry 693: /*
694: * XXX These two functions might be OK to factor out into pcmcia.c since
695: * if_sm_pcmcia.c uses similar ones.
696: */
697: static int
698: xi_pcmcia_funce_enaddr(parent, myla)
699: struct device *parent;
700: u_int8_t *myla;
701: {
702: /* XXX The Linux driver has more ways to do this in case of failure. */
703: return (pcmcia_scan_cis(parent, xi_pcmcia_lan_nid_ciscallback, myla));
704: }
705:
706: static int
707: xi_pcmcia_lan_nid_ciscallback(tuple, arg)
708: struct pcmcia_tuple *tuple;
709: void *arg;
710: {
711: u_int8_t *myla = arg;
712: int i;
713:
1.2 gmcgarry 714: DPRINTF(XID_CONFIG, ("xi_pcmcia_lan_nid_ciscallback()\n"));
1.1 gmcgarry 715:
1.36 ! mycroft 716: if (tuple->length < 2)
! 717: return (0);
1.1 gmcgarry 718:
1.36 ! mycroft 719: switch (tuple->code) {
! 720: case PCMCIA_CISTPL_FUNCE:
1.1 gmcgarry 721: switch (pcmcia_tuple_read_1(tuple, 0)) {
722: case PCMCIA_TPLFE_TYPE_LAN_NID:
723: if (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)
724: return (0);
725: break;
726:
727: case 0x02:
728: /*
729: * Not sure about this, I don't have a CE2
730: * that puts the ethernet addr here.
731: */
732: if (pcmcia_tuple_read_1(tuple, 1) != 13)
733: return (0);
734: break;
735:
736: default:
737: return (0);
738: }
739:
1.36 ! mycroft 740: case 0x89:
! 741: if (pcmcia_tuple_read_1(tuple, 0) != 0x04 ||
! 742: pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)
! 743: return (0);
! 744: break;
1.1 gmcgarry 745: }
746:
1.36 ! mycroft 747: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 748: myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
! 749: return (1);
1.1 gmcgarry 750: }
751:
1.3 gmcgarry 752: int
753: xi_pcmcia_manfid_ciscallback(tuple, arg)
754: struct pcmcia_tuple *tuple;
755: void *arg;
756: {
757: u_int8_t *id = arg;
758:
759: DPRINTF(XID_CONFIG, ("xi_pcmcia_manfid_callback()\n"));
760:
761: if (tuple->code != PCMCIA_CISTPL_MANFID)
762: return (0);
763:
764: if (tuple->length < 2)
765: return (0);
766:
767: *id = pcmcia_tuple_read_1(tuple, 4);
768: return (1);
769: }
770:
1.1 gmcgarry 771: static int
772: xi_intr(arg)
773: void *arg;
774: {
775: struct xi_softc *sc = arg;
776: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
777: u_int8_t esr, rsr, isr, rx_status, savedpage;
1.33 mycroft 778: u_int16_t tx_status, recvcount = 0, tempint;
1.1 gmcgarry 779:
1.2 gmcgarry 780: DPRINTF(XID_CONFIG, ("xi_intr()\n"));
1.1 gmcgarry 781:
782: #if 0
783: if (!(ifp->if_flags & IFF_RUNNING))
784: return (0);
785: #endif
786:
787: ifp->if_timer = 0; /* turn watchdog timer off */
788:
1.3 gmcgarry 789: if (sc->sc_flags & XIFLAGS_MOHAWK) {
1.1 gmcgarry 790: /* Disable interrupt (Linux does it). */
791: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
792: 0);
793: }
794:
795: savedpage =
796: bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + PR);
797:
798: PAGE(sc, 0);
799: esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ESR);
800: isr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ISR0);
801: rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
802:
803: /* Check to see if card has been ejected. */
804: if (isr == 0xff) {
805: #ifdef DIAGNOSTIC
806: printf("%s: interrupt for dead card\n", sc->sc_dev.dv_xname);
807: #endif
808: goto end;
809: }
810:
811: PAGE(sc, 40);
812: rx_status =
813: bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RXST0);
1.23 martin 814: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RXST0,
815: ~rx_status & 0xff);
1.1 gmcgarry 816: tx_status =
1.11 gmcgarry 817: bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST0);
1.23 martin 818: tx_status |=
819: bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST1) << 8;
820: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST0,0);
821: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST1,0);
1.1 gmcgarry 822:
823: PAGE(sc, 0);
824: while (esr & FULL_PKT_RCV) {
825: if (!(rsr & RSR_RX_OK))
826: break;
827:
828: /* Compare bytes read this interrupt to hard maximum. */
829: if (recvcount > MAX_BYTES_INTR) {
830: DPRINTF(XID_INTR,
1.2 gmcgarry 831: ("xi: too many bytes this interrupt\n"));
1.1 gmcgarry 832: ifp->if_iqdrops++;
833: /* Drop packet. */
834: bus_space_write_2(sc->sc_bst, sc->sc_bsh,
835: sc->sc_offset + DO0, DO_SKIP_RX_PKT);
836: }
837: tempint = xi_get(sc); /* XXX doesn't check the error! */
838: recvcount += tempint;
839: ifp->if_ibytes += tempint;
840: esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
841: sc->sc_offset + ESR);
842: rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
843: sc->sc_offset + RSR);
844: }
845:
846: /* Packet too long? */
847: if (rsr & RSR_TOO_LONG) {
848: ifp->if_ierrors++;
1.2 gmcgarry 849: DPRINTF(XID_INTR, ("xi: packet too long\n"));
1.1 gmcgarry 850: }
851:
852: /* CRC error? */
853: if (rsr & RSR_CRCERR) {
854: ifp->if_ierrors++;
1.2 gmcgarry 855: DPRINTF(XID_INTR, ("xi: CRC error detected\n"));
1.1 gmcgarry 856: }
857:
858: /* Alignment error? */
859: if (rsr & RSR_ALIGNERR) {
860: ifp->if_ierrors++;
1.2 gmcgarry 861: DPRINTF(XID_INTR, ("xi: alignment error detected\n"));
1.1 gmcgarry 862: }
863:
864: /* Check for rx overrun. */
865: if (rx_status & RX_OVERRUN) {
1.23 martin 866: ifp->if_ierrors++;
1.1 gmcgarry 867: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
868: CLR_RX_OVERRUN);
1.2 gmcgarry 869: DPRINTF(XID_INTR, ("xi: overrun cleared\n"));
1.1 gmcgarry 870: }
871:
872: /* Try to start more packets transmitting. */
1.7 thorpej 873: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1.1 gmcgarry 874: xi_start(ifp);
875:
876: /* Detected excessive collisions? */
877: if ((tx_status & EXCESSIVE_COLL) && ifp->if_opackets > 0) {
1.2 gmcgarry 878: DPRINTF(XID_INTR, ("xi: excessive collisions\n"));
1.1 gmcgarry 879: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
880: RESTART_TX);
881: ifp->if_oerrors++;
882: }
883:
884: if ((tx_status & TX_ABORT) && ifp->if_opackets > 0)
885: ifp->if_oerrors++;
886:
1.33 mycroft 887: /* have handled the interrupt */
888: #if NRND > 0
889: rnd_add_uint32(&sc->sc_rnd_source, tx_status);
890: #endif
891:
1.1 gmcgarry 892: end:
893: /* Reenable interrupts. */
894: PAGE(sc, savedpage);
895: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
896: ENABLE_INT);
1.11 gmcgarry 897:
1.1 gmcgarry 898: return (1);
899: }
900:
901: /*
902: * Pull a packet from the card into an mbuf chain.
903: */
904: static u_int16_t
905: xi_get(sc)
906: struct xi_softc *sc;
907: {
908: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
909: struct mbuf *top, **mp, *m;
910: u_int16_t pktlen, len, recvcount = 0;
911: u_int8_t *data;
912: u_int8_t rsr;
913:
1.2 gmcgarry 914: DPRINTF(XID_CONFIG, ("xi_get()\n"));
1.1 gmcgarry 915:
916: PAGE(sc, 0);
917: rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
918:
919: pktlen =
920: bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RBC0) &
921: RBC_COUNT_MASK;
922:
923: DPRINTF(XID_CONFIG, ("xi_get: pktlen=%d\n", pktlen));
924:
925: if (pktlen == 0) {
926: /*
927: * XXX At least one CE2 sets RBC0 == 0 occasionally, and only
928: * when MPE is set. It is not known why.
929: */
930: return (0);
931: }
932:
933: /* XXX should this be incremented now ? */
934: recvcount += pktlen;
935:
936: MGETHDR(m, M_DONTWAIT, MT_DATA);
937: if (m == 0)
938: return (recvcount);
939: m->m_pkthdr.rcvif = ifp;
940: m->m_pkthdr.len = pktlen;
1.10 gmcgarry 941: m->m_flags |= M_HASFCS;
1.1 gmcgarry 942: len = MHLEN;
943: top = 0;
944: mp = ⊤
945:
946: while (pktlen > 0) {
947: if (top) {
948: MGET(m, M_DONTWAIT, MT_DATA);
949: if (m == 0) {
950: m_freem(top);
951: return (recvcount);
952: }
953: len = MLEN;
954: }
955: if (pktlen >= MINCLSIZE) {
956: MCLGET(m, M_DONTWAIT);
957: if (!(m->m_flags & M_EXT)) {
958: m_freem(m);
959: m_freem(top);
960: return (recvcount);
961: }
962: len = MCLBYTES;
963: }
964: if (!top) {
965: caddr_t newdata = (caddr_t)ALIGN(m->m_data +
966: sizeof(struct ether_header)) -
967: sizeof(struct ether_header);
968: len -= newdata - m->m_data;
969: m->m_data = newdata;
970: }
971: len = min(pktlen, len);
972: data = mtod(m, u_int8_t *);
973: if (len > 1) {
974: len &= ~1;
975: bus_space_read_multi_2(sc->sc_bst, sc->sc_bsh,
1.21 takemura 976: sc->sc_offset + EDP, (u_int16_t *)data, len>>1);
1.1 gmcgarry 977: } else
978: *data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
979: sc->sc_offset + EDP);
980: m->m_len = len;
981: pktlen -= len;
982: *mp = m;
983: mp = &m->m_next;
984: }
985:
986: /* Skip Rx packet. */
987: bus_space_write_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + DO0,
988: DO_SKIP_RX_PKT);
989:
990: ifp->if_ipackets++;
991:
992: #if NBPFILTER > 0
993: if (ifp->if_bpf)
994: bpf_mtap(ifp->if_bpf, top);
995: #endif
996:
997: (*ifp->if_input)(ifp, top);
998: return (recvcount);
999: }
1000:
1001: /*
1002: * Serial management for the MII.
1003: * The DELAY's below stem from the fact that the maximum frequency
1004: * acceptable on the MDC pin is 2.5 MHz and fast processors can easily
1005: * go much faster than that.
1006: */
1007:
1008: /* Let the MII serial management be idle for one period. */
1009: static INLINE void xi_mdi_idle __P((struct xi_softc *));
1010: static INLINE void
1011: xi_mdi_idle(sc)
1012: struct xi_softc *sc;
1013: {
1014: bus_space_tag_t bst = sc->sc_bst;
1015: bus_space_handle_t bsh = sc->sc_bsh;
1.30 martin 1016: bus_size_t offset = sc->sc_offset;
1.1 gmcgarry 1017:
1018: /* Drive MDC low... */
1019: bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
1020: DELAY(1);
1021:
1022: /* and high again. */
1023: bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
1024: DELAY(1);
1025: }
1026:
1027: /* Pulse out one bit of data. */
1028: static INLINE void xi_mdi_pulse __P((struct xi_softc *, int));
1029: static INLINE void
1030: xi_mdi_pulse(sc, data)
1031: struct xi_softc *sc;
1032: int data;
1033: {
1034: bus_space_tag_t bst = sc->sc_bst;
1035: bus_space_handle_t bsh = sc->sc_bsh;
1.30 martin 1036: bus_size_t offset = sc->sc_offset;
1.1 gmcgarry 1037: u_int8_t bit = data ? MDIO_HIGH : MDIO_LOW;
1038:
1039: /* First latch the data bit MDIO with clock bit MDC low...*/
1040: bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_LOW);
1041: DELAY(1);
1042:
1043: /* then raise the clock again, preserving the data bit. */
1044: bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_HIGH);
1045: DELAY(1);
1046: }
1047:
1048: /* Probe one bit of data. */
1049: static INLINE int xi_mdi_probe __P((struct xi_softc *sc));
1050: static INLINE int
1051: xi_mdi_probe(sc)
1052: struct xi_softc *sc;
1053: {
1054: bus_space_tag_t bst = sc->sc_bst;
1055: bus_space_handle_t bsh = sc->sc_bsh;
1.19 soren 1056: bus_size_t offset = sc->sc_offset;
1.1 gmcgarry 1057: u_int8_t x;
1058:
1059: /* Pull clock bit MDCK low... */
1060: bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
1061: DELAY(1);
1062:
1063: /* Read data and drive clock high again. */
1064: x = bus_space_read_1(bst, bsh, offset + GP2) & MDIO;
1065: bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
1066: DELAY(1);
1067:
1068: return (x);
1069: }
1070:
1071: /* Pulse out a sequence of data bits. */
1072: static INLINE void xi_mdi_pulse_bits __P((struct xi_softc *, u_int32_t, int));
1073: static INLINE void
1074: xi_mdi_pulse_bits(sc, data, len)
1075: struct xi_softc *sc;
1076: u_int32_t data;
1077: int len;
1078: {
1079: u_int32_t mask;
1080:
1081: for (mask = 1 << (len - 1); mask; mask >>= 1)
1082: xi_mdi_pulse(sc, data & mask);
1083: }
1084:
1085: /* Read a PHY register. */
1086: static int
1087: xi_mdi_read(self, phy, reg)
1088: struct device *self;
1089: int phy;
1090: int reg;
1091: {
1092: struct xi_softc *sc = (struct xi_softc *)self;
1093: int i;
1094: u_int32_t mask;
1095: u_int32_t data = 0;
1096:
1097: PAGE(sc, 2);
1098: for (i = 0; i < 32; i++) /* Synchronize. */
1099: xi_mdi_pulse(sc, 1);
1100: xi_mdi_pulse_bits(sc, 0x06, 4); /* Start + Read opcode */
1101: xi_mdi_pulse_bits(sc, phy, 5); /* PHY address */
1102: xi_mdi_pulse_bits(sc, reg, 5); /* PHY register */
1103: xi_mdi_idle(sc); /* Turn around. */
1104: xi_mdi_probe(sc); /* Drop initial zero bit. */
1105:
1106: for (mask = 1 << 15; mask; mask >>= 1) {
1107: if (xi_mdi_probe(sc))
1108: data |= mask;
1109: }
1110: xi_mdi_idle(sc);
1111:
1112: DPRINTF(XID_MII,
1113: ("xi_mdi_read: phy %d reg %d -> %x\n", phy, reg, data));
1114:
1115: return (data);
1116: }
1117:
1118: /* Write a PHY register. */
1119: static void
1120: xi_mdi_write(self, phy, reg, value)
1121: struct device *self;
1122: int phy;
1123: int reg;
1124: int value;
1125: {
1126: struct xi_softc *sc = (struct xi_softc *)self;
1127: int i;
1128:
1129: PAGE(sc, 2);
1130: for (i = 0; i < 32; i++) /* Synchronize. */
1131: xi_mdi_pulse(sc, 1);
1132: xi_mdi_pulse_bits(sc, 0x05, 4); /* Start + Write opcode */
1133: xi_mdi_pulse_bits(sc, phy, 5); /* PHY address */
1134: xi_mdi_pulse_bits(sc, reg, 5); /* PHY register */
1135: xi_mdi_pulse_bits(sc, 0x02, 2); /* Turn around. */
1136: xi_mdi_pulse_bits(sc, value, 16); /* Write the data */
1137: xi_mdi_idle(sc); /* Idle away. */
1138:
1139: DPRINTF(XID_MII,
1140: ("xi_mdi_write: phy %d reg %d val %x\n", phy, reg, value));
1141: }
1142:
1143: static void
1144: xi_statchg(self)
1145: struct device *self;
1146: {
1147: /* XXX Update ifp->if_baudrate */
1148: }
1149:
1150: /*
1151: * Change media according to request.
1152: */
1153: static int
1154: xi_mediachange(ifp)
1155: struct ifnet *ifp;
1156: {
1.2 gmcgarry 1157: DPRINTF(XID_CONFIG, ("xi_mediachange()\n"));
1.1 gmcgarry 1158:
1159: if (ifp->if_flags & IFF_UP)
1160: xi_init(ifp->if_softc);
1161: return (0);
1162: }
1163:
1164: /*
1165: * Notify the world which media we're using.
1166: */
1167: static void
1168: xi_mediastatus(ifp, ifmr)
1169: struct ifnet *ifp;
1170: struct ifmediareq *ifmr;
1171: {
1172: struct xi_softc *sc = ifp->if_softc;
1173:
1.2 gmcgarry 1174: DPRINTF(XID_CONFIG, ("xi_mediastatus()\n"));
1.1 gmcgarry 1175:
1176: mii_pollstat(&sc->sc_mii);
1177: ifmr->ifm_status = sc->sc_mii.mii_media_status;
1178: ifmr->ifm_active = sc->sc_mii.mii_media_active;
1179: }
1180:
1181: static void
1182: xi_reset(sc)
1183: struct xi_softc *sc;
1184: {
1185: int s;
1186:
1.2 gmcgarry 1187: DPRINTF(XID_CONFIG, ("xi_reset()\n"));
1.1 gmcgarry 1188:
1189: s = splnet();
1190: xi_stop(sc);
1191: xi_full_reset(sc);
1192: xi_init(sc);
1193: splx(s);
1194: }
1195:
1196: static void
1197: xi_watchdog(ifp)
1198: struct ifnet *ifp;
1199: {
1200: struct xi_softc *sc = ifp->if_softc;
1201:
1202: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
1203: ++ifp->if_oerrors;
1204:
1205: xi_reset(sc);
1206: }
1207:
1208: static void
1209: xi_stop(sc)
1210: register struct xi_softc *sc;
1211: {
1.2 gmcgarry 1212: DPRINTF(XID_CONFIG, ("xi_stop()\n"));
1.1 gmcgarry 1213:
1214: /* Disable interrupts. */
1215: PAGE(sc, 0);
1216: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR, 0);
1217:
1218: PAGE(sc, 1);
1219: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + IMR0, 0);
1220:
1221: /* Power down, wait. */
1222: PAGE(sc, 4);
1223: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + GP1, 0);
1224: DELAY(40000);
1225:
1226: /* Cancel watchdog timer. */
1227: sc->sc_ethercom.ec_if.if_timer = 0;
1228: }
1229:
1230: static void
1231: xi_init(sc)
1232: struct xi_softc *sc;
1233: {
1.11 gmcgarry 1234: struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)sc;
1.1 gmcgarry 1235: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1236: int s;
1237:
1.2 gmcgarry 1238: DPRINTF(XID_CONFIG, ("xi_init()\n"));
1.1 gmcgarry 1239:
1.11 gmcgarry 1240: if ((psc->sc_resource & XI_RES_PCIC) == 0)
1241: xi_pcmcia_enable(psc);
1242:
1.8 thorpej 1243: s = splnet();
1.1 gmcgarry 1244:
1245: xi_set_address(sc);
1246:
1247: /* Set current media. */
1248: mii_mediachg(&sc->sc_mii);
1249:
1250: ifp->if_flags |= IFF_RUNNING;
1251: ifp->if_flags &= ~IFF_OACTIVE;
1252: splx(s);
1253: }
1254:
1255: /*
1256: * Start outputting on the interface.
1257: * Always called as splnet().
1258: */
1259: static void
1260: xi_start(ifp)
1261: struct ifnet *ifp;
1262: {
1263: struct xi_softc *sc = ifp->if_softc;
1264: bus_space_tag_t bst = sc->sc_bst;
1265: bus_space_handle_t bsh = sc->sc_bsh;
1.30 martin 1266: bus_size_t offset = sc->sc_offset;
1.1 gmcgarry 1267: unsigned int s, len, pad = 0;
1268: struct mbuf *m0, *m;
1269: u_int16_t space;
1270:
1.2 gmcgarry 1271: DPRINTF(XID_CONFIG, ("xi_start()\n"));
1.1 gmcgarry 1272:
1273: /* Don't transmit if interface is busy or not running. */
1274: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) {
1.2 gmcgarry 1275: DPRINTF(XID_CONFIG, ("xi: interface busy or not running\n"));
1.1 gmcgarry 1276: return;
1277: }
1278:
1279: /* Peek at the next packet. */
1.7 thorpej 1280: IFQ_POLL(&ifp->if_snd, m0);
1.1 gmcgarry 1281: if (m0 == 0)
1282: return;
1283:
1284: /* We need to use m->m_pkthdr.len, so require the header. */
1285: if (!(m0->m_flags & M_PKTHDR))
1286: panic("xi_start: no header mbuf");
1287:
1288: len = m0->m_pkthdr.len;
1289:
1290: /* Pad to ETHER_MIN_LEN - ETHER_CRC_LEN. */
1291: if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
1292: pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
1293:
1294: PAGE(sc, 0);
1295: space = bus_space_read_2(bst, bsh, offset + TSO0) & 0x7fff;
1296: if (len + pad + 2 > space) {
1297: DPRINTF(XID_FIFO,
1.2 gmcgarry 1298: ("xi: not enough space in output FIFO (%d > %d)\n",
1299: len + pad + 2, space));
1.1 gmcgarry 1300: return;
1301: }
1302:
1.7 thorpej 1303: IFQ_DEQUEUE(&ifp->if_snd, m0);
1.1 gmcgarry 1304:
1305: #if NBPFILTER > 0
1306: if (ifp->if_bpf)
1307: bpf_mtap(ifp->if_bpf, m0);
1308: #endif
1309:
1310: /*
1311: * Do the output at splhigh() so that an interrupt from another device
1312: * won't cause a FIFO underrun.
1313: */
1314: s = splhigh();
1315:
1316: bus_space_write_2(bst, bsh, offset + TSO2, (u_int16_t)len + pad + 2);
1317: bus_space_write_2(bst, bsh, offset + EDP, (u_int16_t)len + pad);
1318: for (m = m0; m; ) {
1319: if (m->m_len > 1)
1320: bus_space_write_multi_2(bst, bsh, offset + EDP,
1.21 takemura 1321: mtod(m, u_int16_t *), m->m_len>>1);
1.1 gmcgarry 1322: if (m->m_len & 1)
1323: bus_space_write_1(bst, bsh, offset + EDP,
1324: *(mtod(m, u_int8_t *) + m->m_len - 1));
1325: MFREE(m, m0);
1326: m = m0;
1327: }
1.3 gmcgarry 1328: if (sc->sc_flags & XIFLAGS_MOHAWK)
1.1 gmcgarry 1329: bus_space_write_1(bst, bsh, offset + CR, TX_PKT | ENABLE_INT);
1330: else {
1331: for (; pad > 1; pad -= 2)
1332: bus_space_write_2(bst, bsh, offset + EDP, 0);
1333: if (pad == 1)
1334: bus_space_write_1(bst, bsh, offset + EDP, 0);
1335: }
1336:
1337: splx(s);
1338:
1339: ifp->if_timer = 5;
1340: ++ifp->if_opackets;
1341: }
1342:
1343: static int
1344: xi_ether_ioctl(ifp, cmd, data)
1345: struct ifnet *ifp;
1346: u_long cmd;
1347: caddr_t data;
1348: {
1349: struct ifaddr *ifa = (struct ifaddr *)data;
1350: struct xi_softc *sc = ifp->if_softc;
1351:
1352:
1.2 gmcgarry 1353: DPRINTF(XID_CONFIG, ("xi_ether_ioctl()\n"));
1.1 gmcgarry 1354:
1355: switch (cmd) {
1356: case SIOCSIFADDR:
1357: ifp->if_flags |= IFF_UP;
1358:
1359: switch (ifa->ifa_addr->sa_family) {
1360: #ifdef INET
1361: case AF_INET:
1362: xi_init(sc);
1363: arp_ifinit(ifp, ifa);
1364: break;
1365: #endif /* INET */
1366:
1367: #ifdef NS
1368: case AF_NS:
1369: {
1370: struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
1371:
1372: if (ns_nullhost(*ina))
1373: ina->x_host = *(union ns_host *)
1374: LLADDR(ifp->if_sadl);
1375: else
1.12 thorpej 1376: memcpy(LLADDR(ifp->if_sadl), ina->x_host.c_host,
1.1 gmcgarry 1377: ifp->if_addrlen);
1378: /* Set new address. */
1379: xi_init(sc);
1380: break;
1381: }
1382: #endif /* NS */
1383:
1384: default:
1385: xi_init(sc);
1386: break;
1387: }
1388: break;
1389:
1390: default:
1391: return (EINVAL);
1392: }
1393:
1394: return (0);
1395: }
1396:
1397: static int
1398: xi_ioctl(ifp, command, data)
1399: struct ifnet *ifp;
1400: u_long command;
1401: caddr_t data;
1402: {
1.11 gmcgarry 1403: struct xi_pcmcia_softc *psc = ifp->if_softc;
1404: struct xi_softc *sc = &psc->sc_xi;
1.1 gmcgarry 1405: struct ifreq *ifr = (struct ifreq *)data;
1406: int s, error = 0;
1407:
1.2 gmcgarry 1408: DPRINTF(XID_CONFIG, ("xi_ioctl()\n"));
1.1 gmcgarry 1409:
1.8 thorpej 1410: s = splnet();
1.1 gmcgarry 1411:
1412: switch (command) {
1413: case SIOCSIFADDR:
1414: error = xi_ether_ioctl(ifp, command, data);
1415: break;
1416:
1417: case SIOCSIFFLAGS:
1418: sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
1419:
1420: PAGE(sc, 0x42);
1421: if ((ifp->if_flags & IFF_PROMISC) ||
1422: (ifp->if_flags & IFF_ALLMULTI))
1423: bus_space_write_1(sc->sc_bst, sc->sc_bsh,
1424: sc->sc_offset + SWC1,
1425: SWC1_PROMISC | SWC1_MCAST_PROM);
1426: else
1427: bus_space_write_1(sc->sc_bst, sc->sc_bsh,
1428: sc->sc_offset + SWC1, 0);
1429:
1430: /*
1431: * If interface is marked up and not running, then start it.
1432: * If it is marked down and running, stop it.
1433: * XXX If it's up then re-initialize it. This is so flags
1434: * such as IFF_PROMISC are handled.
1435: */
1436: if (ifp->if_flags & IFF_UP) {
1437: xi_init(sc);
1438: } else {
1439: if (ifp->if_flags & IFF_RUNNING) {
1.11 gmcgarry 1440: xi_pcmcia_disable(psc);
1.1 gmcgarry 1441: xi_stop(sc);
1442: ifp->if_flags &= ~IFF_RUNNING;
1443: }
1444: }
1445: break;
1446:
1447: case SIOCADDMULTI:
1448: case SIOCDELMULTI:
1449: sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
1450: error = (command == SIOCADDMULTI) ?
1451: ether_addmulti(ifr, &sc->sc_ethercom) :
1452: ether_delmulti(ifr, &sc->sc_ethercom);
1453:
1454: if (error == ENETRESET) {
1455: /*
1456: * Multicast list has changed; set the hardware
1457: * filter accordingly.
1458: */
1459: if (!sc->sc_all_mcasts &&
1460: !(ifp->if_flags & IFF_PROMISC))
1461: xi_set_address(sc);
1462:
1463: /*
1464: * xi_set_address() can turn on all_mcasts if we run
1465: * out of space, so check it again rather than else {}.
1466: */
1467: if (sc->sc_all_mcasts)
1468: xi_init(sc);
1469: error = 0;
1470: }
1471: break;
1472:
1473: case SIOCSIFMEDIA:
1474: case SIOCGIFMEDIA:
1475: error =
1476: ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
1477: break;
1478:
1479: default:
1480: error = EINVAL;
1481: }
1482: splx(s);
1483: return (error);
1484: }
1485:
1486: static void
1487: xi_set_address(sc)
1488: struct xi_softc *sc;
1489: {
1490: bus_space_tag_t bst = sc->sc_bst;
1491: bus_space_handle_t bsh = sc->sc_bsh;
1.30 martin 1492: bus_size_t offset = sc->sc_offset;
1.1 gmcgarry 1493: struct ethercom *ether = &sc->sc_ethercom;
1.11 gmcgarry 1494: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1495: #if WORKING_MULTICAST
1496: struct ether_multistep step;
1.1 gmcgarry 1497: struct ether_multi *enm;
1.11 gmcgarry 1498: int page, pos, num;
1499: #endif
1500: int i;
1.1 gmcgarry 1501:
1.2 gmcgarry 1502: DPRINTF(XID_CONFIG, ("xi_set_address()\n"));
1.1 gmcgarry 1503:
1504: PAGE(sc, 0x50);
1.11 gmcgarry 1505: for (i = 0; i < ETHER_ADDR_LEN; i++) {
1.1 gmcgarry 1506: bus_space_write_1(bst, bsh, offset + IA + i,
1.3 gmcgarry 1507: sc->sc_enaddr[(sc->sc_flags & XIFLAGS_MOHAWK) ? 5-i : i]);
1.1 gmcgarry 1508: }
1.11 gmcgarry 1509:
1.1 gmcgarry 1510: if (ether->ec_multicnt > 0) {
1.11 gmcgarry 1511: #ifdef WORKING_MULTICAST
1.1 gmcgarry 1512: if (ether->ec_multicnt > 9) {
1.11 gmcgarry 1513: #else
1514: {
1515: #endif
1.1 gmcgarry 1516: PAGE(sc, 0x42);
1517: bus_space_write_1(sc->sc_bst, sc->sc_bsh,
1518: sc->sc_offset + SWC1,
1519: SWC1_PROMISC | SWC1_MCAST_PROM);
1.28 bouyer 1520: ifp->if_flags |= IFF_PROMISC;
1.1 gmcgarry 1521: return;
1522: }
1523:
1.11 gmcgarry 1524: #ifdef WORKING_MULTICAST
1525:
1.1 gmcgarry 1526: ETHER_FIRST_MULTI(step, ether, enm);
1527:
1528: pos = IA + 6;
1529: for (page = 0x50, num = ether->ec_multicnt; num > 0 && enm;
1530: num--) {
1.13 thorpej 1531: if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
1.1 gmcgarry 1532: sizeof(enm->enm_addrlo)) != 0) {
1533: /*
1534: * The multicast address is really a range;
1535: * it's easier just to accept all multicasts.
1536: * XXX should we be setting IFF_ALLMULTI here?
1537: */
1.11 gmcgarry 1538: #if 0
1.1 gmcgarry 1539: ifp->if_flags |= IFF_ALLMULTI;
1.11 gmcgarry 1540: #endif
1.1 gmcgarry 1541: sc->sc_all_mcasts=1;
1542: break;
1543: }
1544:
1.11 gmcgarry 1545: for (i = 0; i < ETHER_ADDR_LEN; i++) {
1546: printf("%x:", enm->enm_addrlo[i]);
1.1 gmcgarry 1547: bus_space_write_1(bst, bsh, offset + pos,
1548: enm->enm_addrlo[
1.3 gmcgarry 1549: (sc->sc_flags & XIFLAGS_MOHAWK) ? 5-i : i]);
1.1 gmcgarry 1550:
1551: if (++pos > 15) {
1552: pos = IA;
1553: page++;
1554: PAGE(sc, page);
1555: }
1556: }
1.11 gmcgarry 1557: printf("\n");
1558: ETHER_NEXT_MULTI(step, enm);
1.1 gmcgarry 1559: }
1.11 gmcgarry 1560: #endif
1.1 gmcgarry 1561: }
1562: }
1563:
1564: static void
1565: xi_cycle_power(sc)
1566: struct xi_softc *sc;
1567: {
1568: bus_space_tag_t bst = sc->sc_bst;
1569: bus_space_handle_t bsh = sc->sc_bsh;
1.30 martin 1570: bus_size_t offset = sc->sc_offset;
1.1 gmcgarry 1571:
1.2 gmcgarry 1572: DPRINTF(XID_CONFIG, ("xi_cycle_power()\n"));
1.1 gmcgarry 1573:
1574: PAGE(sc, 4);
1575: DELAY(1);
1576: bus_space_write_1(bst, bsh, offset + GP1, 0);
1577: DELAY(40000);
1.3 gmcgarry 1578: if (sc->sc_flags & XIFLAGS_MOHAWK)
1.1 gmcgarry 1579: bus_space_write_1(bst, bsh, offset + GP1, POWER_UP);
1580: else
1581: /* XXX What is bit 2 (aka AIC)? */
1582: bus_space_write_1(bst, bsh, offset + GP1, POWER_UP | 4);
1583: DELAY(20000);
1584: }
1585:
1586: static void
1587: xi_full_reset(sc)
1588: struct xi_softc *sc;
1589: {
1590: bus_space_tag_t bst = sc->sc_bst;
1591: bus_space_handle_t bsh = sc->sc_bsh;
1.30 martin 1592: bus_size_t offset = sc->sc_offset;
1.1 gmcgarry 1593:
1.2 gmcgarry 1594: DPRINTF(XID_CONFIG, ("xi_full_reset()\n"));
1.1 gmcgarry 1595:
1596: /* Do an as extensive reset as possible on all functions. */
1597: xi_cycle_power(sc);
1598: bus_space_write_1(bst, bsh, offset + CR, SOFT_RESET);
1599: DELAY(20000);
1600: bus_space_write_1(bst, bsh, offset + CR, 0);
1601: DELAY(20000);
1.3 gmcgarry 1602: if (sc->sc_flags & XIFLAGS_MOHAWK) {
1.1 gmcgarry 1603: PAGE(sc, 4);
1604: /*
1605: * Drive GP1 low to power up ML6692 and GP2 high to power up
1.29 tsutsui 1606: * the 10MHz chip. XXX What chip is that? The phy?
1.1 gmcgarry 1607: */
1608: bus_space_write_1(bst, bsh, offset + GP0,
1609: GP1_OUT | GP2_OUT | GP2_WR);
1610: }
1611: DELAY(500000);
1612:
1613: /* Get revision information. XXX Symbolic constants. */
1614: sc->sc_rev = bus_space_read_1(bst, bsh, offset + BV) &
1.3 gmcgarry 1615: ((sc->sc_flags & XIFLAGS_MOHAWK) ? 0x70 : 0x30) >> 4;
1.1 gmcgarry 1616:
1617: /* Media selection. XXX Maybe manual overriding too? */
1.3 gmcgarry 1618: if (!(sc->sc_flags & XIFLAGS_MOHAWK)) {
1.1 gmcgarry 1619: PAGE(sc, 4);
1620: /*
1621: * XXX I have no idea what this really does, it is from the
1622: * Linux driver.
1623: */
1624: bus_space_write_1(bst, bsh, offset + GP0, GP1_OUT);
1625: }
1626: DELAY(40000);
1627:
1628: /* Setup the ethernet interrupt mask. */
1629: PAGE(sc, 1);
1.11 gmcgarry 1630: #if 1
1.1 gmcgarry 1631: bus_space_write_1(bst, bsh, offset + IMR0,
1632: ISR_TX_OFLOW | ISR_PKT_TX | ISR_MAC_INT | /* ISR_RX_EARLY | */
1633: ISR_RX_FULL | ISR_RX_PKT_REJ | ISR_FORCED_INT);
1.11 gmcgarry 1634: #else
1.1 gmcgarry 1635: bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
1636: #endif
1.3 gmcgarry 1637: if (!(sc->sc_flags & XIFLAGS_DINGO)) {
1.1 gmcgarry 1638: /* XXX What is this? Not for Dingo at least. */
1.11 gmcgarry 1639: /* Unmask TX underrun detection */
1.1 gmcgarry 1640: bus_space_write_1(bst, bsh, offset + IMR1, 1);
1641: }
1642:
1643: /*
1644: * Disable source insertion.
1645: * XXX Dingo does not have this bit, but Linux does it unconditionally.
1646: */
1.3 gmcgarry 1647: if (!(sc->sc_flags & XIFLAGS_DINGO)) {
1.1 gmcgarry 1648: PAGE(sc, 0x42);
1649: bus_space_write_1(bst, bsh, offset + SWC0, 0x20);
1650: }
1651:
1652: /* Set the local memory dividing line. */
1653: if (sc->sc_rev != 1) {
1654: PAGE(sc, 2);
1655: /* XXX Symbolic constant preferrable. */
1656: bus_space_write_2(bst, bsh, offset + RBS0, 0x2000);
1657: }
1658:
1659: xi_set_address(sc);
1660:
1661: /*
1662: * Apparently the receive byte pointer can be bad after a reset, so
1663: * we hardwire it correctly.
1664: */
1665: PAGE(sc, 0);
1666: bus_space_write_2(bst, bsh, offset + DO0, DO_CHG_OFFSET);
1667:
1668: /* Setup ethernet MAC registers. XXX Symbolic constants. */
1669: PAGE(sc, 0x40);
1670: bus_space_write_1(bst, bsh, offset + RX0MSK,
1671: PKT_TOO_LONG | CRC_ERR | RX_OVERRUN | RX_ABORT | RX_OK);
1672: bus_space_write_1(bst, bsh, offset + TX0MSK,
1673: CARRIER_LOST | EXCESSIVE_COLL | TX_UNDERRUN | LATE_COLLISION |
1674: SQE | TX_ABORT | TX_OK);
1.3 gmcgarry 1675: if (!(sc->sc_flags & XIFLAGS_DINGO))
1.1 gmcgarry 1676: /* XXX From Linux, dunno what 0xb0 means. */
1677: bus_space_write_1(bst, bsh, offset + TX1MSK, 0xb0);
1678: bus_space_write_1(bst, bsh, offset + RXST0, 0);
1679: bus_space_write_1(bst, bsh, offset + TXST0, 0);
1680: bus_space_write_1(bst, bsh, offset + TXST1, 0);
1681:
1682: /* Enable MII function if available. */
1683: if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
1684: PAGE(sc, 2);
1685: bus_space_write_1(bst, bsh, offset + MSR,
1686: bus_space_read_1(bst, bsh, offset + MSR) | SELECT_MII);
1687: DELAY(20000);
1688: } else {
1689: PAGE(sc, 0);
1690:
1691: /* XXX Do we need to do this? */
1692: PAGE(sc, 0x42);
1693: bus_space_write_1(bst, bsh, offset + SWC1, SWC1_AUTO_MEDIA);
1694: DELAY(50000);
1695:
1696: /* XXX Linux probes the media here. */
1697: }
1698:
1699: /* Configure the LED registers. */
1700: PAGE(sc, 2);
1701:
1702: /* XXX This is not good for 10base2. */
1703: bus_space_write_1(bst, bsh, offset + LED,
1704: LED_TX_ACT << LED1_SHIFT | LED_10MB_LINK << LED0_SHIFT);
1.3 gmcgarry 1705: if (sc->sc_flags & XIFLAGS_DINGO)
1.1 gmcgarry 1706: bus_space_write_1(bst, bsh, offset + LED3,
1707: LED_100MB_LINK << LED3_SHIFT);
1708:
1709: /* Enable receiver and go online. */
1710: PAGE(sc, 0x40);
1711: bus_space_write_1(bst, bsh, offset + CMD0, ENABLE_RX | ONLINE);
1712:
1713: #if 0
1714: /* XXX Linux does this here - is it necessary? */
1715: PAGE(sc, 1);
1716: bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
1.3 gmcgarry 1717: if (!(sc->sc_flags & XIFLAGS_DINGO)) {
1.1 gmcgarry 1718: /* XXX What is this? Not for Dingo at least. */
1719: bus_space_write_1(bst, bsh, offset + IMR1, 1);
1720: }
1721: #endif
1722:
1723: /* Enable interrupts. */
1724: PAGE(sc, 0);
1725: bus_space_write_1(bst, bsh, offset + CR, ENABLE_INT);
1726:
1727: /* XXX This is pure magic for me, found in the Linux driver. */
1.3 gmcgarry 1728: if ((sc->sc_flags & (XIFLAGS_DINGO | XIFLAGS_MODEM)) == XIFLAGS_MODEM) {
1.1 gmcgarry 1729: if ((bus_space_read_1(bst, bsh, offset + 0x10) & 0x01) == 0)
1730: /* Unmask the master interrupt bit. */
1731: bus_space_write_1(bst, bsh, offset + 0x10, 0x11);
1732: }
1733:
1734: /*
1735: * The Linux driver says this:
1736: * We should switch back to page 0 to avoid a bug in revision 0
1737: * where regs with offset below 8 can't be read after an access
1738: * to the MAC registers.
1739: */
1740: PAGE(sc, 0);
1741: }
CVSweb <webmaster@jp.NetBSD.org>