Annotation of sys/dev/pcmcia/if_xe.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_xe.c,v 1.33 2007/06/06 09:43:44 henning Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1999 Niklas Hallqvist, Brandon Creighton, Job de Haas
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Niklas Hallqvist,
! 18: * C Stone and Job de Haas.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: /*
! 35: * A driver for Xircom ethernet PC-cards.
! 36: *
! 37: * The driver has been inspired by the xirc2ps_cs.c driver found in Linux'
! 38: * PCMCIA package written by Werner Koch <werner.koch@guug.de>:
! 39: * [xirc2ps_cs.c wk 14.04.97] (1.31 1998/12/09 19:32:55)
! 40: * I will note that no code was used verbatim from that driver as it is under
! 41: * the much too strong GNU General Public License, it was only used as a
! 42: * "specification" of sorts.
! 43: * Other inspirations have been if_fxp.c, if_ep_pcmcia.c and elink3.c as
! 44: * they were found in OpenBSD 2.4.
! 45: */
! 46:
! 47: #include "bpfilter.h"
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/device.h>
! 52: #include <sys/ioctl.h>
! 53: #include <sys/mbuf.h>
! 54: #include <sys/malloc.h>
! 55: #include <sys/kernel.h>
! 56: #include <sys/socket.h>
! 57: #include <sys/syslog.h>
! 58:
! 59: #include <net/if.h>
! 60: #include <net/if_dl.h>
! 61: #include <net/if_media.h>
! 62: #include <net/if_types.h>
! 63:
! 64: #ifdef INET
! 65: #include <netinet/in.h>
! 66: #include <netinet/in_systm.h>
! 67: #include <netinet/in_var.h>
! 68: #include <netinet/ip.h>
! 69: #include <netinet/if_ether.h>
! 70: #endif
! 71:
! 72: #if NBPFILTER > 0
! 73: #include <net/bpf.h>
! 74: #endif
! 75:
! 76: /*
! 77: * Maximum number of bytes to read per interrupt. Linux recommends
! 78: * somewhere between 2000-22000.
! 79: * XXX This is currently a hard maximum.
! 80: */
! 81: #define MAX_BYTES_INTR 12000
! 82:
! 83: #include <dev/mii/miivar.h>
! 84:
! 85: #include <dev/pcmcia/pcmciareg.h>
! 86: #include <dev/pcmcia/pcmciavar.h>
! 87: #include <dev/pcmcia/pcmciadevs.h>
! 88: #include <dev/pcmcia/if_xereg.h>
! 89:
! 90: #ifdef __GNUC__
! 91: #define INLINE __inline
! 92: #else
! 93: #define INLINE
! 94: #endif /* __GNUC__ */
! 95:
! 96: #ifdef XEDEBUG
! 97:
! 98: #define XED_CONFIG 0x1
! 99: #define XED_MII 0x2
! 100: #define XED_INTR 0x4
! 101: #define XED_FIFO 0x8
! 102:
! 103: #ifndef XEDEBUG_DEF
! 104: #define XEDEBUG_DEF (XED_CONFIG|XED_INTR)
! 105: #endif /* XEDEBUG_DEF */
! 106:
! 107: int xedebug = XEDEBUG_DEF;
! 108:
! 109: #define DPRINTF(cat, x) if (xedebug & (cat)) printf x
! 110:
! 111: #else /* XEDEBUG */
! 112: #define DPRINTF(cat, x) (void)0
! 113: #endif /* XEDEBUG */
! 114:
! 115: int xe_pcmcia_match(struct device *, void *, void *);
! 116: void xe_pcmcia_attach(struct device *, struct device *, void *);
! 117: int xe_pcmcia_detach(struct device *, int);
! 118: int xe_pcmcia_activate(struct device *, enum devact);
! 119:
! 120: /*
! 121: * In case this chipset ever turns up out of pcmcia attachments (very
! 122: * unlikely) do the driver splitup.
! 123: */
! 124: struct xe_softc {
! 125: struct device sc_dev; /* Generic device info */
! 126: u_int32_t sc_flags; /* Misc. flags */
! 127: void *sc_ih; /* Interrupt handler */
! 128: struct arpcom sc_arpcom; /* Ethernet common part */
! 129: struct ifmedia sc_media; /* Media control */
! 130: struct mii_data sc_mii; /* MII media information */
! 131: int sc_all_mcasts; /* Receive all multicasts */
! 132: bus_space_tag_t sc_bst; /* Bus cookie */
! 133: bus_space_handle_t sc_bsh; /* Bus I/O handle */
! 134: bus_size_t sc_offset; /* Offset of registers */
! 135: u_int8_t sc_rev; /* Chip revision */
! 136: };
! 137:
! 138: #define XEF_MOHAWK 0x001
! 139: #define XEF_DINGO 0x002
! 140: #define XEF_MODEM 0x004
! 141: #define XEF_UNSUPPORTED 0x008
! 142: #define XEF_CE 0x010
! 143: #define XEF_CE2 0x020
! 144: #define XEF_CE3 0x040
! 145: #define XEF_CE33 0x080
! 146: #define XEF_CE56 0x100
! 147:
! 148: struct xe_pcmcia_softc {
! 149: struct xe_softc sc_xe; /* Generic device info */
! 150: struct pcmcia_mem_handle sc_pcmh; /* PCMCIA memspace info */
! 151: int sc_mem_window; /* mem window */
! 152: struct pcmcia_io_handle sc_pcioh; /* iospace info */
! 153: int sc_io_window; /* io window info */
! 154: struct pcmcia_function *sc_pf; /* PCMCIA function */
! 155: };
! 156:
! 157: /* Autoconfig definition of driver back-end */
! 158: struct cfdriver xe_cd = {
! 159: NULL, "xe", DV_IFNET
! 160: };
! 161:
! 162: struct cfattach xe_pcmcia_ca = {
! 163: sizeof (struct xe_pcmcia_softc), xe_pcmcia_match, xe_pcmcia_attach,
! 164: xe_pcmcia_detach, xe_pcmcia_activate
! 165: };
! 166:
! 167: void xe_cycle_power(struct xe_softc *);
! 168: int xe_ether_ioctl(struct ifnet *, u_long cmd, caddr_t);
! 169: void xe_full_reset(struct xe_softc *);
! 170: void xe_init(struct xe_softc *);
! 171: int xe_intr(void *);
! 172: int xe_ioctl(struct ifnet *, u_long, caddr_t);
! 173: int xe_mdi_read(struct device *, int, int);
! 174: void xe_mdi_write(struct device *, int, int, int);
! 175: int xe_mediachange(struct ifnet *);
! 176: void xe_mediastatus(struct ifnet *, struct ifmediareq *);
! 177: int xe_pcmcia_funce_enaddr(struct device *, u_int8_t *);
! 178: u_int32_t xe_pcmcia_interpret_manfid(struct device *);
! 179: int xe_pcmcia_lan_nid_ciscallback(struct pcmcia_tuple *, void *);
! 180: int xe_pcmcia_manfid_ciscallback(struct pcmcia_tuple *, void *);
! 181: u_int16_t xe_get(struct xe_softc *);
! 182: void xe_reset(struct xe_softc *);
! 183: void xe_set_address(struct xe_softc *);
! 184: void xe_start(struct ifnet *);
! 185: void xe_statchg(struct device *);
! 186: void xe_stop(struct xe_softc *);
! 187: void xe_watchdog(struct ifnet *);
! 188: #ifdef XEDEBUG
! 189: void xe_reg_dump(struct xe_softc *);
! 190: #endif /* XEDEBUG */
! 191:
! 192: int
! 193: xe_pcmcia_match(parent, match, aux)
! 194: struct device *parent;
! 195: void *match, *aux;
! 196: {
! 197: struct pcmcia_attach_args *pa = aux;
! 198:
! 199: if (pa->pf->function != PCMCIA_FUNCTION_NETWORK)
! 200: return (0);
! 201:
! 202: switch (pa->manufacturer) {
! 203: case PCMCIA_VENDOR_COMPAQ:
! 204: case PCMCIA_VENDOR_COMPAQ2:
! 205: return (0);
! 206:
! 207: case PCMCIA_VENDOR_INTEL:
! 208: case PCMCIA_VENDOR_XIRCOM:
! 209: /* XXX Per-productid checking here. */
! 210: return (1);
! 211:
! 212: default:
! 213: return (0);
! 214: }
! 215: }
! 216:
! 217: void
! 218: xe_pcmcia_attach(parent, self, aux)
! 219: struct device *parent, *self;
! 220: void *aux;
! 221: {
! 222: struct xe_pcmcia_softc *psc = (struct xe_pcmcia_softc *)self;
! 223: struct xe_softc *sc = &psc->sc_xe;
! 224: struct pcmcia_attach_args *pa = aux;
! 225: struct pcmcia_function *pf = pa->pf;
! 226: struct pcmcia_config_entry *cfe;
! 227: struct ifnet *ifp;
! 228: u_int8_t myla[ETHER_ADDR_LEN], *enaddr = NULL;
! 229: int state = 0;
! 230: struct pcmcia_mem_handle pcmh;
! 231: int ccr_window;
! 232: bus_size_t ccr_offset;
! 233: const char *intrstr;
! 234:
! 235: psc->sc_pf = pf;
! 236:
! 237: #if 0
! 238: /* Figure out what card we are. */
! 239: sc->sc_flags = xe_pcmcia_interpret_manfid(parent);
! 240: #endif
! 241: if (sc->sc_flags & XEF_UNSUPPORTED) {
! 242: printf(": card unsupported\n");
! 243: goto bad;
! 244: }
! 245:
! 246: /* Tell the pcmcia framework where the CCR is. */
! 247: pf->ccr_base = 0x800;
! 248: pf->ccr_mask = 0x67;
! 249:
! 250: /* Fake a cfe. */
! 251: SIMPLEQ_FIRST(&pa->pf->cfe_head) = cfe = (struct pcmcia_config_entry *)
! 252: malloc(sizeof *cfe, M_DEVBUF, M_NOWAIT);
! 253: if (!cfe) {
! 254: printf(": function enable failed\n");
! 255: return;
! 256: }
! 257: bzero(cfe, sizeof *cfe);
! 258:
! 259: /*
! 260: * XXX Use preprocessor symbols instead.
! 261: * Enable ethernet & its interrupts, wiring them to -INT
! 262: * No I/O base.
! 263: */
! 264: cfe->number = 0x5;
! 265: cfe->flags = 0; /* XXX Check! */
! 266: cfe->iftype = PCMCIA_IFTYPE_IO;
! 267: cfe->num_iospace = 0;
! 268: cfe->num_memspace = 0;
! 269: cfe->irqmask = 0x8eb0;
! 270:
! 271: /* Enable the card. */
! 272: pcmcia_function_init(pa->pf, cfe);
! 273: if (pcmcia_function_enable(pa->pf)) {
! 274: printf(": function enable failed\n");
! 275: goto bad;
! 276: }
! 277:
! 278: state++;
! 279:
! 280: if (pcmcia_io_alloc(pa->pf, 0, 16, 16, &psc->sc_pcioh)) {
! 281: printf(": io allocation failed\n");
! 282: goto bad;
! 283: }
! 284:
! 285: state++;
! 286:
! 287: if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO16, 0, 16, &psc->sc_pcioh,
! 288: &psc->sc_io_window)) {
! 289: printf(": can't map io space\n");
! 290: goto bad;
! 291: }
! 292: sc->sc_bst = psc->sc_pcioh.iot;
! 293: sc->sc_bsh = psc->sc_pcioh.ioh;
! 294: sc->sc_offset = 0;
! 295:
! 296: printf(" port 0x%lx/%d", psc->sc_pcioh.addr, 16);
! 297:
! 298: #if 0
! 299: if (pcmcia_mem_alloc(pf, 16, &psc->sc_pcmh)) {
! 300: printf(": pcmcia memory allocation failed\n");
! 301: goto bad;
! 302: }
! 303: state++;
! 304:
! 305: if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0x300, 16, &psc->sc_pcmh,
! 306: &sc->sc_offset, &psc->sc_mem_window)) {
! 307: printf(": pcmcia memory mapping failed\n");
! 308: goto bad;
! 309: }
! 310:
! 311: sc->sc_bst = psc->sc_pcmh.memt;
! 312: sc->sc_bsh = psc->sc_pcmh.memh;
! 313: #endif
! 314:
! 315: /* Figure out what card we are. */
! 316: sc->sc_flags = xe_pcmcia_interpret_manfid(parent);
! 317:
! 318: /*
! 319: * Configuration as advised by DINGO documentation.
! 320: * We only know about this flag after the manfid interpretation.
! 321: * Dingo has some extra configuration registers in the CCR space.
! 322: */
! 323: if (sc->sc_flags & XEF_DINGO) {
! 324: if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE_DINGO, &pcmh)) {
! 325: DPRINTF(XED_CONFIG, ("bad mem alloc\n"));
! 326: goto bad;
! 327: }
! 328:
! 329: if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
! 330: PCMCIA_CCR_SIZE_DINGO, &pcmh, &ccr_offset,
! 331: &ccr_window)) {
! 332: DPRINTF(XED_CONFIG, ("bad mem map\n"));
! 333: pcmcia_mem_free(pf, &pcmh);
! 334: goto bad;
! 335: }
! 336:
! 337: bus_space_write_1(pcmh.memt, pcmh.memh,
! 338: ccr_offset + PCMCIA_CCR_DCOR0, PCMCIA_CCR_DCOR0_SFINT);
! 339: bus_space_write_1(pcmh.memt, pcmh.memh,
! 340: ccr_offset + PCMCIA_CCR_DCOR1,
! 341: PCMCIA_CCR_DCOR1_FORCE_LEVIREQ | PCMCIA_CCR_DCOR1_D6);
! 342: bus_space_write_1(pcmh.memt, pcmh.memh,
! 343: ccr_offset + PCMCIA_CCR_DCOR2, 0);
! 344: bus_space_write_1(pcmh.memt, pcmh.memh,
! 345: ccr_offset + PCMCIA_CCR_DCOR3, 0);
! 346: bus_space_write_1(pcmh.memt, pcmh.memh,
! 347: ccr_offset + PCMCIA_CCR_DCOR4, 0);
! 348:
! 349: /* We don't need them anymore and can free them (I think). */
! 350: pcmcia_mem_unmap(pf, ccr_window);
! 351: pcmcia_mem_free(pf, &pcmh);
! 352: }
! 353:
! 354: /*
! 355: * Try to get the ethernet address from FUNCE/LAN_NID tuple.
! 356: */
! 357: if (xe_pcmcia_funce_enaddr(parent, myla))
! 358: enaddr = myla;
! 359: ifp = &sc->sc_arpcom.ac_if;
! 360: if (enaddr)
! 361: bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
! 362: else {
! 363: printf(", unable to get ethernet address\n");
! 364: goto bad;
! 365: }
! 366:
! 367: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 368: ifp->if_softc = sc;
! 369: ifp->if_flags =
! 370: IFF_BROADCAST | IFF_NOTRAILERS | IFF_SIMPLEX | IFF_MULTICAST;
! 371: ifp->if_ioctl = xe_ioctl;
! 372: ifp->if_start = xe_start;
! 373: ifp->if_watchdog = xe_watchdog;
! 374: IFQ_SET_READY(&ifp->if_snd);
! 375:
! 376: /* Establish the interrupt. */
! 377: sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, xe_intr, sc,
! 378: sc->sc_dev.dv_xname);
! 379: if (sc->sc_ih == NULL) {
! 380: printf(", couldn't establish interrupt\n");
! 381: goto bad;
! 382: }
! 383: intrstr = pcmcia_intr_string(psc->sc_pf, sc->sc_ih);
! 384: printf("%s%s: address %s\n", *intrstr ? ", " : "", intrstr,
! 385: ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 386:
! 387: /* Reset and initialize the card. */
! 388: xe_full_reset(sc);
! 389:
! 390: /* Initialize our media structures and probe the phy. */
! 391: sc->sc_mii.mii_ifp = ifp;
! 392: sc->sc_mii.mii_readreg = xe_mdi_read;
! 393: sc->sc_mii.mii_writereg = xe_mdi_write;
! 394: sc->sc_mii.mii_statchg = xe_statchg;
! 395: ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, xe_mediachange,
! 396: xe_mediastatus);
! 397: DPRINTF(XED_MII | XED_CONFIG,
! 398: ("bmsr %x\n", xe_mdi_read(&sc->sc_dev, 0, 1)));
! 399: mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
! 400: 0);
! 401: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL)
! 402: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO, 0,
! 403: NULL);
! 404: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
! 405:
! 406: /*
! 407: * Attach the interface.
! 408: */
! 409: if_attach(ifp);
! 410: ether_ifattach(ifp);
! 411:
! 412: /*
! 413: * Reset and initialize the card again for DINGO (as found in Linux
! 414: * driver). Without this Dingo will get a watchdog timeout the first
! 415: * time. The ugly media tickling seems to be necessary for getting
! 416: * autonegotiation to work too.
! 417: */
! 418: if (sc->sc_flags & XEF_DINGO) {
! 419: xe_full_reset(sc);
! 420: xe_init(sc);
! 421: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
! 422: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
! 423: xe_stop(sc);
! 424: }
! 425:
! 426: #ifdef notyet
! 427: pcmcia_function_disable(pa->pf);
! 428: #endif /* notyet */
! 429:
! 430: return;
! 431:
! 432: bad:
! 433: if (state > 2)
! 434: pcmcia_io_unmap(pf, psc->sc_io_window);
! 435: if (state > 1)
! 436: pcmcia_io_free(pf, &psc->sc_pcioh);
! 437: if (state > 0)
! 438: pcmcia_function_disable(pa->pf);
! 439: free(cfe, M_DEVBUF);
! 440: }
! 441:
! 442: int
! 443: xe_pcmcia_detach(dev, flags)
! 444: struct device *dev;
! 445: int flags;
! 446: {
! 447: struct xe_pcmcia_softc *psc = (struct xe_pcmcia_softc *)dev;
! 448: struct xe_softc *sc = &psc->sc_xe;
! 449: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 450: int rv = 0;
! 451:
! 452: mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
! 453: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
! 454:
! 455: pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
! 456: pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
! 457:
! 458: ether_ifdetach(ifp);
! 459: if_detach(ifp);
! 460:
! 461: return (rv);
! 462: }
! 463:
! 464: int
! 465: xe_pcmcia_activate(dev, act)
! 466: struct device *dev;
! 467: enum devact act;
! 468: {
! 469: struct xe_pcmcia_softc *sc = (struct xe_pcmcia_softc *)dev;
! 470: struct ifnet *ifp = &sc->sc_xe.sc_arpcom.ac_if;
! 471: int s;
! 472:
! 473: s = splnet();
! 474: switch (act) {
! 475: case DVACT_ACTIVATE:
! 476: pcmcia_function_enable(sc->sc_pf);
! 477: sc->sc_xe.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
! 478: xe_intr, sc, sc->sc_xe.sc_dev.dv_xname);
! 479: xe_init(&sc->sc_xe);
! 480: break;
! 481:
! 482: case DVACT_DEACTIVATE:
! 483: ifp->if_timer = 0;
! 484: if (ifp->if_flags & IFF_RUNNING)
! 485: xe_stop(&sc->sc_xe);
! 486: pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih);
! 487: pcmcia_function_disable(sc->sc_pf);
! 488: break;
! 489: }
! 490: splx(s);
! 491: return (0);
! 492: }
! 493:
! 494: /*
! 495: * XXX These two functions might be OK to factor out into pcmcia.c since
! 496: * if_sm_pcmcia.c uses similar ones.
! 497: */
! 498: int
! 499: xe_pcmcia_funce_enaddr(parent, myla)
! 500: struct device *parent;
! 501: u_int8_t *myla;
! 502: {
! 503: /* XXX The Linux driver has more ways to do this in case of failure. */
! 504: return (pcmcia_scan_cis(parent, xe_pcmcia_lan_nid_ciscallback, myla));
! 505: }
! 506:
! 507: int
! 508: xe_pcmcia_lan_nid_ciscallback(tuple, arg)
! 509: struct pcmcia_tuple *tuple;
! 510: void *arg;
! 511: {
! 512: u_int8_t *myla = arg;
! 513: int i;
! 514:
! 515: if (tuple->code == PCMCIA_CISTPL_FUNCE) {
! 516: if (tuple->length < 2)
! 517: return (0);
! 518:
! 519: switch (pcmcia_tuple_read_1(tuple, 0)) {
! 520: case PCMCIA_TPLFE_TYPE_LAN_NID:
! 521: if (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)
! 522: return (0);
! 523: break;
! 524:
! 525: case 0x02:
! 526: /*
! 527: * Not sure about this, I don't have a CE2
! 528: * that puts the ethernet addr here.
! 529: */
! 530: if (pcmcia_tuple_read_1(tuple, 1) != 13)
! 531: return (0);
! 532: break;
! 533:
! 534: default:
! 535: return (0);
! 536: }
! 537:
! 538: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 539: myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
! 540: return (1);
! 541: }
! 542:
! 543: /* Yet another spot where this might be. */
! 544: if (tuple->code == 0x89) {
! 545: pcmcia_tuple_read_1(tuple, 1);
! 546: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 547: myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
! 548: return (1);
! 549: }
! 550: return (0);
! 551: }
! 552:
! 553: u_int32_t
! 554: xe_pcmcia_interpret_manfid (parent)
! 555: struct device *parent;
! 556: {
! 557: u_int32_t flags = 0;
! 558: struct pcmcia_softc *psc = (struct pcmcia_softc *)parent;
! 559: char *tptr;
! 560:
! 561: if (!pcmcia_scan_cis(parent, xe_pcmcia_manfid_ciscallback, &flags))
! 562: return (XEF_UNSUPPORTED);
! 563:
! 564: if (flags & XEF_CE) {
! 565: tptr = memchr(psc->card.cis1_info[2], 'C',
! 566: strlen(psc->card.cis1_info[2]));
! 567: /* XXX not sure if other CE2s hide "CE2" in different places */
! 568: if (tptr && *(tptr + 1) == 'E' && *(tptr + 2) == '2') {
! 569: flags ^= (XEF_CE | XEF_UNSUPPORTED);
! 570: flags |= XEF_CE2;
! 571: }
! 572: }
! 573: return (flags);
! 574: }
! 575:
! 576: int
! 577: xe_pcmcia_manfid_ciscallback(tuple, arg)
! 578: struct pcmcia_tuple *tuple;
! 579: void *arg;
! 580: {
! 581: u_int32_t *flagsp = arg;
! 582: u_int8_t media, product;
! 583:
! 584: if (tuple->code == PCMCIA_CISTPL_MANFID) {
! 585: if (tuple->length < 2)
! 586: return (0);
! 587:
! 588: media = pcmcia_tuple_read_1(tuple, 3);
! 589: product = pcmcia_tuple_read_1(tuple, 4);
! 590:
! 591: if (!(product & XEPROD_CREDITCARD) ||
! 592: !(media & XEMEDIA_ETHER)) {
! 593: *flagsp |= XEF_UNSUPPORTED;
! 594: return (1);
! 595: }
! 596:
! 597: if (media & XEMEDIA_MODEM)
! 598: *flagsp |= XEF_MODEM;
! 599:
! 600: switch (product & XEPROD_IDMASK) {
! 601: case 1:
! 602: /* XXX Can be CE2 too (we double-check later). */
! 603: *flagsp |= XEF_CE | XEF_UNSUPPORTED;
! 604: break;
! 605: case 2:
! 606: *flagsp |= XEF_CE2;
! 607: break;
! 608: case 3:
! 609: if (!(*flagsp & XEF_MODEM))
! 610: *flagsp |= XEF_MOHAWK;
! 611: *flagsp |= XEF_CE3;
! 612: break;
! 613: case 4:
! 614: *flagsp |= XEF_CE33;
! 615: break;
! 616: case 5:
! 617: *flagsp |= XEF_CE56 | XEF_MOHAWK;
! 618: break;
! 619: case 6:
! 620: case 7:
! 621: *flagsp |= XEF_CE56 | XEF_MOHAWK | XEF_DINGO;
! 622: break;
! 623: default:
! 624: *flagsp |= XEF_UNSUPPORTED;
! 625: break;
! 626: }
! 627:
! 628: return (1);
! 629: }
! 630: return (0);
! 631: }
! 632:
! 633: int
! 634: xe_intr(arg)
! 635: void *arg;
! 636: {
! 637: struct xe_softc *sc = arg;
! 638: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 639: u_int8_t esr, rsr, isr, rx_status, savedpage;
! 640: u_int16_t tx_status, recvcount = 0, tempint;
! 641:
! 642: ifp->if_timer = 0; /* turn watchdog timer off */
! 643:
! 644: if (sc->sc_flags & XEF_MOHAWK) {
! 645: /* Disable interrupt (Linux does it). */
! 646: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
! 647: 0);
! 648: }
! 649:
! 650: savedpage =
! 651: bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + PR);
! 652:
! 653: PAGE(sc, 0);
! 654: esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ESR);
! 655: isr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ISR0);
! 656: rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
! 657:
! 658: /* Check to see if card has been ejected. */
! 659: if (isr == 0xff) {
! 660: printf("%s: interrupt for dead card\n", sc->sc_dev.dv_xname);
! 661: goto end;
! 662: }
! 663:
! 664: PAGE(sc, 40);
! 665: rx_status =
! 666: bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RXST0);
! 667: tx_status =
! 668: bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST0);
! 669:
! 670: /*
! 671: * XXX Linux writes to RXST0 and TXST* here. My CE2 works just fine
! 672: * without it, and I can't see an obvious reason for it.
! 673: */
! 674:
! 675: PAGE(sc, 0);
! 676: while (esr & FULL_PKT_RCV) {
! 677: if (!(rsr & RSR_RX_OK))
! 678: break;
! 679:
! 680: /* Compare bytes read this interrupt to hard maximum. */
! 681: if (recvcount > MAX_BYTES_INTR) {
! 682: DPRINTF(XED_INTR,
! 683: ("%s: too many bytes this interrupt\n",
! 684: sc->sc_dev.dv_xname));
! 685: ifp->if_iqdrops++;
! 686: /* Drop packet. */
! 687: bus_space_write_2(sc->sc_bst, sc->sc_bsh,
! 688: sc->sc_offset + DO0, DO_SKIP_RX_PKT);
! 689: }
! 690: tempint = xe_get(sc);
! 691: recvcount += tempint;
! 692: ifp->if_ibytes += tempint;
! 693: esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
! 694: sc->sc_offset + ESR);
! 695: rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
! 696: sc->sc_offset + RSR);
! 697: }
! 698:
! 699: /* Packet too long? */
! 700: if (rsr & RSR_TOO_LONG) {
! 701: ifp->if_ierrors++;
! 702: DPRINTF(XED_INTR,
! 703: ("%s: packet too long\n", sc->sc_dev.dv_xname));
! 704: }
! 705:
! 706: /* CRC error? */
! 707: if (rsr & RSR_CRCERR) {
! 708: ifp->if_ierrors++;
! 709: DPRINTF(XED_INTR,
! 710: ("%s: CRC error detected\n", sc->sc_dev.dv_xname));
! 711: }
! 712:
! 713: /* Alignment error? */
! 714: if (rsr & RSR_ALIGNERR) {
! 715: ifp->if_ierrors++;
! 716: DPRINTF(XED_INTR,
! 717: ("%s: alignment error detected\n", sc->sc_dev.dv_xname));
! 718: }
! 719:
! 720: /* Check for rx overrun. */
! 721: if (rx_status & RX_OVERRUN) {
! 722: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
! 723: CLR_RX_OVERRUN);
! 724: DPRINTF(XED_INTR, ("overrun cleared\n"));
! 725: }
! 726:
! 727: /* Try to start more packets transmitting. */
! 728: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 729: xe_start(ifp);
! 730:
! 731: /* Detected excessive collisions? */
! 732: if ((tx_status & EXCESSIVE_COLL) && ifp->if_opackets > 0) {
! 733: DPRINTF(XED_INTR,
! 734: ("%s: excessive collisions\n", sc->sc_dev.dv_xname));
! 735: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
! 736: RESTART_TX);
! 737: ifp->if_oerrors++;
! 738: }
! 739:
! 740: if ((tx_status & TX_ABORT) && ifp->if_opackets > 0)
! 741: ifp->if_oerrors++;
! 742:
! 743: end:
! 744: /* Reenable interrupts. */
! 745: PAGE(sc, savedpage);
! 746: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
! 747: ENABLE_INT);
! 748:
! 749: return (1);
! 750: }
! 751:
! 752: u_int16_t
! 753: xe_get(sc)
! 754: struct xe_softc *sc;
! 755: {
! 756: u_int8_t rsr;
! 757: struct mbuf *top, **mp, *m;
! 758: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 759: u_int16_t pktlen, len, recvcount = 0;
! 760: u_int8_t *data;
! 761:
! 762: PAGE(sc, 0);
! 763: rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
! 764:
! 765: pktlen =
! 766: bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RBC0) &
! 767: RBC_COUNT_MASK;
! 768: if (pktlen == 0) {
! 769: /*
! 770: * XXX At least one CE2 sets RBC0 == 0 occasionally, and only
! 771: * when MPE is set. It is not known why.
! 772: */
! 773: return (0);
! 774: }
! 775: recvcount += pktlen;
! 776:
! 777: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 778: if (m == 0)
! 779: return (recvcount);
! 780: m->m_pkthdr.rcvif = ifp;
! 781: m->m_pkthdr.len = pktlen;
! 782: len = MHLEN;
! 783: top = 0;
! 784: mp = ⊤
! 785:
! 786: while (pktlen > 0) {
! 787: if (top) {
! 788: MGET(m, M_DONTWAIT, MT_DATA);
! 789: if (m == 0) {
! 790: m_freem(top);
! 791: return (recvcount);
! 792: }
! 793: len = MLEN;
! 794: }
! 795: if (pktlen >= MINCLSIZE) {
! 796: MCLGET(m, M_DONTWAIT);
! 797: if (!(m->m_flags & M_EXT)) {
! 798: m_freem(m);
! 799: m_freem(top);
! 800: return (recvcount);
! 801: }
! 802: len = MCLBYTES;
! 803: }
! 804: if (!top) {
! 805: caddr_t newdata = (caddr_t)ALIGN(m->m_data +
! 806: sizeof (struct ether_header)) -
! 807: sizeof (struct ether_header);
! 808: len -= newdata - m->m_data;
! 809: m->m_data = newdata;
! 810: }
! 811: len = min(pktlen, len);
! 812:
! 813: data = mtod(m, u_int8_t *);
! 814: if (len > 1) {
! 815: len &= ~1;
! 816: bus_space_read_raw_multi_2(sc->sc_bst, sc->sc_bsh,
! 817: sc->sc_offset + EDP, data, len);
! 818: } else
! 819: *data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
! 820: sc->sc_offset + EDP);
! 821: m->m_len = len;
! 822: pktlen -= len;
! 823: *mp = m;
! 824: mp = &m->m_next;
! 825: }
! 826:
! 827: /* Skip Rx packet. */
! 828: bus_space_write_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + DO0,
! 829: DO_SKIP_RX_PKT);
! 830:
! 831: ifp->if_ipackets++;
! 832:
! 833: #if NBPFILTER > 0
! 834: if (ifp->if_bpf)
! 835: bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_IN);
! 836: #endif
! 837:
! 838: ether_input_mbuf(ifp, top);
! 839: return (recvcount);
! 840: }
! 841:
! 842:
! 843: /*
! 844: * Serial management for the MII.
! 845: * The DELAY's below stem from the fact that the maximum frequency
! 846: * acceptable on the MDC pin is 2.5 MHz and fast processors can easily
! 847: * go much faster than that.
! 848: */
! 849:
! 850: /* Let the MII serial management be idle for one period. */
! 851: static INLINE void xe_mdi_idle(struct xe_softc *);
! 852: static INLINE void
! 853: xe_mdi_idle(sc)
! 854: struct xe_softc *sc;
! 855: {
! 856: bus_space_tag_t bst = sc->sc_bst;
! 857: bus_space_handle_t bsh = sc->sc_bsh;
! 858: bus_size_t offset = sc->sc_offset;
! 859:
! 860: /* Drive MDC low... */
! 861: bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
! 862: DELAY(1);
! 863:
! 864: /* and high again. */
! 865: bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
! 866: DELAY(1);
! 867: }
! 868:
! 869: /* Pulse out one bit of data. */
! 870: static INLINE void xe_mdi_pulse(struct xe_softc *, int);
! 871: static INLINE void
! 872: xe_mdi_pulse(sc, data)
! 873: struct xe_softc *sc;
! 874: int data;
! 875: {
! 876: bus_space_tag_t bst = sc->sc_bst;
! 877: bus_space_handle_t bsh = sc->sc_bsh;
! 878: bus_size_t offset = sc->sc_offset;
! 879: u_int8_t bit = data ? MDIO_HIGH : MDIO_LOW;
! 880:
! 881: /* First latch the data bit MDIO with clock bit MDC low...*/
! 882: bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_LOW);
! 883: DELAY(1);
! 884:
! 885: /* then raise the clock again, preserving the data bit. */
! 886: bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_HIGH);
! 887: DELAY(1);
! 888: }
! 889:
! 890: /* Probe one bit of data. */
! 891: static INLINE int xe_mdi_probe(struct xe_softc *sc);
! 892: static INLINE int
! 893: xe_mdi_probe(sc)
! 894: struct xe_softc *sc;
! 895: {
! 896: bus_space_tag_t bst = sc->sc_bst;
! 897: bus_space_handle_t bsh = sc->sc_bsh;
! 898: bus_size_t offset = sc->sc_offset;
! 899: u_int8_t x;
! 900:
! 901: /* Pull clock bit MDCK low... */
! 902: bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
! 903: DELAY(1);
! 904:
! 905: /* Read data and drive clock high again. */
! 906: x = bus_space_read_1(bst, bsh, offset + GP2) & MDIO;
! 907: bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
! 908: DELAY(1);
! 909:
! 910: return (x);
! 911: }
! 912:
! 913: /* Pulse out a sequence of data bits. */
! 914: static INLINE void xe_mdi_pulse_bits(struct xe_softc *, u_int32_t, int);
! 915: static INLINE void
! 916: xe_mdi_pulse_bits(sc, data, len)
! 917: struct xe_softc *sc;
! 918: u_int32_t data;
! 919: int len;
! 920: {
! 921: u_int32_t mask;
! 922:
! 923: for (mask = 1 << (len - 1); mask; mask >>= 1)
! 924: xe_mdi_pulse(sc, data & mask);
! 925: }
! 926:
! 927: /* Read a PHY register. */
! 928: int
! 929: xe_mdi_read(self, phy, reg)
! 930: struct device *self;
! 931: int phy;
! 932: int reg;
! 933: {
! 934: struct xe_softc *sc = (struct xe_softc *)self;
! 935: int i;
! 936: u_int32_t mask;
! 937: u_int32_t data = 0;
! 938:
! 939: PAGE(sc, 2);
! 940: for (i = 0; i < 32; i++) /* Synchronize. */
! 941: xe_mdi_pulse(sc, 1);
! 942: xe_mdi_pulse_bits(sc, 0x06, 4); /* Start + Read opcode */
! 943: xe_mdi_pulse_bits(sc, phy, 5); /* PHY address */
! 944: xe_mdi_pulse_bits(sc, reg, 5); /* PHY register */
! 945: xe_mdi_idle(sc); /* Turn around. */
! 946: xe_mdi_probe(sc); /* Drop initial zero bit. */
! 947:
! 948: for (mask = 1 << 15; mask; mask >>= 1)
! 949: if (xe_mdi_probe(sc))
! 950: data |= mask;
! 951: xe_mdi_idle(sc);
! 952:
! 953: DPRINTF(XED_MII,
! 954: ("xe_mdi_read: phy %d reg %d -> %x\n", phy, reg, data));
! 955: return (data);
! 956: }
! 957:
! 958: /* Write a PHY register. */
! 959: void
! 960: xe_mdi_write(self, phy, reg, value)
! 961: struct device *self;
! 962: int phy;
! 963: int reg;
! 964: int value;
! 965: {
! 966: struct xe_softc *sc = (struct xe_softc *)self;
! 967: int i;
! 968:
! 969: PAGE(sc, 2);
! 970: for (i = 0; i < 32; i++) /* Synchronize. */
! 971: xe_mdi_pulse(sc, 1);
! 972: xe_mdi_pulse_bits(sc, 0x05, 4); /* Start + Write opcode */
! 973: xe_mdi_pulse_bits(sc, phy, 5); /* PHY address */
! 974: xe_mdi_pulse_bits(sc, reg, 5); /* PHY register */
! 975: xe_mdi_pulse_bits(sc, 0x02, 2); /* Turn around. */
! 976: xe_mdi_pulse_bits(sc, value, 16); /* Write the data */
! 977: xe_mdi_idle(sc); /* Idle away. */
! 978:
! 979: DPRINTF(XED_MII,
! 980: ("xe_mdi_write: phy %d reg %d val %x\n", phy, reg, value));
! 981: }
! 982:
! 983: void
! 984: xe_statchg(self)
! 985: struct device *self;
! 986: {
! 987: /* XXX Update ifp->if_baudrate */
! 988: }
! 989:
! 990: /*
! 991: * Change media according to request.
! 992: */
! 993: int
! 994: xe_mediachange(ifp)
! 995: struct ifnet *ifp;
! 996: {
! 997: if (ifp->if_flags & IFF_UP)
! 998: xe_init(ifp->if_softc);
! 999: return (0);
! 1000: }
! 1001:
! 1002: /*
! 1003: * Notify the world which media we're using.
! 1004: */
! 1005: void
! 1006: xe_mediastatus(ifp, ifmr)
! 1007: struct ifnet *ifp;
! 1008: struct ifmediareq *ifmr;
! 1009: {
! 1010: struct xe_softc *sc = ifp->if_softc;
! 1011:
! 1012: mii_pollstat(&sc->sc_mii);
! 1013: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 1014: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 1015: }
! 1016:
! 1017: void
! 1018: xe_reset(sc)
! 1019: struct xe_softc *sc;
! 1020: {
! 1021: int s;
! 1022:
! 1023: s = splnet();
! 1024: xe_stop(sc);
! 1025: xe_full_reset(sc);
! 1026: xe_init(sc);
! 1027: splx(s);
! 1028: }
! 1029:
! 1030: void
! 1031: xe_watchdog(ifp)
! 1032: struct ifnet *ifp;
! 1033: {
! 1034: struct xe_softc *sc = ifp->if_softc;
! 1035:
! 1036: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 1037: ++sc->sc_arpcom.ac_if.if_oerrors;
! 1038:
! 1039: xe_reset(sc);
! 1040: }
! 1041:
! 1042: void
! 1043: xe_stop(sc)
! 1044: register struct xe_softc *sc;
! 1045: {
! 1046: /* Disable interrupts. */
! 1047: PAGE(sc, 0);
! 1048: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR, 0);
! 1049:
! 1050: PAGE(sc, 1);
! 1051: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + IMR0, 0);
! 1052:
! 1053: /* Power down, wait. */
! 1054: PAGE(sc, 4);
! 1055: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + GP1, 0);
! 1056: DELAY(40000);
! 1057:
! 1058: /* Cancel watchdog timer. */
! 1059: sc->sc_arpcom.ac_if.if_timer = 0;
! 1060: }
! 1061:
! 1062: void
! 1063: xe_init(sc)
! 1064: struct xe_softc *sc;
! 1065: {
! 1066: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1067: int s;
! 1068:
! 1069: DPRINTF(XED_CONFIG, ("xe_init\n"));
! 1070:
! 1071: s = splnet();
! 1072:
! 1073: xe_set_address(sc);
! 1074:
! 1075: /* Set current media. */
! 1076: mii_mediachg(&sc->sc_mii);
! 1077:
! 1078: ifp->if_flags |= IFF_RUNNING;
! 1079: ifp->if_flags &= ~IFF_OACTIVE;
! 1080: splx(s);
! 1081: }
! 1082:
! 1083: /*
! 1084: * Start outputting on the interface.
! 1085: * Always called as splnet().
! 1086: */
! 1087: void
! 1088: xe_start(ifp)
! 1089: struct ifnet *ifp;
! 1090: {
! 1091: struct xe_softc *sc = ifp->if_softc;
! 1092: bus_space_tag_t bst = sc->sc_bst;
! 1093: bus_space_handle_t bsh = sc->sc_bsh;
! 1094: bus_size_t offset = sc->sc_offset;
! 1095: unsigned int s, len, pad = 0;
! 1096: struct mbuf *m0, *m;
! 1097: u_int16_t space;
! 1098:
! 1099: /* Don't transmit if interface is busy or not running. */
! 1100: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 1101: return;
! 1102:
! 1103: /* Peek at the next packet. */
! 1104: IFQ_POLL(&ifp->if_snd, m0);
! 1105: if (m0 == 0)
! 1106: return;
! 1107:
! 1108: /* We need to use m->m_pkthdr.len, so require the header. */
! 1109: if (!(m0->m_flags & M_PKTHDR))
! 1110: panic("xe_start: no header mbuf");
! 1111:
! 1112: len = m0->m_pkthdr.len;
! 1113:
! 1114: /* Pad to ETHER_MIN_LEN - ETHER_CRC_LEN. */
! 1115: if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
! 1116: pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
! 1117:
! 1118: PAGE(sc, 0);
! 1119: space = bus_space_read_2(bst, bsh, offset + TSO0) & 0x7fff;
! 1120: if (len + pad + 2 > space) {
! 1121: DPRINTF(XED_FIFO,
! 1122: ("%s: not enough space in output FIFO (%d > %d)\n",
! 1123: sc->sc_dev.dv_xname, len + pad + 2, space));
! 1124: return;
! 1125: }
! 1126:
! 1127: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 1128:
! 1129: #if NBPFILTER > 0
! 1130: if (ifp->if_bpf)
! 1131: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 1132: #endif
! 1133:
! 1134: /*
! 1135: * Do the output at splhigh() so that an interrupt from another device
! 1136: * won't cause a FIFO underrun.
! 1137: */
! 1138: s = splhigh();
! 1139:
! 1140: bus_space_write_2(bst, bsh, offset + TSO2, (u_int16_t)len + pad + 2);
! 1141: bus_space_write_2(bst, bsh, offset + EDP, (u_int16_t)len + pad);
! 1142: for (m = m0; m; ) {
! 1143: if (m->m_len > 1)
! 1144: bus_space_write_raw_multi_2(bst, bsh, offset + EDP,
! 1145: mtod(m, u_int8_t *), m->m_len & ~1);
! 1146: if (m->m_len & 1)
! 1147: bus_space_write_1(bst, bsh, offset + EDP,
! 1148: *(mtod(m, u_int8_t *) + m->m_len - 1));
! 1149: MFREE(m, m0);
! 1150: m = m0;
! 1151: }
! 1152: if (sc->sc_flags & XEF_MOHAWK)
! 1153: bus_space_write_1(bst, bsh, offset + CR, TX_PKT | ENABLE_INT);
! 1154: else {
! 1155: for (; pad > 1; pad -= 2)
! 1156: bus_space_write_2(bst, bsh, offset + EDP, 0);
! 1157: if (pad == 1)
! 1158: bus_space_write_1(bst, bsh, offset + EDP, 0);
! 1159: }
! 1160:
! 1161: splx(s);
! 1162:
! 1163: ifp->if_timer = 5;
! 1164: ++ifp->if_opackets;
! 1165: }
! 1166:
! 1167: int
! 1168: xe_ether_ioctl(ifp, cmd, data)
! 1169: struct ifnet *ifp;
! 1170: u_long cmd;
! 1171: caddr_t data;
! 1172: {
! 1173: struct ifaddr *ifa = (struct ifaddr *)data;
! 1174: struct xe_softc *sc = ifp->if_softc;
! 1175:
! 1176: switch (cmd) {
! 1177: case SIOCSIFADDR:
! 1178: ifp->if_flags |= IFF_UP;
! 1179:
! 1180: switch (ifa->ifa_addr->sa_family) {
! 1181: #ifdef INET
! 1182: case AF_INET:
! 1183: xe_init(sc);
! 1184: arp_ifinit(&sc->sc_arpcom, ifa);
! 1185: break;
! 1186: #endif /* INET */
! 1187:
! 1188: default:
! 1189: xe_init(sc);
! 1190: break;
! 1191: }
! 1192: break;
! 1193:
! 1194: default:
! 1195: return (EINVAL);
! 1196: }
! 1197:
! 1198: return (0);
! 1199: }
! 1200:
! 1201: int
! 1202: xe_ioctl(ifp, command, data)
! 1203: struct ifnet *ifp;
! 1204: u_long command;
! 1205: caddr_t data;
! 1206: {
! 1207: struct xe_softc *sc = ifp->if_softc;
! 1208: struct ifreq *ifr = (struct ifreq *)data;
! 1209: int s, error = 0;
! 1210:
! 1211: s = splnet();
! 1212:
! 1213: switch (command) {
! 1214: case SIOCSIFADDR:
! 1215: error = xe_ether_ioctl(ifp, command, data);
! 1216: break;
! 1217:
! 1218: case SIOCSIFFLAGS:
! 1219: sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
! 1220:
! 1221: PAGE(sc, 0x42);
! 1222: if ((ifp->if_flags & IFF_PROMISC) ||
! 1223: (ifp->if_flags & IFF_ALLMULTI))
! 1224: bus_space_write_1(sc->sc_bst, sc->sc_bsh,
! 1225: sc->sc_offset + SWC1,
! 1226: SWC1_PROMISC | SWC1_MCAST_PROM);
! 1227: else
! 1228: bus_space_write_1(sc->sc_bst, sc->sc_bsh,
! 1229: sc->sc_offset + SWC1, 0);
! 1230:
! 1231: /*
! 1232: * If interface is marked up and not running, then start it.
! 1233: * If it is marked down and running, stop it.
! 1234: * XXX If it's up then re-initialize it. This is so flags
! 1235: * such as IFF_PROMISC are handled.
! 1236: */
! 1237: if (ifp->if_flags & IFF_UP) {
! 1238: xe_init(sc);
! 1239: } else {
! 1240: if (ifp->if_flags & IFF_RUNNING)
! 1241: xe_stop(sc);
! 1242: }
! 1243: break;
! 1244:
! 1245: case SIOCADDMULTI:
! 1246: case SIOCDELMULTI:
! 1247: sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
! 1248: error = (command == SIOCADDMULTI) ?
! 1249: ether_addmulti(ifr, &sc->sc_arpcom) :
! 1250: ether_delmulti(ifr, &sc->sc_arpcom);
! 1251:
! 1252: if (error == ENETRESET) {
! 1253: /*
! 1254: * Multicast list has changed; set the hardware
! 1255: * filter accordingly.
! 1256: */
! 1257: if (!sc->sc_all_mcasts &&
! 1258: !(ifp->if_flags & IFF_PROMISC))
! 1259: xe_set_address(sc);
! 1260:
! 1261: /*
! 1262: * xe_set_address() can turn on all_mcasts if we run
! 1263: * out of space, so check it again rather than else {}.
! 1264: */
! 1265: if (sc->sc_all_mcasts)
! 1266: xe_init(sc);
! 1267: error = 0;
! 1268: }
! 1269: break;
! 1270:
! 1271: case SIOCSIFMEDIA:
! 1272: case SIOCGIFMEDIA:
! 1273: error =
! 1274: ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
! 1275: break;
! 1276:
! 1277: default:
! 1278: error = EINVAL;
! 1279: }
! 1280: splx(s);
! 1281: return (error);
! 1282: }
! 1283:
! 1284: void
! 1285: xe_set_address(sc)
! 1286: struct xe_softc *sc;
! 1287: {
! 1288: bus_space_tag_t bst = sc->sc_bst;
! 1289: bus_space_handle_t bsh = sc->sc_bsh;
! 1290: bus_size_t offset = sc->sc_offset;
! 1291: struct arpcom *arp = &sc->sc_arpcom;
! 1292: struct ether_multi *enm;
! 1293: struct ether_multistep step;
! 1294: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1295: int i, page, pos, num;
! 1296:
! 1297: PAGE(sc, 0x50);
! 1298: for (i = 0; i < 6; i++) {
! 1299: bus_space_write_1(bst, bsh, offset + IA + i,
! 1300: sc->sc_arpcom.ac_enaddr[(sc->sc_flags & XEF_MOHAWK) ?
! 1301: 5 - i : i]);
! 1302: }
! 1303:
! 1304: if (arp->ac_multicnt > 0) {
! 1305: if (arp->ac_multicnt > 9) {
! 1306: PAGE(sc, 0x42);
! 1307: bus_space_write_1(sc->sc_bst, sc->sc_bsh,
! 1308: sc->sc_offset + SWC1,
! 1309: SWC1_PROMISC | SWC1_MCAST_PROM);
! 1310: return;
! 1311: }
! 1312:
! 1313: ETHER_FIRST_MULTI(step, arp, enm);
! 1314:
! 1315: pos = IA + 6;
! 1316: for (page = 0x50, num = arp->ac_multicnt; num > 0 && enm;
! 1317: num--) {
! 1318: if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
! 1319: sizeof(enm->enm_addrlo)) != 0) {
! 1320: /*
! 1321: * The multicast address is really a range;
! 1322: * it's easier just to accept all multicasts.
! 1323: * XXX should we be setting IFF_ALLMULTI here?
! 1324: */
! 1325: ifp->if_flags |= IFF_ALLMULTI;
! 1326: sc->sc_all_mcasts=1;
! 1327: break;
! 1328: }
! 1329:
! 1330: for (i = 0; i < 6; i++) {
! 1331: bus_space_write_1(bst, bsh, offset + pos,
! 1332: enm->enm_addrlo[
! 1333: (sc->sc_flags & XEF_MOHAWK) ? 5 - i : i]);
! 1334:
! 1335: if (++pos > 15) {
! 1336: pos = IA;
! 1337: page++;
! 1338: PAGE(sc, page);
! 1339: }
! 1340: }
! 1341: }
! 1342: }
! 1343: }
! 1344:
! 1345: void
! 1346: xe_cycle_power(sc)
! 1347: struct xe_softc *sc;
! 1348: {
! 1349: bus_space_tag_t bst = sc->sc_bst;
! 1350: bus_space_handle_t bsh = sc->sc_bsh;
! 1351: bus_size_t offset = sc->sc_offset;
! 1352:
! 1353: PAGE(sc, 4);
! 1354: DELAY(1);
! 1355: bus_space_write_1(bst, bsh, offset + GP1, 0);
! 1356: DELAY(40000);
! 1357: if (sc->sc_flags & XEF_MOHAWK)
! 1358: bus_space_write_1(bst, bsh, offset + GP1, POWER_UP);
! 1359: else
! 1360: /* XXX What is bit 2 (aka AIC)? */
! 1361: bus_space_write_1(bst, bsh, offset + GP1, POWER_UP | 4);
! 1362: DELAY(20000);
! 1363: }
! 1364:
! 1365: void
! 1366: xe_full_reset(sc)
! 1367: struct xe_softc *sc;
! 1368: {
! 1369: bus_space_tag_t bst = sc->sc_bst;
! 1370: bus_space_handle_t bsh = sc->sc_bsh;
! 1371: bus_size_t offset = sc->sc_offset;
! 1372:
! 1373: /* Do an as extensive reset as possible on all functions. */
! 1374: xe_cycle_power(sc);
! 1375: bus_space_write_1(bst, bsh, offset + CR, SOFT_RESET);
! 1376: DELAY(20000);
! 1377: bus_space_write_1(bst, bsh, offset + CR, 0);
! 1378: DELAY(20000);
! 1379: if (sc->sc_flags & XEF_MOHAWK) {
! 1380: PAGE(sc, 4);
! 1381: /*
! 1382: * Drive GP1 low to power up ML6692 and GP2 high to power up
! 1383: * the 10MHz chip. XXX What chip is that? The phy?
! 1384: */
! 1385: bus_space_write_1(bst, bsh, offset + GP0,
! 1386: GP1_OUT | GP2_OUT | GP2_WR);
! 1387: }
! 1388: DELAY(500000);
! 1389:
! 1390: /* Get revision information. XXX Symbolic constants. */
! 1391: sc->sc_rev = bus_space_read_1(bst, bsh, offset + BV) &
! 1392: ((sc->sc_flags & XEF_MOHAWK) ? 0x70 : 0x30) >> 4;
! 1393:
! 1394: /* Media selection. XXX Maybe manual overriding too? */
! 1395: if (!(sc->sc_flags & XEF_MOHAWK)) {
! 1396: PAGE(sc, 4);
! 1397: /*
! 1398: * XXX I have no idea what this really does, it is from the
! 1399: * Linux driver.
! 1400: */
! 1401: bus_space_write_1(bst, bsh, offset + GP0, GP1_OUT);
! 1402: }
! 1403: DELAY(40000);
! 1404:
! 1405: /* Setup the ethernet interrupt mask. */
! 1406: PAGE(sc, 1);
! 1407: bus_space_write_1(bst, bsh, offset + IMR0,
! 1408: ISR_TX_OFLOW | ISR_PKT_TX | ISR_MAC_INT | /* ISR_RX_EARLY | */
! 1409: ISR_RX_FULL | ISR_RX_PKT_REJ | ISR_FORCED_INT);
! 1410: #if 0
! 1411: bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
! 1412: #endif
! 1413: if (!(sc->sc_flags & XEF_DINGO))
! 1414: /* XXX What is this? Not for Dingo at least. */
! 1415: bus_space_write_1(bst, bsh, offset + IMR1, 1);
! 1416:
! 1417: /*
! 1418: * Disable source insertion.
! 1419: * XXX Dingo does not have this bit, but Linux does it unconditionally.
! 1420: */
! 1421: if (!(sc->sc_flags & XEF_DINGO)) {
! 1422: PAGE(sc, 0x42);
! 1423: bus_space_write_1(bst, bsh, offset + SWC0, 0x20);
! 1424: }
! 1425:
! 1426: /* Set the local memory dividing line. */
! 1427: if (sc->sc_rev != 1) {
! 1428: PAGE(sc, 2);
! 1429: /* XXX Symbolic constant preferrable. */
! 1430: bus_space_write_2(bst, bsh, offset + RBS0, 0x2000);
! 1431: }
! 1432:
! 1433: xe_set_address(sc);
! 1434:
! 1435: /*
! 1436: * Apparently the receive byte pointer can be bad after a reset, so
! 1437: * we hardwire it correctly.
! 1438: */
! 1439: PAGE(sc, 0);
! 1440: bus_space_write_2(bst, bsh, offset + DO0, DO_CHG_OFFSET);
! 1441:
! 1442: /* Setup ethernet MAC registers. XXX Symbolic constants. */
! 1443: PAGE(sc, 0x40);
! 1444: bus_space_write_1(bst, bsh, offset + RX0MSK,
! 1445: PKT_TOO_LONG | CRC_ERR | RX_OVERRUN | RX_ABORT | RX_OK);
! 1446: bus_space_write_1(bst, bsh, offset + TX0MSK,
! 1447: CARRIER_LOST | EXCESSIVE_COLL | TX_UNDERRUN | LATE_COLLISION |
! 1448: SQE | TX_ABORT | TX_OK);
! 1449: if (!(sc->sc_flags & XEF_DINGO))
! 1450: /* XXX From Linux, dunno what 0xb0 means. */
! 1451: bus_space_write_1(bst, bsh, offset + TX1MSK, 0xb0);
! 1452: bus_space_write_1(bst, bsh, offset + RXST0, 0);
! 1453: bus_space_write_1(bst, bsh, offset + TXST0, 0);
! 1454: bus_space_write_1(bst, bsh, offset + TXST1, 0);
! 1455:
! 1456: /* Enable MII function if available. */
! 1457: if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
! 1458: PAGE(sc, 2);
! 1459: bus_space_write_1(bst, bsh, offset + MSR,
! 1460: bus_space_read_1(bst, bsh, offset + MSR) | SELECT_MII);
! 1461: DELAY(20000);
! 1462: } else {
! 1463: PAGE(sc, 0);
! 1464:
! 1465: /* XXX Do we need to do this? */
! 1466: PAGE(sc, 0x42);
! 1467: bus_space_write_1(bst, bsh, offset + SWC1, SWC1_AUTO_MEDIA);
! 1468: DELAY(50000);
! 1469:
! 1470: /* XXX Linux probes the media here. */
! 1471: }
! 1472:
! 1473: /* Configure the LED registers. */
! 1474: PAGE(sc, 2);
! 1475:
! 1476: /* XXX This is not good for 10base2. */
! 1477: bus_space_write_1(bst, bsh, offset + LED,
! 1478: LED_TX_ACT << LED1_SHIFT | LED_10MB_LINK << LED0_SHIFT);
! 1479: if (sc->sc_flags & XEF_DINGO)
! 1480: bus_space_write_1(bst, bsh, offset + LED3,
! 1481: LED_100MB_LINK << LED3_SHIFT);
! 1482:
! 1483: /* Enable receiver and go online. */
! 1484: PAGE(sc, 0x40);
! 1485: bus_space_write_1(bst, bsh, offset + CMD0, ENABLE_RX | ONLINE);
! 1486:
! 1487: #if 0
! 1488: /* XXX Linux does this here - is it necessary? */
! 1489: PAGE(sc, 1);
! 1490: bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
! 1491: if (!(sc->sc_flags & XEF_DINGO))
! 1492: /* XXX What is this? Not for Dingo at least. */
! 1493: bus_space_write_1(bst, bsh, offset + IMR1, 1);
! 1494: #endif
! 1495:
! 1496: /* Enable interrupts. */
! 1497: PAGE(sc, 0);
! 1498: bus_space_write_1(bst, bsh, offset + CR, ENABLE_INT);
! 1499:
! 1500: /* XXX This is pure magic for me, found in the Linux driver. */
! 1501: if ((sc->sc_flags & (XEF_DINGO | XEF_MODEM)) == XEF_MODEM) {
! 1502: if ((bus_space_read_1(bst, bsh, offset + 0x10) & 0x01) == 0)
! 1503: /* Unmask the master interrupt bit. */
! 1504: bus_space_write_1(bst, bsh, offset + 0x10, 0x11);
! 1505: }
! 1506:
! 1507: /*
! 1508: * The Linux driver says this:
! 1509: * We should switch back to page 0 to avoid a bug in revision 0
! 1510: * where regs with offset below 8 can't be read after an access
! 1511: * to the MAC registers.
! 1512: */
! 1513: PAGE(sc, 0);
! 1514: }
! 1515:
! 1516: #ifdef XEDEBUG
! 1517: void
! 1518: xe_reg_dump(sc)
! 1519: struct xe_softc *sc;
! 1520: {
! 1521: int page, i;
! 1522: bus_space_tag_t bst = sc->sc_bst;
! 1523: bus_space_handle_t bsh = sc->sc_bsh;
! 1524: bus_size_t offset = sc->sc_offset;
! 1525:
! 1526: printf("%x: Common registers: ", sc->sc_dev.dv_xname);
! 1527: for (i = 0; i < 8; i++) {
! 1528: printf(" %2.2x", bus_space_read_1(bst, bsh, offset + i));
! 1529: }
! 1530: printf("\n");
! 1531:
! 1532: for (page = 0; page < 8; page++) {
! 1533: printf("%s: Register page %2.2x: ", sc->sc_dev.dv_xname, page);
! 1534: PAGE(sc, page);
! 1535: for (i = 8; i < 16; i++) {
! 1536: printf(" %2.2x",
! 1537: bus_space_read_1(bst, bsh, offset + i));
! 1538: }
! 1539: printf("\n");
! 1540: }
! 1541:
! 1542: for (page = 0x40; page < 0x5f; page++) {
! 1543: if (page == 0x43 || (page >= 0x46 && page <= 0x4f) ||
! 1544: (page >= 0x51 && page <= 0x5e))
! 1545: continue;
! 1546: printf("%s: Register page %2.2x: ", sc->sc_dev.dv_xname, page);
! 1547: PAGE(sc, page);
! 1548: for (i = 8; i < 16; i++) {
! 1549: printf(" %2.2x",
! 1550: bus_space_read_1(bst, bsh, offset + i));
! 1551: }
! 1552: printf("\n");
! 1553: }
! 1554: }
! 1555: #endif /* XEDEBUG */
CVSweb