Annotation of sys/dev/pci/if_cas.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_cas.c,v 1.8 2007/04/18 21:08:35 kettenis Exp $ */
! 2:
! 3: /*
! 4: *
! 5: * Copyright (C) 2007 Mark Kettenis.
! 6: * Copyright (C) 2001 Eduardo Horvath.
! 7: * All rights reserved.
! 8: *
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
! 20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 22: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
! 23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 29: * SUCH DAMAGE.
! 30: *
! 31: */
! 32:
! 33: /*
! 34: * Driver for Sun Cassini ethernet controllers.
! 35: */
! 36:
! 37: #include "bpfilter.h"
! 38:
! 39: #include <sys/param.h>
! 40: #include <sys/systm.h>
! 41: #include <sys/timeout.h>
! 42: #include <sys/mbuf.h>
! 43: #include <sys/syslog.h>
! 44: #include <sys/malloc.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/socket.h>
! 47: #include <sys/ioctl.h>
! 48: #include <sys/errno.h>
! 49: #include <sys/device.h>
! 50:
! 51: #include <machine/endian.h>
! 52:
! 53: #include <net/if.h>
! 54: #include <net/if_dl.h>
! 55: #include <net/if_media.h>
! 56:
! 57: #ifdef INET
! 58: #include <netinet/in.h>
! 59: #include <netinet/if_ether.h>
! 60: #endif
! 61:
! 62: #if NBPFILTER > 0
! 63: #include <net/bpf.h>
! 64: #endif
! 65:
! 66: #include <machine/bus.h>
! 67: #include <machine/intr.h>
! 68:
! 69: #include <dev/mii/mii.h>
! 70: #include <dev/mii/miivar.h>
! 71: #include <dev/mii/mii_bitbang.h>
! 72:
! 73: #include <dev/pci/if_casreg.h>
! 74: #include <dev/pci/if_casvar.h>
! 75:
! 76: #include <dev/pci/pcivar.h>
! 77: #include <dev/pci/pcireg.h>
! 78: #include <dev/pci/pcidevs.h>
! 79:
! 80: #ifdef __sparc64__
! 81: #include <dev/ofw/openfirm.h>
! 82: #endif
! 83:
! 84: #define TRIES 10000
! 85:
! 86: struct cfdriver cas_cd = {
! 87: NULL, "cas", DV_IFNET
! 88: };
! 89:
! 90: int cas_match(struct device *, void *, void *);
! 91: void cas_attach(struct device *, struct device *, void *);
! 92: int cas_pci_enaddr(struct cas_softc *, struct pci_attach_args *);
! 93:
! 94: struct cfattach cas_ca = {
! 95: sizeof(struct cas_softc), cas_match, cas_attach
! 96: };
! 97:
! 98: void cas_config(struct cas_softc *);
! 99: void cas_start(struct ifnet *);
! 100: void cas_stop(struct ifnet *, int);
! 101: int cas_ioctl(struct ifnet *, u_long, caddr_t);
! 102: void cas_tick(void *);
! 103: void cas_watchdog(struct ifnet *);
! 104: void cas_shutdown(void *);
! 105: int cas_init(struct ifnet *);
! 106: void cas_init_regs(struct cas_softc *);
! 107: int cas_ringsize(int);
! 108: int cas_cringsize(int);
! 109: int cas_meminit(struct cas_softc *);
! 110: void cas_mifinit(struct cas_softc *);
! 111: int cas_bitwait(struct cas_softc *, bus_space_handle_t, int,
! 112: u_int32_t, u_int32_t);
! 113: void cas_reset(struct cas_softc *);
! 114: int cas_reset_rx(struct cas_softc *);
! 115: int cas_reset_tx(struct cas_softc *);
! 116: int cas_disable_rx(struct cas_softc *);
! 117: int cas_disable_tx(struct cas_softc *);
! 118: void cas_rxdrain(struct cas_softc *);
! 119: int cas_add_rxbuf(struct cas_softc *, int idx);
! 120: void cas_setladrf(struct cas_softc *);
! 121: int cas_encap(struct cas_softc *, struct mbuf *, u_int32_t *);
! 122:
! 123: /* MII methods & callbacks */
! 124: int cas_mii_readreg(struct device *, int, int);
! 125: void cas_mii_writereg(struct device *, int, int, int);
! 126: void cas_mii_statchg(struct device *);
! 127: int cas_pcs_readreg(struct device *, int, int);
! 128: void cas_pcs_writereg(struct device *, int, int, int);
! 129:
! 130: int cas_mediachange(struct ifnet *);
! 131: void cas_mediastatus(struct ifnet *, struct ifmediareq *);
! 132:
! 133: int cas_eint(struct cas_softc *, u_int);
! 134: int cas_rint(struct cas_softc *);
! 135: int cas_tint(struct cas_softc *, u_int32_t);
! 136: int cas_pint(struct cas_softc *);
! 137: int cas_intr(void *);
! 138:
! 139: #ifdef CAS_DEBUG
! 140: #define DPRINTF(sc, x) if ((sc)->sc_arpcom.ac_if.if_flags & IFF_DEBUG) \
! 141: printf x
! 142: #else
! 143: #define DPRINTF(sc, x) /* nothing */
! 144: #endif
! 145:
! 146: const struct pci_matchid cas_pci_devices[] = {
! 147: { PCI_VENDOR_SUN, PCI_PRODUCT_SUN_CASSINI }
! 148: };
! 149:
! 150: int
! 151: cas_match(struct device *parent, void *cf, void *aux)
! 152: {
! 153: return (pci_matchbyid((struct pci_attach_args *)aux, cas_pci_devices,
! 154: sizeof(cas_pci_devices)/sizeof(cas_pci_devices[0])));
! 155: }
! 156:
! 157: #define PROMHDR_PTR_DATA 0x18
! 158: #define PROMDATA_PTR_VPD 0x08
! 159: #define PROMDATA_DATA2 0x0a
! 160:
! 161: static const u_int8_t cas_promhdr[] = { 0x55, 0xaa };
! 162: static const u_int8_t cas_promdat[] = {
! 163: 'P', 'C', 'I', 'R',
! 164: PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8,
! 165: PCI_PRODUCT_SUN_CASSINI & 0xff, PCI_PRODUCT_SUN_CASSINI >> 8
! 166: };
! 167:
! 168: static const u_int8_t cas_promdat2[] = {
! 169: 0x18, 0x00, /* structure length */
! 170: 0x00, /* structure revision */
! 171: 0x00, /* interface revision */
! 172: PCI_SUBCLASS_NETWORK_ETHERNET, /* subclass code */
! 173: PCI_CLASS_NETWORK /* class code */
! 174: };
! 175:
! 176: int
! 177: cas_pci_enaddr(struct cas_softc *sc, struct pci_attach_args *pa)
! 178: {
! 179: struct pci_vpd_largeres *res;
! 180: struct pci_vpd *vpd;
! 181: bus_space_handle_t romh;
! 182: bus_space_tag_t romt;
! 183: bus_size_t romsize;
! 184: u_int8_t buf[32], *desc;
! 185: pcireg_t address, mask;
! 186: int dataoff, vpdoff, len;
! 187: int rv = -1;
! 188:
! 189: address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
! 190: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe);
! 191: mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
! 192: address |= PCI_ROM_ENABLE;
! 193: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
! 194:
! 195: romt = pa->pa_memt;
! 196: romsize = PCI_ROM_SIZE(mask);
! 197: if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) {
! 198: romsize = 0;
! 199: goto fail;
! 200: }
! 201:
! 202: bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf));
! 203: if (bcmp(buf, cas_promhdr, sizeof(cas_promhdr)))
! 204: goto fail;
! 205:
! 206: dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8);
! 207: if (dataoff < 0x1c)
! 208: goto fail;
! 209:
! 210: bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf));
! 211: if (bcmp(buf, cas_promdat, sizeof(cas_promdat)) ||
! 212: bcmp(buf + PROMDATA_DATA2, cas_promdat2, sizeof(cas_promdat2)))
! 213: goto fail;
! 214:
! 215: vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8);
! 216: if (vpdoff < 0x1c)
! 217: goto fail;
! 218:
! 219: next:
! 220: bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf));
! 221: if (!PCI_VPDRES_ISLARGE(buf[0]))
! 222: goto fail;
! 223:
! 224: res = (struct pci_vpd_largeres *)buf;
! 225: vpdoff += sizeof(*res);
! 226:
! 227: len = ((res->vpdres_len_msb << 8) + res->vpdres_len_lsb);
! 228: switch(PCI_VPDRES_LARGE_NAME(res->vpdres_byte0)) {
! 229: case PCI_VPDRES_TYPE_IDENTIFIER_STRING:
! 230: /* Skip identifier string. */
! 231: vpdoff += len;
! 232: goto next;
! 233:
! 234: case PCI_VPDRES_TYPE_VPD:
! 235: while (len > 0) {
! 236: bus_space_read_region_1(romt, romh, vpdoff,
! 237: buf, sizeof(buf));
! 238:
! 239: vpd = (struct pci_vpd *)buf;
! 240: vpdoff += sizeof(*vpd) + vpd->vpd_len;
! 241: len -= sizeof(*vpd) + vpd->vpd_len;
! 242:
! 243: /*
! 244: * We're looking for an "Enhanced" VPD...
! 245: */
! 246: if (vpd->vpd_key0 != 'Z')
! 247: continue;
! 248:
! 249: desc = buf + sizeof(*vpd);
! 250:
! 251: /*
! 252: * ...which is an instance property...
! 253: */
! 254: if (desc[0] != 'I')
! 255: continue;
! 256: desc += 3;
! 257:
! 258: /*
! 259: * ...that's a byte array with the proper
! 260: * length for a MAC address...
! 261: */
! 262: if (desc[0] != 'B' || desc[1] != ETHER_ADDR_LEN)
! 263: continue;
! 264: desc += 2;
! 265:
! 266: /*
! 267: * ...named "local-mac-address".
! 268: */
! 269: if (strcmp(desc, "local-mac-address") != 0)
! 270: continue;
! 271: desc += strlen("local-mac-address") + 1;
! 272:
! 273: bcopy(desc, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
! 274: rv = 0;
! 275: }
! 276: break;
! 277:
! 278: default:
! 279: goto fail;
! 280: }
! 281:
! 282: fail:
! 283: if (romsize != 0)
! 284: bus_space_unmap(romt, romh, romsize);
! 285:
! 286: address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
! 287: address &= ~PCI_ROM_ENABLE;
! 288: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
! 289:
! 290: return (rv);
! 291: }
! 292:
! 293: void
! 294: cas_attach(struct device *parent, struct device *self, void *aux)
! 295: {
! 296: struct pci_attach_args *pa = aux;
! 297: struct cas_softc *sc = (void *)self;
! 298: pci_intr_handle_t ih;
! 299: #ifdef __sparc64__
! 300: /* XXX the following declarations should be elsewhere */
! 301: extern void myetheraddr(u_char *);
! 302: #endif
! 303: const char *intrstr = NULL;
! 304: bus_size_t size;
! 305: int gotenaddr = 0;
! 306:
! 307: sc->sc_dmatag = pa->pa_dmat;
! 308:
! 309: #define PCI_CAS_BASEADDR 0x10
! 310: if (pci_mapreg_map(pa, PCI_CAS_BASEADDR, PCI_MAPREG_TYPE_MEM, 0,
! 311: &sc->sc_memt, &sc->sc_memh, NULL, &size, 0) != 0) {
! 312: printf(": could not map registers\n");
! 313: return;
! 314: }
! 315:
! 316: if (cas_pci_enaddr(sc, pa) == 0)
! 317: gotenaddr = 1;
! 318:
! 319: #ifdef __sparc64__
! 320: if (!gotenaddr) {
! 321: if (OF_getprop(PCITAG_NODE(pa->pa_tag), "local-mac-address",
! 322: sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN) <= 0)
! 323: myetheraddr(sc->sc_arpcom.ac_enaddr);
! 324: gotenaddr = 1;
! 325: }
! 326: #endif
! 327: #ifdef __powerpc__
! 328: if (!gotenaddr) {
! 329: pci_ether_hw_addr(pa->pa_pc, sc->sc_arpcom.ac_enaddr);
! 330: gotenaddr = 1;
! 331: }
! 332: #endif
! 333:
! 334: sc->sc_burst = 16; /* XXX */
! 335:
! 336: if (pci_intr_map(pa, &ih) != 0) {
! 337: printf(": couldn't map interrupt\n");
! 338: bus_space_unmap(sc->sc_memt, sc->sc_memh, size);
! 339: return;
! 340: }
! 341: intrstr = pci_intr_string(pa->pa_pc, ih);
! 342: sc->sc_ih = pci_intr_establish(pa->pa_pc,
! 343: ih, IPL_NET, cas_intr, sc, self->dv_xname);
! 344: if (sc->sc_ih == NULL) {
! 345: printf(": couldn't establish interrupt");
! 346: if (intrstr != NULL)
! 347: printf(" at %s", intrstr);
! 348: printf("\n");
! 349: bus_space_unmap(sc->sc_memt, sc->sc_memh, size);
! 350: return;
! 351: }
! 352:
! 353: printf(": %s", intrstr);
! 354:
! 355: /*
! 356: * call the main configure
! 357: */
! 358: cas_config(sc);
! 359: }
! 360:
! 361: /*
! 362: * cas_config:
! 363: *
! 364: * Attach a Cassini interface to the system.
! 365: */
! 366: void
! 367: cas_config(struct cas_softc *sc)
! 368: {
! 369: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 370: struct mii_data *mii = &sc->sc_mii;
! 371: struct mii_softc *child;
! 372: int i, error;
! 373:
! 374: /* Make sure the chip is stopped. */
! 375: ifp->if_softc = sc;
! 376: cas_reset(sc);
! 377:
! 378: /*
! 379: * Allocate the control data structures, and create and load the
! 380: * DMA map for it.
! 381: */
! 382: if ((error = bus_dmamem_alloc(sc->sc_dmatag,
! 383: sizeof(struct cas_control_data), CAS_PAGE_SIZE, 0, &sc->sc_cdseg,
! 384: 1, &sc->sc_cdnseg, 0)) != 0) {
! 385: printf("\n%s: unable to allocate control data, error = %d\n",
! 386: sc->sc_dev.dv_xname, error);
! 387: goto fail_0;
! 388: }
! 389:
! 390: /* XXX should map this in with correct endianness */
! 391: if ((error = bus_dmamem_map(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg,
! 392: sizeof(struct cas_control_data), (caddr_t *)&sc->sc_control_data,
! 393: BUS_DMA_COHERENT)) != 0) {
! 394: printf("\n%s: unable to map control data, error = %d\n",
! 395: sc->sc_dev.dv_xname, error);
! 396: goto fail_1;
! 397: }
! 398:
! 399: if ((error = bus_dmamap_create(sc->sc_dmatag,
! 400: sizeof(struct cas_control_data), 1,
! 401: sizeof(struct cas_control_data), 0, 0, &sc->sc_cddmamap)) != 0) {
! 402: printf("\n%s: unable to create control data DMA map, "
! 403: "error = %d\n", sc->sc_dev.dv_xname, error);
! 404: goto fail_2;
! 405: }
! 406:
! 407: if ((error = bus_dmamap_load(sc->sc_dmatag, sc->sc_cddmamap,
! 408: sc->sc_control_data, sizeof(struct cas_control_data), NULL,
! 409: 0)) != 0) {
! 410: printf("\n%s: unable to load control data DMA map, error = %d\n",
! 411: sc->sc_dev.dv_xname, error);
! 412: goto fail_3;
! 413: }
! 414:
! 415: /*
! 416: * Create the receive buffer DMA maps.
! 417: */
! 418: for (i = 0; i < CAS_NRXDESC; i++) {
! 419: bus_dma_segment_t seg;
! 420: caddr_t kva;
! 421: int rseg;
! 422:
! 423: if ((error = bus_dmamem_alloc(sc->sc_dmatag, CAS_PAGE_SIZE,
! 424: CAS_PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
! 425: printf("\n%s: unable to alloc rx DMA mem %d, "
! 426: "error = %d\n", sc->sc_dev.dv_xname, i, error);
! 427: goto fail_5;
! 428: }
! 429: sc->sc_rxsoft[i].rxs_dmaseg = seg;
! 430:
! 431: if ((error = bus_dmamem_map(sc->sc_dmatag, &seg, rseg,
! 432: CAS_PAGE_SIZE, &kva, BUS_DMA_NOWAIT)) != 0) {
! 433: printf("\n%s: unable to alloc rx DMA mem %d, "
! 434: "error = %d\n", sc->sc_dev.dv_xname, i, error);
! 435: goto fail_5;
! 436: }
! 437: sc->sc_rxsoft[i].rxs_kva = kva;
! 438:
! 439: if ((error = bus_dmamap_create(sc->sc_dmatag, CAS_PAGE_SIZE, 1,
! 440: CAS_PAGE_SIZE, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) {
! 441: printf("\n%s: unable to create rx DMA map %d, "
! 442: "error = %d\n", sc->sc_dev.dv_xname, i, error);
! 443: goto fail_5;
! 444: }
! 445:
! 446: if ((error = bus_dmamap_load(sc->sc_dmatag,
! 447: sc->sc_rxsoft[i].rxs_dmamap, kva, CAS_PAGE_SIZE, NULL,
! 448: BUS_DMA_NOWAIT)) != 0) {
! 449: printf("\n%s: unable to load rx DMA map %d, "
! 450: "error = %d\n", sc->sc_dev.dv_xname, i, error);
! 451: goto fail_5;
! 452: }
! 453: }
! 454:
! 455: /*
! 456: * Create the transmit buffer DMA maps.
! 457: */
! 458: for (i = 0; i < CAS_NTXDESC; i++) {
! 459: if ((error = bus_dmamap_create(sc->sc_dmatag, MCLBYTES,
! 460: CAS_NTXSEGS, MCLBYTES, 0, BUS_DMA_NOWAIT,
! 461: &sc->sc_txd[i].sd_map)) != 0) {
! 462: printf("\n%s: unable to create tx DMA map %d, "
! 463: "error = %d\n", sc->sc_dev.dv_xname, i, error);
! 464: goto fail_6;
! 465: }
! 466: sc->sc_txd[i].sd_mbuf = NULL;
! 467: }
! 468:
! 469: /*
! 470: * From this point forward, the attachment cannot fail. A failure
! 471: * before this point releases all resources that may have been
! 472: * allocated.
! 473: */
! 474:
! 475: /* Announce ourselves. */
! 476: printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 477:
! 478: /* Get RX FIFO size */
! 479: sc->sc_rxfifosize = 16 * 1024;
! 480:
! 481: /* Initialize ifnet structure. */
! 482: strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname);
! 483: ifp->if_softc = sc;
! 484: ifp->if_flags =
! 485: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 486: ifp->if_start = cas_start;
! 487: ifp->if_ioctl = cas_ioctl;
! 488: ifp->if_watchdog = cas_watchdog;
! 489: IFQ_SET_MAXLEN(&ifp->if_snd, CAS_NTXDESC - 1);
! 490: IFQ_SET_READY(&ifp->if_snd);
! 491:
! 492: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 493:
! 494: /* Initialize ifmedia structures and MII info */
! 495: mii->mii_ifp = ifp;
! 496: mii->mii_readreg = cas_mii_readreg;
! 497: mii->mii_writereg = cas_mii_writereg;
! 498: mii->mii_statchg = cas_mii_statchg;
! 499:
! 500: ifmedia_init(&mii->mii_media, 0, cas_mediachange, cas_mediastatus);
! 501:
! 502: bus_space_write_4(sc->sc_memt, sc->sc_memh, CAS_MII_DATAPATH_MODE, 0);
! 503:
! 504: cas_mifinit(sc);
! 505:
! 506: if (sc->sc_mif_config & CAS_MIF_CONFIG_MDI1) {
! 507: sc->sc_mif_config |= CAS_MIF_CONFIG_PHY_SEL;
! 508: bus_space_write_4(sc->sc_memt, sc->sc_memh,
! 509: CAS_MIF_CONFIG, sc->sc_mif_config);
! 510: }
! 511:
! 512: mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,
! 513: MII_OFFSET_ANY, 0);
! 514:
! 515: child = LIST_FIRST(&mii->mii_phys);
! 516: if (child == NULL &&
! 517: sc->sc_mif_config & (CAS_MIF_CONFIG_MDI0|CAS_MIF_CONFIG_MDI1)) {
! 518: /*
! 519: * Try the external PCS SERDES if we didn't find any
! 520: * MII devices.
! 521: */
! 522: bus_space_write_4(sc->sc_memt, sc->sc_memh,
! 523: CAS_MII_DATAPATH_MODE, CAS_MII_DATAPATH_SERDES);
! 524:
! 525: bus_space_write_4(sc->sc_memt, sc->sc_memh,
! 526: CAS_MII_SLINK_CONTROL,
! 527: CAS_MII_SLINK_LOOPBACK|CAS_MII_SLINK_EN_SYNC_D);
! 528:
! 529: bus_space_write_4(sc->sc_memt, sc->sc_memh,
! 530: CAS_MII_CONFIG, CAS_MII_CONFIG_ENABLE);
! 531:
! 532: mii->mii_readreg = cas_pcs_readreg;
! 533: mii->mii_writereg = cas_pcs_writereg;
! 534:
! 535: mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,
! 536: MII_OFFSET_ANY, MIIF_NOISOLATE);
! 537: }
! 538:
! 539: child = LIST_FIRST(&mii->mii_phys);
! 540: if (child == NULL) {
! 541: /* No PHY attached */
! 542: ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
! 543: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
! 544: } else {
! 545: /*
! 546: * Walk along the list of attached MII devices and
! 547: * establish an `MII instance' to `phy number'
! 548: * mapping. We'll use this mapping in media change
! 549: * requests to determine which phy to use to program
! 550: * the MIF configuration register.
! 551: */
! 552: for (; child != NULL; child = LIST_NEXT(child, mii_list)) {
! 553: /*
! 554: * Note: we support just two PHYs: the built-in
! 555: * internal device and an external on the MII
! 556: * connector.
! 557: */
! 558: if (child->mii_phy > 1 || child->mii_inst > 1) {
! 559: printf("%s: cannot accommodate MII device %s"
! 560: " at phy %d, instance %d\n",
! 561: sc->sc_dev.dv_xname,
! 562: child->mii_dev.dv_xname,
! 563: child->mii_phy, child->mii_inst);
! 564: continue;
! 565: }
! 566:
! 567: sc->sc_phys[child->mii_inst] = child->mii_phy;
! 568: }
! 569:
! 570: /*
! 571: * XXX - we can really do the following ONLY if the
! 572: * phy indeed has the auto negotiation capability!!
! 573: */
! 574: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
! 575: }
! 576:
! 577: /* Attach the interface. */
! 578: if_attach(ifp);
! 579: ether_ifattach(ifp);
! 580:
! 581: sc->sc_sh = shutdownhook_establish(cas_shutdown, sc);
! 582: if (sc->sc_sh == NULL)
! 583: panic("cas_config: can't establish shutdownhook");
! 584:
! 585: timeout_set(&sc->sc_tick_ch, cas_tick, sc);
! 586: return;
! 587:
! 588: /*
! 589: * Free any resources we've allocated during the failed attach
! 590: * attempt. Do this in reverse order and fall through.
! 591: */
! 592: fail_6:
! 593: for (i = 0; i < CAS_NTXDESC; i++) {
! 594: if (sc->sc_txd[i].sd_map != NULL)
! 595: bus_dmamap_destroy(sc->sc_dmatag,
! 596: sc->sc_txd[i].sd_map);
! 597: }
! 598: fail_5:
! 599: for (i = 0; i < CAS_NRXDESC; i++) {
! 600: if (sc->sc_rxsoft[i].rxs_dmamap != NULL)
! 601: bus_dmamap_destroy(sc->sc_dmatag,
! 602: sc->sc_rxsoft[i].rxs_dmamap);
! 603: }
! 604: bus_dmamap_unload(sc->sc_dmatag, sc->sc_cddmamap);
! 605: fail_3:
! 606: bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cddmamap);
! 607: fail_2:
! 608: bus_dmamem_unmap(sc->sc_dmatag, (caddr_t)sc->sc_control_data,
! 609: sizeof(struct cas_control_data));
! 610: fail_1:
! 611: bus_dmamem_free(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg);
! 612: fail_0:
! 613: return;
! 614: }
! 615:
! 616:
! 617: void
! 618: cas_tick(void *arg)
! 619: {
! 620: struct cas_softc *sc = arg;
! 621: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 622: bus_space_tag_t t = sc->sc_memt;
! 623: bus_space_handle_t mac = sc->sc_memh;
! 624: int s;
! 625:
! 626: /* unload collisions counters */
! 627: ifp->if_collisions +=
! 628: bus_space_read_4(t, mac, CAS_MAC_NORM_COLL_CNT) +
! 629: bus_space_read_4(t, mac, CAS_MAC_FIRST_COLL_CNT) +
! 630: bus_space_read_4(t, mac, CAS_MAC_EXCESS_COLL_CNT) +
! 631: bus_space_read_4(t, mac, CAS_MAC_LATE_COLL_CNT);
! 632:
! 633: /* clear the hardware counters */
! 634: bus_space_write_4(t, mac, CAS_MAC_NORM_COLL_CNT, 0);
! 635: bus_space_write_4(t, mac, CAS_MAC_FIRST_COLL_CNT, 0);
! 636: bus_space_write_4(t, mac, CAS_MAC_EXCESS_COLL_CNT, 0);
! 637: bus_space_write_4(t, mac, CAS_MAC_LATE_COLL_CNT, 0);
! 638:
! 639: s = splnet();
! 640: mii_tick(&sc->sc_mii);
! 641: splx(s);
! 642:
! 643: timeout_add(&sc->sc_tick_ch, hz);
! 644: }
! 645:
! 646: int
! 647: cas_bitwait(struct cas_softc *sc, bus_space_handle_t h, int r,
! 648: u_int32_t clr, u_int32_t set)
! 649: {
! 650: int i;
! 651: u_int32_t reg;
! 652:
! 653: for (i = TRIES; i--; DELAY(100)) {
! 654: reg = bus_space_read_4(sc->sc_memt, h, r);
! 655: if ((reg & clr) == 0 && (reg & set) == set)
! 656: return (1);
! 657: }
! 658:
! 659: return (0);
! 660: }
! 661:
! 662: void
! 663: cas_reset(struct cas_softc *sc)
! 664: {
! 665: bus_space_tag_t t = sc->sc_memt;
! 666: bus_space_handle_t h = sc->sc_memh;
! 667: int s;
! 668:
! 669: s = splnet();
! 670: DPRINTF(sc, ("%s: cas_reset\n", sc->sc_dev.dv_xname));
! 671: cas_reset_rx(sc);
! 672: cas_reset_tx(sc);
! 673:
! 674: /* Do a full reset */
! 675: bus_space_write_4(t, h, CAS_RESET, CAS_RESET_RX|CAS_RESET_TX);
! 676: if (!cas_bitwait(sc, h, CAS_RESET, CAS_RESET_RX | CAS_RESET_TX, 0))
! 677: printf("%s: cannot reset device\n", sc->sc_dev.dv_xname);
! 678: splx(s);
! 679: }
! 680:
! 681:
! 682: /*
! 683: * cas_rxdrain:
! 684: *
! 685: * Drain the receive queue.
! 686: */
! 687: void
! 688: cas_rxdrain(struct cas_softc *sc)
! 689: {
! 690: /* Nothing to do yet. */
! 691: }
! 692:
! 693: /*
! 694: * Reset the whole thing.
! 695: */
! 696: void
! 697: cas_stop(struct ifnet *ifp, int disable)
! 698: {
! 699: struct cas_softc *sc = (struct cas_softc *)ifp->if_softc;
! 700: struct cas_sxd *sd;
! 701: u_int32_t i;
! 702:
! 703: DPRINTF(sc, ("%s: cas_stop\n", sc->sc_dev.dv_xname));
! 704:
! 705: timeout_del(&sc->sc_tick_ch);
! 706:
! 707: /*
! 708: * Mark the interface down and cancel the watchdog timer.
! 709: */
! 710: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 711: ifp->if_timer = 0;
! 712:
! 713: mii_down(&sc->sc_mii);
! 714:
! 715: cas_reset_rx(sc);
! 716: cas_reset_tx(sc);
! 717:
! 718: /*
! 719: * Release any queued transmit buffers.
! 720: */
! 721: for (i = 0; i < CAS_NTXDESC; i++) {
! 722: sd = &sc->sc_txd[i];
! 723: if (sd->sd_mbuf != NULL) {
! 724: bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0,
! 725: sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 726: bus_dmamap_unload(sc->sc_dmatag, sd->sd_map);
! 727: m_freem(sd->sd_mbuf);
! 728: sd->sd_mbuf = NULL;
! 729: }
! 730: }
! 731: sc->sc_tx_cnt = sc->sc_tx_prod = sc->sc_tx_cons = 0;
! 732:
! 733: if (disable)
! 734: cas_rxdrain(sc);
! 735: }
! 736:
! 737:
! 738: /*
! 739: * Reset the receiver
! 740: */
! 741: int
! 742: cas_reset_rx(struct cas_softc *sc)
! 743: {
! 744: bus_space_tag_t t = sc->sc_memt;
! 745: bus_space_handle_t h = sc->sc_memh;
! 746:
! 747: /*
! 748: * Resetting while DMA is in progress can cause a bus hang, so we
! 749: * disable DMA first.
! 750: */
! 751: cas_disable_rx(sc);
! 752: bus_space_write_4(t, h, CAS_RX_CONFIG, 0);
! 753: /* Wait till it finishes */
! 754: if (!cas_bitwait(sc, h, CAS_RX_CONFIG, 1, 0))
! 755: printf("%s: cannot disable rx dma\n", sc->sc_dev.dv_xname);
! 756: /* Wait 5ms extra. */
! 757: delay(5000);
! 758:
! 759: /* Finally, reset the ERX */
! 760: bus_space_write_4(t, h, CAS_RESET, CAS_RESET_RX);
! 761: /* Wait till it finishes */
! 762: if (!cas_bitwait(sc, h, CAS_RESET, CAS_RESET_RX, 0)) {
! 763: printf("%s: cannot reset receiver\n", sc->sc_dev.dv_xname);
! 764: return (1);
! 765: }
! 766: return (0);
! 767: }
! 768:
! 769:
! 770: /*
! 771: * Reset the transmitter
! 772: */
! 773: int
! 774: cas_reset_tx(struct cas_softc *sc)
! 775: {
! 776: bus_space_tag_t t = sc->sc_memt;
! 777: bus_space_handle_t h = sc->sc_memh;
! 778:
! 779: /*
! 780: * Resetting while DMA is in progress can cause a bus hang, so we
! 781: * disable DMA first.
! 782: */
! 783: cas_disable_tx(sc);
! 784: bus_space_write_4(t, h, CAS_TX_CONFIG, 0);
! 785: /* Wait till it finishes */
! 786: if (!cas_bitwait(sc, h, CAS_TX_CONFIG, 1, 0))
! 787: printf("%s: cannot disable tx dma\n", sc->sc_dev.dv_xname);
! 788: /* Wait 5ms extra. */
! 789: delay(5000);
! 790:
! 791: /* Finally, reset the ETX */
! 792: bus_space_write_4(t, h, CAS_RESET, CAS_RESET_TX);
! 793: /* Wait till it finishes */
! 794: if (!cas_bitwait(sc, h, CAS_RESET, CAS_RESET_TX, 0)) {
! 795: printf("%s: cannot reset transmitter\n",
! 796: sc->sc_dev.dv_xname);
! 797: return (1);
! 798: }
! 799: return (0);
! 800: }
! 801:
! 802: /*
! 803: * disable receiver.
! 804: */
! 805: int
! 806: cas_disable_rx(struct cas_softc *sc)
! 807: {
! 808: bus_space_tag_t t = sc->sc_memt;
! 809: bus_space_handle_t h = sc->sc_memh;
! 810: u_int32_t cfg;
! 811:
! 812: /* Flip the enable bit */
! 813: cfg = bus_space_read_4(t, h, CAS_MAC_RX_CONFIG);
! 814: cfg &= ~CAS_MAC_RX_ENABLE;
! 815: bus_space_write_4(t, h, CAS_MAC_RX_CONFIG, cfg);
! 816:
! 817: /* Wait for it to finish */
! 818: return (cas_bitwait(sc, h, CAS_MAC_RX_CONFIG, CAS_MAC_RX_ENABLE, 0));
! 819: }
! 820:
! 821: /*
! 822: * disable transmitter.
! 823: */
! 824: int
! 825: cas_disable_tx(struct cas_softc *sc)
! 826: {
! 827: bus_space_tag_t t = sc->sc_memt;
! 828: bus_space_handle_t h = sc->sc_memh;
! 829: u_int32_t cfg;
! 830:
! 831: /* Flip the enable bit */
! 832: cfg = bus_space_read_4(t, h, CAS_MAC_TX_CONFIG);
! 833: cfg &= ~CAS_MAC_TX_ENABLE;
! 834: bus_space_write_4(t, h, CAS_MAC_TX_CONFIG, cfg);
! 835:
! 836: /* Wait for it to finish */
! 837: return (cas_bitwait(sc, h, CAS_MAC_TX_CONFIG, CAS_MAC_TX_ENABLE, 0));
! 838: }
! 839:
! 840: /*
! 841: * Initialize interface.
! 842: */
! 843: int
! 844: cas_meminit(struct cas_softc *sc)
! 845: {
! 846: struct cas_rxsoft *rxs;
! 847: int i, error;
! 848:
! 849: rxs = (void *)&error;
! 850:
! 851: /*
! 852: * Initialize the transmit descriptor ring.
! 853: */
! 854: for (i = 0; i < CAS_NTXDESC; i++) {
! 855: sc->sc_txdescs[i].cd_flags = 0;
! 856: sc->sc_txdescs[i].cd_addr = 0;
! 857: }
! 858: CAS_CDTXSYNC(sc, 0, CAS_NTXDESC,
! 859: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 860:
! 861: /*
! 862: * Initialize the receive descriptor and receive job
! 863: * descriptor rings.
! 864: */
! 865: for (i = 0; i < CAS_NRXDESC; i++)
! 866: CAS_INIT_RXDESC(sc, i, i);
! 867: sc->sc_rxdptr = 0;
! 868: sc->sc_rxptr = 0;
! 869:
! 870: /*
! 871: * Initialize the receive completion ring.
! 872: */
! 873: for (i = 0; i < CAS_NRXCOMP; i++) {
! 874: sc->sc_rxcomps[i].cc_word[0] = 0;
! 875: sc->sc_rxcomps[i].cc_word[1] = 0;
! 876: sc->sc_rxcomps[i].cc_word[2] = 0;
! 877: sc->sc_rxcomps[i].cc_word[3] = CAS_DMA_WRITE(CAS_RC3_OWN);
! 878: CAS_CDRXCSYNC(sc, i,
! 879: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 880: }
! 881:
! 882: return (0);
! 883: }
! 884:
! 885: int
! 886: cas_ringsize(int sz)
! 887: {
! 888: switch (sz) {
! 889: case 32:
! 890: return CAS_RING_SZ_32;
! 891: case 64:
! 892: return CAS_RING_SZ_64;
! 893: case 128:
! 894: return CAS_RING_SZ_128;
! 895: case 256:
! 896: return CAS_RING_SZ_256;
! 897: case 512:
! 898: return CAS_RING_SZ_512;
! 899: case 1024:
! 900: return CAS_RING_SZ_1024;
! 901: case 2048:
! 902: return CAS_RING_SZ_2048;
! 903: case 4096:
! 904: return CAS_RING_SZ_4096;
! 905: case 8192:
! 906: return CAS_RING_SZ_8192;
! 907: default:
! 908: printf("cas: invalid Receive Descriptor ring size %d\n", sz);
! 909: return CAS_RING_SZ_32;
! 910: }
! 911: }
! 912:
! 913: int
! 914: cas_cringsize(int sz)
! 915: {
! 916: int i;
! 917:
! 918: for (i = 0; i < 9; i++)
! 919: if (sz == (128 << i))
! 920: return i;
! 921:
! 922: printf("cas: invalid completion ring size %d\n", sz);
! 923: return 128;
! 924: }
! 925:
! 926: /*
! 927: * Initialization of interface; set up initialization block
! 928: * and transmit/receive descriptor rings.
! 929: */
! 930: int
! 931: cas_init(struct ifnet *ifp)
! 932: {
! 933:
! 934: struct cas_softc *sc = (struct cas_softc *)ifp->if_softc;
! 935: bus_space_tag_t t = sc->sc_memt;
! 936: bus_space_handle_t h = sc->sc_memh;
! 937: int s;
! 938: u_int max_frame_size;
! 939: u_int32_t v;
! 940:
! 941: s = splnet();
! 942:
! 943: DPRINTF(sc, ("%s: cas_init: calling stop\n", sc->sc_dev.dv_xname));
! 944: /*
! 945: * Initialization sequence. The numbered steps below correspond
! 946: * to the sequence outlined in section 6.3.5.1 in the Ethernet
! 947: * Channel Engine manual (part of the PCIO manual).
! 948: * See also the STP2002-STQ document from Sun Microsystems.
! 949: */
! 950:
! 951: /* step 1 & 2. Reset the Ethernet Channel */
! 952: cas_stop(ifp, 0);
! 953: cas_reset(sc);
! 954: DPRINTF(sc, ("%s: cas_init: restarting\n", sc->sc_dev.dv_xname));
! 955:
! 956: /* Re-initialize the MIF */
! 957: cas_mifinit(sc);
! 958:
! 959: /* step 3. Setup data structures in host memory */
! 960: cas_meminit(sc);
! 961:
! 962: /* step 4. TX MAC registers & counters */
! 963: cas_init_regs(sc);
! 964: max_frame_size = ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN;
! 965: v = (max_frame_size) | (0x2000 << 16) /* Burst size */;
! 966: bus_space_write_4(t, h, CAS_MAC_MAC_MAX_FRAME, v);
! 967:
! 968: /* step 5. RX MAC registers & counters */
! 969: cas_setladrf(sc);
! 970:
! 971: /* step 6 & 7. Program Descriptor Ring Base Addresses */
! 972: KASSERT((CAS_CDTXADDR(sc, 0) & 0x1fff) == 0);
! 973: bus_space_write_4(t, h, CAS_TX_RING_PTR_HI,
! 974: (((uint64_t)CAS_CDTXADDR(sc,0)) >> 32));
! 975: bus_space_write_4(t, h, CAS_TX_RING_PTR_LO, CAS_CDTXADDR(sc, 0));
! 976:
! 977: KASSERT((CAS_CDRXADDR(sc, 0) & 0x1fff) == 0);
! 978: bus_space_write_4(t, h, CAS_RX_DRING_PTR_HI,
! 979: (((uint64_t)CAS_CDRXADDR(sc,0)) >> 32));
! 980: bus_space_write_4(t, h, CAS_RX_DRING_PTR_LO, CAS_CDRXADDR(sc, 0));
! 981:
! 982: KASSERT((CAS_CDRXCADDR(sc, 0) & 0x1fff) == 0);
! 983: bus_space_write_4(t, h, CAS_RX_CRING_PTR_HI,
! 984: (((uint64_t)CAS_CDRXCADDR(sc,0)) >> 32));
! 985: bus_space_write_4(t, h, CAS_RX_CRING_PTR_LO, CAS_CDRXCADDR(sc, 0));
! 986:
! 987: /* step 8. Global Configuration & Interrupt Mask */
! 988: bus_space_write_4(t, h, CAS_INTMASK,
! 989: ~(CAS_INTR_TX_INTME|CAS_INTR_TX_EMPTY|
! 990: CAS_INTR_TX_TAG_ERR|
! 991: CAS_INTR_RX_DONE|CAS_INTR_RX_NOBUF|
! 992: CAS_INTR_RX_TAG_ERR|
! 993: CAS_INTR_RX_COMP_FULL|CAS_INTR_PCS|
! 994: CAS_INTR_MAC_CONTROL|CAS_INTR_MIF|
! 995: CAS_INTR_BERR));
! 996: bus_space_write_4(t, h, CAS_MAC_RX_MASK,
! 997: CAS_MAC_RX_DONE|CAS_MAC_RX_FRAME_CNT);
! 998: bus_space_write_4(t, h, CAS_MAC_TX_MASK, CAS_MAC_TX_XMIT_DONE);
! 999: bus_space_write_4(t, h, CAS_MAC_CONTROL_MASK, 0); /* XXXX */
! 1000:
! 1001: /* step 9. ETX Configuration: use mostly default values */
! 1002:
! 1003: /* Enable DMA */
! 1004: v = cas_ringsize(CAS_NTXDESC /*XXX*/) << 10;
! 1005: bus_space_write_4(t, h, CAS_TX_CONFIG,
! 1006: v|CAS_TX_CONFIG_TXDMA_EN|(1<<24)|(1<<29));
! 1007: bus_space_write_4(t, h, CAS_TX_KICK, 0);
! 1008:
! 1009: /* step 10. ERX Configuration */
! 1010:
! 1011: /* Encode Receive Descriptor ring size */
! 1012: v = cas_ringsize(CAS_NRXDESC) << CAS_RX_CONFIG_RXDRNG_SZ_SHIFT;
! 1013:
! 1014: /* Encode Receive Completion ring size */
! 1015: v |= cas_cringsize(CAS_NRXCOMP) << CAS_RX_CONFIG_RXCRNG_SZ_SHIFT;
! 1016:
! 1017: /* Enable DMA */
! 1018: bus_space_write_4(t, h, CAS_RX_CONFIG,
! 1019: v|(2<<CAS_RX_CONFIG_FBOFF_SHFT)|CAS_RX_CONFIG_RXDMA_EN);
! 1020:
! 1021: /*
! 1022: * The following value is for an OFF Threshold of about 3/4 full
! 1023: * and an ON Threshold of 1/4 full.
! 1024: */
! 1025: bus_space_write_4(t, h, CAS_RX_PAUSE_THRESH,
! 1026: (3 * sc->sc_rxfifosize / 256) |
! 1027: ( (sc->sc_rxfifosize / 256) << 12));
! 1028: bus_space_write_4(t, h, CAS_RX_BLANKING, (6<<12)|6);
! 1029:
! 1030: /* step 11. Configure Media */
! 1031: mii_mediachg(&sc->sc_mii);
! 1032:
! 1033: /* step 12. RX_MAC Configuration Register */
! 1034: v = bus_space_read_4(t, h, CAS_MAC_RX_CONFIG);
! 1035: v |= CAS_MAC_RX_ENABLE | CAS_MAC_RX_STRIP_CRC;
! 1036: bus_space_write_4(t, h, CAS_MAC_RX_CONFIG, v);
! 1037:
! 1038: /* step 14. Issue Transmit Pending command */
! 1039:
! 1040: /* step 15. Give the receiver a swift kick */
! 1041: bus_space_write_4(t, h, CAS_RX_KICK, CAS_NRXDESC-4);
! 1042:
! 1043: /* Start the one second timer. */
! 1044: timeout_add(&sc->sc_tick_ch, hz);
! 1045:
! 1046: ifp->if_flags |= IFF_RUNNING;
! 1047: ifp->if_flags &= ~IFF_OACTIVE;
! 1048: ifp->if_timer = 0;
! 1049: splx(s);
! 1050:
! 1051: return (0);
! 1052: }
! 1053:
! 1054: void
! 1055: cas_init_regs(struct cas_softc *sc)
! 1056: {
! 1057: bus_space_tag_t t = sc->sc_memt;
! 1058: bus_space_handle_t h = sc->sc_memh;
! 1059: u_int32_t v, r;
! 1060:
! 1061: /* These regs are not cleared on reset */
! 1062: sc->sc_inited = 0;
! 1063: if (!sc->sc_inited) {
! 1064:
! 1065: /* Wooo. Magic values. */
! 1066: bus_space_write_4(t, h, CAS_MAC_IPG0, 0);
! 1067: bus_space_write_4(t, h, CAS_MAC_IPG1, 8);
! 1068: bus_space_write_4(t, h, CAS_MAC_IPG2, 4);
! 1069:
! 1070: bus_space_write_4(t, h, CAS_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN);
! 1071: /* Max frame and max burst size */
! 1072: v = ETHER_MAX_LEN | (0x2000 << 16) /* Burst size */;
! 1073: bus_space_write_4(t, h, CAS_MAC_MAC_MAX_FRAME, v);
! 1074:
! 1075: bus_space_write_4(t, h, CAS_MAC_PREAMBLE_LEN, 0x7);
! 1076: bus_space_write_4(t, h, CAS_MAC_JAM_SIZE, 0x4);
! 1077: bus_space_write_4(t, h, CAS_MAC_ATTEMPT_LIMIT, 0x10);
! 1078: /* Dunno.... */
! 1079: bus_space_write_4(t, h, CAS_MAC_CONTROL_TYPE, 0x8088);
! 1080: bus_space_write_4(t, h, CAS_MAC_RANDOM_SEED,
! 1081: ((sc->sc_arpcom.ac_enaddr[5]<<8)|sc->sc_arpcom.ac_enaddr[4])&0x3ff);
! 1082:
! 1083: /* Secondary MAC addresses set to 0:0:0:0:0:0 */
! 1084: for (r = CAS_MAC_ADDR3; r < CAS_MAC_ADDR42; r += 4)
! 1085: bus_space_write_4(t, h, r, 0);
! 1086:
! 1087: /* MAC control addr set to 0:1:c2:0:1:80 */
! 1088: bus_space_write_4(t, h, CAS_MAC_ADDR42, 0x0001);
! 1089: bus_space_write_4(t, h, CAS_MAC_ADDR43, 0xc200);
! 1090: bus_space_write_4(t, h, CAS_MAC_ADDR44, 0x0180);
! 1091:
! 1092: /* MAC filter addr set to 0:0:0:0:0:0 */
! 1093: bus_space_write_4(t, h, CAS_MAC_ADDR_FILTER0, 0);
! 1094: bus_space_write_4(t, h, CAS_MAC_ADDR_FILTER1, 0);
! 1095: bus_space_write_4(t, h, CAS_MAC_ADDR_FILTER2, 0);
! 1096:
! 1097: bus_space_write_4(t, h, CAS_MAC_ADR_FLT_MASK1_2, 0);
! 1098: bus_space_write_4(t, h, CAS_MAC_ADR_FLT_MASK0, 0);
! 1099:
! 1100: /* Hash table initialized to 0 */
! 1101: for (r = CAS_MAC_HASH0; r <= CAS_MAC_HASH15; r += 4)
! 1102: bus_space_write_4(t, h, r, 0);
! 1103:
! 1104: sc->sc_inited = 1;
! 1105: }
! 1106:
! 1107: /* Counters need to be zeroed */
! 1108: bus_space_write_4(t, h, CAS_MAC_NORM_COLL_CNT, 0);
! 1109: bus_space_write_4(t, h, CAS_MAC_FIRST_COLL_CNT, 0);
! 1110: bus_space_write_4(t, h, CAS_MAC_EXCESS_COLL_CNT, 0);
! 1111: bus_space_write_4(t, h, CAS_MAC_LATE_COLL_CNT, 0);
! 1112: bus_space_write_4(t, h, CAS_MAC_DEFER_TMR_CNT, 0);
! 1113: bus_space_write_4(t, h, CAS_MAC_PEAK_ATTEMPTS, 0);
! 1114: bus_space_write_4(t, h, CAS_MAC_RX_FRAME_COUNT, 0);
! 1115: bus_space_write_4(t, h, CAS_MAC_RX_LEN_ERR_CNT, 0);
! 1116: bus_space_write_4(t, h, CAS_MAC_RX_ALIGN_ERR, 0);
! 1117: bus_space_write_4(t, h, CAS_MAC_RX_CRC_ERR_CNT, 0);
! 1118: bus_space_write_4(t, h, CAS_MAC_RX_CODE_VIOL, 0);
! 1119:
! 1120: /* Un-pause stuff */
! 1121: bus_space_write_4(t, h, CAS_MAC_SEND_PAUSE_CMD, 0);
! 1122:
! 1123: /*
! 1124: * Set the station address.
! 1125: */
! 1126: bus_space_write_4(t, h, CAS_MAC_ADDR0,
! 1127: (sc->sc_arpcom.ac_enaddr[4]<<8) | sc->sc_arpcom.ac_enaddr[5]);
! 1128: bus_space_write_4(t, h, CAS_MAC_ADDR1,
! 1129: (sc->sc_arpcom.ac_enaddr[2]<<8) | sc->sc_arpcom.ac_enaddr[3]);
! 1130: bus_space_write_4(t, h, CAS_MAC_ADDR2,
! 1131: (sc->sc_arpcom.ac_enaddr[0]<<8) | sc->sc_arpcom.ac_enaddr[1]);
! 1132: }
! 1133:
! 1134: /*
! 1135: * Receive interrupt.
! 1136: */
! 1137: int
! 1138: cas_rint(struct cas_softc *sc)
! 1139: {
! 1140: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1141: bus_space_tag_t t = sc->sc_memt;
! 1142: bus_space_handle_t h = sc->sc_memh;
! 1143: struct cas_rxsoft *rxs;
! 1144: struct mbuf *m;
! 1145: u_int64_t word[4];
! 1146: int len, off, idx;
! 1147: int i, skip;
! 1148: caddr_t cp;
! 1149:
! 1150: for (i = sc->sc_rxptr;; i = CAS_NEXTRX(i + skip)) {
! 1151: CAS_CDRXCSYNC(sc, i,
! 1152: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 1153:
! 1154: word[0] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[0]);
! 1155: word[1] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[1]);
! 1156: word[2] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[2]);
! 1157: word[3] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[3]);
! 1158:
! 1159: /* Stop if the hardware still owns the descriptor. */
! 1160: if ((word[0] & CAS_RC0_TYPE) == 0 || word[3] & CAS_RC3_OWN)
! 1161: break;
! 1162:
! 1163: len = CAS_RC1_HDR_LEN(word[1]);
! 1164: if (len > 0) {
! 1165: off = CAS_RC1_HDR_OFF(word[1]);
! 1166: idx = CAS_RC1_HDR_IDX(word[1]);
! 1167: rxs = &sc->sc_rxsoft[idx];
! 1168:
! 1169: DPRINTF(sc, ("hdr at idx %d, off %d, len %d\n",
! 1170: idx, off, len));
! 1171:
! 1172: bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
! 1173: rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1174:
! 1175: cp = rxs->rxs_kva + off * 256;
! 1176: m = m_devget(cp, len + ETHER_ALIGN, 0, ifp, NULL);
! 1177:
! 1178: if (word[0] & CAS_RC0_RELEASE_HDR)
! 1179: cas_add_rxbuf(sc, idx);
! 1180:
! 1181: if (m != NULL) {
! 1182: m_adj(m, ETHER_ALIGN);
! 1183:
! 1184: #if NBPFILTER > 0
! 1185: /*
! 1186: * Pass this up to any BPF listeners, but only
! 1187: * pass it up the stack if its for us.
! 1188: */
! 1189: if (ifp->if_bpf)
! 1190: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1191: #endif /* NPBFILTER > 0 */
! 1192:
! 1193: ifp->if_ipackets++;
! 1194: ether_input_mbuf(ifp, m);
! 1195: } else
! 1196: ifp->if_ierrors++;
! 1197: }
! 1198:
! 1199: len = CAS_RC0_DATA_LEN(word[0]);
! 1200: if (len > 0) {
! 1201: off = CAS_RC0_DATA_OFF(word[0]);
! 1202: idx = CAS_RC0_DATA_IDX(word[0]);
! 1203: rxs = &sc->sc_rxsoft[idx];
! 1204:
! 1205: DPRINTF(sc, ("data at idx %d, off %d, len %d\n",
! 1206: idx, off, len));
! 1207:
! 1208: bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
! 1209: rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1210:
! 1211: /* XXX We should not be copying the packet here. */
! 1212: cp = rxs->rxs_kva + off;
! 1213: m = m_devget(cp, len + ETHER_ALIGN, 0, ifp, NULL);
! 1214:
! 1215: if (word[0] & CAS_RC0_RELEASE_DATA)
! 1216: cas_add_rxbuf(sc, idx);
! 1217:
! 1218: if (m != NULL) {
! 1219: m_adj(m, ETHER_ALIGN);
! 1220:
! 1221: #if NBPFILTER > 0
! 1222: /*
! 1223: * Pass this up to any BPF listeners, but only
! 1224: * pass it up the stack if its for us.
! 1225: */
! 1226: if (ifp->if_bpf)
! 1227: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1228: #endif /* NPBFILTER > 0 */
! 1229:
! 1230: ifp->if_ipackets++;
! 1231: ether_input_mbuf(ifp, m);
! 1232: } else
! 1233: ifp->if_ierrors++;
! 1234: }
! 1235:
! 1236: if (word[0] & CAS_RC0_SPLIT)
! 1237: printf("split packet\n");
! 1238:
! 1239: skip = CAS_RC0_SKIP(word[0]);
! 1240: }
! 1241:
! 1242: while (sc->sc_rxptr != i) {
! 1243: sc->sc_rxcomps[sc->sc_rxptr].cc_word[0] = 0;
! 1244: sc->sc_rxcomps[sc->sc_rxptr].cc_word[1] = 0;
! 1245: sc->sc_rxcomps[sc->sc_rxptr].cc_word[2] = 0;
! 1246: sc->sc_rxcomps[sc->sc_rxptr].cc_word[3] =
! 1247: CAS_DMA_WRITE(CAS_RC3_OWN);
! 1248: CAS_CDRXCSYNC(sc, sc->sc_rxptr,
! 1249: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1250:
! 1251: sc->sc_rxptr = CAS_NEXTRX(sc->sc_rxptr);
! 1252: }
! 1253:
! 1254: bus_space_write_4(t, h, CAS_RX_COMP_TAIL, sc->sc_rxptr);
! 1255:
! 1256: DPRINTF(sc, ("cas_rint: done sc->rxptr %d, complete %d\n",
! 1257: sc->sc_rxptr, bus_space_read_4(t, h, CAS_RX_COMPLETION)));
! 1258:
! 1259: return (1);
! 1260: }
! 1261:
! 1262: /*
! 1263: * cas_add_rxbuf:
! 1264: *
! 1265: * Add a receive buffer to the indicated descriptor.
! 1266: */
! 1267: int
! 1268: cas_add_rxbuf(struct cas_softc *sc, int idx)
! 1269: {
! 1270: bus_space_tag_t t = sc->sc_memt;
! 1271: bus_space_handle_t h = sc->sc_memh;
! 1272:
! 1273: CAS_INIT_RXDESC(sc, sc->sc_rxdptr, idx);
! 1274:
! 1275: if ((sc->sc_rxdptr % 4) == 0)
! 1276: bus_space_write_4(t, h, CAS_RX_KICK, sc->sc_rxdptr);
! 1277:
! 1278: sc->sc_rxdptr++;
! 1279: return (0);
! 1280: }
! 1281:
! 1282: int
! 1283: cas_eint(struct cas_softc *sc, u_int status)
! 1284: {
! 1285: if ((status & CAS_INTR_MIF) != 0) {
! 1286: #ifdef CAS_DEBUG
! 1287: printf("%s: link status changed\n", sc->sc_dev.dv_xname);
! 1288: #endif
! 1289: return (1);
! 1290: }
! 1291:
! 1292: printf("%s: status=%b\n", sc->sc_dev.dv_xname, status, CAS_INTR_BITS);
! 1293: return (1);
! 1294: }
! 1295:
! 1296: int
! 1297: cas_pint(struct cas_softc *sc)
! 1298: {
! 1299: bus_space_tag_t t = sc->sc_memt;
! 1300: bus_space_handle_t seb = sc->sc_memh;
! 1301: u_int32_t status;
! 1302:
! 1303: status = bus_space_read_4(t, seb, CAS_MII_INTERRUP_STATUS);
! 1304: status |= bus_space_read_4(t, seb, CAS_MII_INTERRUP_STATUS);
! 1305: #ifdef CAS_DEBUG
! 1306: if (status)
! 1307: printf("%s: link status changed\n", sc->sc_dev.dv_xname);
! 1308: #endif
! 1309: return (1);
! 1310: }
! 1311:
! 1312: int
! 1313: cas_intr(void *v)
! 1314: {
! 1315: struct cas_softc *sc = (struct cas_softc *)v;
! 1316: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1317: bus_space_tag_t t = sc->sc_memt;
! 1318: bus_space_handle_t seb = sc->sc_memh;
! 1319: u_int32_t status;
! 1320: int r = 0;
! 1321:
! 1322: status = bus_space_read_4(t, seb, CAS_STATUS);
! 1323: DPRINTF(sc, ("%s: cas_intr: cplt %xstatus %b\n",
! 1324: sc->sc_dev.dv_xname, (status>>19), status, CAS_INTR_BITS));
! 1325:
! 1326: if ((status & CAS_INTR_PCS) != 0)
! 1327: r |= cas_pint(sc);
! 1328:
! 1329: if ((status & (CAS_INTR_TX_TAG_ERR | CAS_INTR_RX_TAG_ERR |
! 1330: CAS_INTR_RX_COMP_FULL | CAS_INTR_BERR)) != 0)
! 1331: r |= cas_eint(sc, status);
! 1332:
! 1333: if ((status & (CAS_INTR_TX_EMPTY | CAS_INTR_TX_INTME)) != 0)
! 1334: r |= cas_tint(sc, status);
! 1335:
! 1336: if ((status & (CAS_INTR_RX_DONE | CAS_INTR_RX_NOBUF)) != 0)
! 1337: r |= cas_rint(sc);
! 1338:
! 1339: /* We should eventually do more than just print out error stats. */
! 1340: if (status & CAS_INTR_TX_MAC) {
! 1341: int txstat = bus_space_read_4(t, seb, CAS_MAC_TX_STATUS);
! 1342: #ifdef CAS_DEBUG
! 1343: if (txstat & ~CAS_MAC_TX_XMIT_DONE)
! 1344: printf("%s: MAC tx fault, status %x\n",
! 1345: sc->sc_dev.dv_xname, txstat);
! 1346: #endif
! 1347: if (txstat & (CAS_MAC_TX_UNDERRUN | CAS_MAC_TX_PKT_TOO_LONG))
! 1348: cas_init(ifp);
! 1349: }
! 1350: if (status & CAS_INTR_RX_MAC) {
! 1351: int rxstat = bus_space_read_4(t, seb, CAS_MAC_RX_STATUS);
! 1352: #ifdef CAS_DEBUG
! 1353: if (rxstat & ~CAS_MAC_RX_DONE)
! 1354: printf("%s: MAC rx fault, status %x\n",
! 1355: sc->sc_dev.dv_xname, rxstat);
! 1356: #endif
! 1357: /*
! 1358: * On some chip revisions CAS_MAC_RX_OVERFLOW happen often
! 1359: * due to a silicon bug so handle them silently.
! 1360: */
! 1361: if (rxstat & CAS_MAC_RX_OVERFLOW) {
! 1362: ifp->if_ierrors++;
! 1363: cas_init(ifp);
! 1364: }
! 1365: #ifdef CAS_DEBUG
! 1366: else if (rxstat & ~(CAS_MAC_RX_DONE | CAS_MAC_RX_FRAME_CNT))
! 1367: printf("%s: MAC rx fault, status %x\n",
! 1368: sc->sc_dev.dv_xname, rxstat);
! 1369: #endif
! 1370: }
! 1371: return (r);
! 1372: }
! 1373:
! 1374:
! 1375: void
! 1376: cas_watchdog(struct ifnet *ifp)
! 1377: {
! 1378: struct cas_softc *sc = ifp->if_softc;
! 1379:
! 1380: DPRINTF(sc, ("cas_watchdog: CAS_RX_CONFIG %x CAS_MAC_RX_STATUS %x "
! 1381: "CAS_MAC_RX_CONFIG %x\n",
! 1382: bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_RX_CONFIG),
! 1383: bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_MAC_RX_STATUS),
! 1384: bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_MAC_RX_CONFIG)));
! 1385:
! 1386: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 1387: ++ifp->if_oerrors;
! 1388:
! 1389: /* Try to get more packets going. */
! 1390: cas_init(ifp);
! 1391: }
! 1392:
! 1393: /*
! 1394: * Initialize the MII Management Interface
! 1395: */
! 1396: void
! 1397: cas_mifinit(struct cas_softc *sc)
! 1398: {
! 1399: bus_space_tag_t t = sc->sc_memt;
! 1400: bus_space_handle_t mif = sc->sc_memh;
! 1401:
! 1402: /* Configure the MIF in frame mode */
! 1403: sc->sc_mif_config = bus_space_read_4(t, mif, CAS_MIF_CONFIG);
! 1404: sc->sc_mif_config &= ~CAS_MIF_CONFIG_BB_ENA;
! 1405: bus_space_write_4(t, mif, CAS_MIF_CONFIG, sc->sc_mif_config);
! 1406: }
! 1407:
! 1408: /*
! 1409: * MII interface
! 1410: *
! 1411: * The Cassini MII interface supports at least three different operating modes:
! 1412: *
! 1413: * Bitbang mode is implemented using data, clock and output enable registers.
! 1414: *
! 1415: * Frame mode is implemented by loading a complete frame into the frame
! 1416: * register and polling the valid bit for completion.
! 1417: *
! 1418: * Polling mode uses the frame register but completion is indicated by
! 1419: * an interrupt.
! 1420: *
! 1421: */
! 1422: int
! 1423: cas_mii_readreg(struct device *self, int phy, int reg)
! 1424: {
! 1425: struct cas_softc *sc = (void *)self;
! 1426: bus_space_tag_t t = sc->sc_memt;
! 1427: bus_space_handle_t mif = sc->sc_memh;
! 1428: int n;
! 1429: u_int32_t v;
! 1430:
! 1431: #ifdef CAS_DEBUG
! 1432: if (sc->sc_debug)
! 1433: printf("cas_mii_readreg: phy %d reg %d\n", phy, reg);
! 1434: #endif
! 1435:
! 1436: /* Construct the frame command */
! 1437: v = (reg << CAS_MIF_REG_SHIFT) | (phy << CAS_MIF_PHY_SHIFT) |
! 1438: CAS_MIF_FRAME_READ;
! 1439:
! 1440: bus_space_write_4(t, mif, CAS_MIF_FRAME, v);
! 1441: for (n = 0; n < 100; n++) {
! 1442: DELAY(1);
! 1443: v = bus_space_read_4(t, mif, CAS_MIF_FRAME);
! 1444: if (v & CAS_MIF_FRAME_TA0)
! 1445: return (v & CAS_MIF_FRAME_DATA);
! 1446: }
! 1447:
! 1448: printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname);
! 1449: return (0);
! 1450: }
! 1451:
! 1452: void
! 1453: cas_mii_writereg(struct device *self, int phy, int reg, int val)
! 1454: {
! 1455: struct cas_softc *sc = (void *)self;
! 1456: bus_space_tag_t t = sc->sc_memt;
! 1457: bus_space_handle_t mif = sc->sc_memh;
! 1458: int n;
! 1459: u_int32_t v;
! 1460:
! 1461: #ifdef CAS_DEBUG
! 1462: if (sc->sc_debug)
! 1463: printf("cas_mii_writereg: phy %d reg %d val %x\n",
! 1464: phy, reg, val);
! 1465: #endif
! 1466:
! 1467: #if 0
! 1468: /* Select the desired PHY in the MIF configuration register */
! 1469: v = bus_space_read_4(t, mif, CAS_MIF_CONFIG);
! 1470: /* Clear PHY select bit */
! 1471: v &= ~CAS_MIF_CONFIG_PHY_SEL;
! 1472: if (phy == CAS_PHYAD_EXTERNAL)
! 1473: /* Set PHY select bit to get at external device */
! 1474: v |= CAS_MIF_CONFIG_PHY_SEL;
! 1475: bus_space_write_4(t, mif, CAS_MIF_CONFIG, v);
! 1476: #endif
! 1477: /* Construct the frame command */
! 1478: v = CAS_MIF_FRAME_WRITE |
! 1479: (phy << CAS_MIF_PHY_SHIFT) |
! 1480: (reg << CAS_MIF_REG_SHIFT) |
! 1481: (val & CAS_MIF_FRAME_DATA);
! 1482:
! 1483: bus_space_write_4(t, mif, CAS_MIF_FRAME, v);
! 1484: for (n = 0; n < 100; n++) {
! 1485: DELAY(1);
! 1486: v = bus_space_read_4(t, mif, CAS_MIF_FRAME);
! 1487: if (v & CAS_MIF_FRAME_TA0)
! 1488: return;
! 1489: }
! 1490:
! 1491: printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname);
! 1492: }
! 1493:
! 1494: void
! 1495: cas_mii_statchg(struct device *dev)
! 1496: {
! 1497: struct cas_softc *sc = (void *)dev;
! 1498: #ifdef CAS_DEBUG
! 1499: int instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
! 1500: #endif
! 1501: bus_space_tag_t t = sc->sc_memt;
! 1502: bus_space_handle_t mac = sc->sc_memh;
! 1503: u_int32_t v;
! 1504:
! 1505: #ifdef CAS_DEBUG
! 1506: if (sc->sc_debug)
! 1507: printf("cas_mii_statchg: status change: phy = %d\n",
! 1508: sc->sc_phys[instance]);
! 1509: #endif
! 1510:
! 1511: /* Set tx full duplex options */
! 1512: bus_space_write_4(t, mac, CAS_MAC_TX_CONFIG, 0);
! 1513: delay(10000); /* reg must be cleared and delay before changing. */
! 1514: v = CAS_MAC_TX_ENA_IPG0|CAS_MAC_TX_NGU|CAS_MAC_TX_NGU_LIMIT|
! 1515: CAS_MAC_TX_ENABLE;
! 1516: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) {
! 1517: v |= CAS_MAC_TX_IGN_CARRIER|CAS_MAC_TX_IGN_COLLIS;
! 1518: }
! 1519: bus_space_write_4(t, mac, CAS_MAC_TX_CONFIG, v);
! 1520:
! 1521: /* XIF Configuration */
! 1522: v = CAS_MAC_XIF_TX_MII_ENA;
! 1523: v |= CAS_MAC_XIF_LINK_LED;
! 1524:
! 1525: /* MII needs echo disable if half duplex. */
! 1526: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
! 1527: /* turn on full duplex LED */
! 1528: v |= CAS_MAC_XIF_FDPLX_LED;
! 1529: else
! 1530: /* half duplex -- disable echo */
! 1531: v |= CAS_MAC_XIF_ECHO_DISABL;
! 1532:
! 1533: switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
! 1534: case IFM_1000_T: /* Gigabit using GMII interface */
! 1535: case IFM_1000_SX:
! 1536: v |= CAS_MAC_XIF_GMII_MODE;
! 1537: break;
! 1538: default:
! 1539: v &= ~CAS_MAC_XIF_GMII_MODE;
! 1540: }
! 1541: bus_space_write_4(t, mac, CAS_MAC_XIF_CONFIG, v);
! 1542: }
! 1543:
! 1544: int
! 1545: cas_pcs_readreg(struct device *self, int phy, int reg)
! 1546: {
! 1547: struct cas_softc *sc = (void *)self;
! 1548: bus_space_tag_t t = sc->sc_memt;
! 1549: bus_space_handle_t pcs = sc->sc_memh;
! 1550:
! 1551: #ifdef CAS_DEBUG
! 1552: if (sc->sc_debug)
! 1553: printf("cas_pcs_readreg: phy %d reg %d\n", phy, reg);
! 1554: #endif
! 1555:
! 1556: if (phy != CAS_PHYAD_EXTERNAL)
! 1557: return (0);
! 1558:
! 1559: switch (reg) {
! 1560: case MII_BMCR:
! 1561: reg = CAS_MII_CONTROL;
! 1562: break;
! 1563: case MII_BMSR:
! 1564: reg = CAS_MII_STATUS;
! 1565: break;
! 1566: case MII_ANAR:
! 1567: reg = CAS_MII_ANAR;
! 1568: break;
! 1569: case MII_ANLPAR:
! 1570: reg = CAS_MII_ANLPAR;
! 1571: break;
! 1572: case MII_EXTSR:
! 1573: return (EXTSR_1000XFDX|EXTSR_1000XHDX);
! 1574: default:
! 1575: return (0);
! 1576: }
! 1577:
! 1578: return bus_space_read_4(t, pcs, reg);
! 1579: }
! 1580:
! 1581: void
! 1582: cas_pcs_writereg(struct device *self, int phy, int reg, int val)
! 1583: {
! 1584: struct cas_softc *sc = (void *)self;
! 1585: bus_space_tag_t t = sc->sc_memt;
! 1586: bus_space_handle_t pcs = sc->sc_memh;
! 1587:
! 1588: #ifdef CAS_DEBUG
! 1589: if (sc->sc_debug)
! 1590: printf("cas_pcs_writereg: phy %d reg %d val %x\n",
! 1591: phy, reg, val);
! 1592: #endif
! 1593:
! 1594: if (phy != CAS_PHYAD_EXTERNAL)
! 1595: return;
! 1596:
! 1597: switch (reg) {
! 1598: case MII_BMCR:
! 1599: reg = CAS_MII_CONTROL;
! 1600: break;
! 1601: case MII_BMSR:
! 1602: reg = CAS_MII_STATUS;
! 1603: break;
! 1604: case MII_ANAR:
! 1605: reg = CAS_MII_ANAR;
! 1606: break;
! 1607: case MII_ANLPAR:
! 1608: reg = CAS_MII_ANLPAR;
! 1609: break;
! 1610: default:
! 1611: return;
! 1612: }
! 1613:
! 1614: bus_space_write_4(t, pcs, reg, val);
! 1615:
! 1616: if (reg == CAS_MII_ANAR) {
! 1617: bus_space_write_4(t, pcs, CAS_MII_SLINK_CONTROL,
! 1618: CAS_MII_SLINK_LOOPBACK|CAS_MII_SLINK_EN_SYNC_D);
! 1619: bus_space_write_4(t, pcs, CAS_MII_CONFIG,
! 1620: CAS_MII_CONFIG_ENABLE);
! 1621: }
! 1622: }
! 1623:
! 1624: int
! 1625: cas_mediachange(struct ifnet *ifp)
! 1626: {
! 1627: struct cas_softc *sc = ifp->if_softc;
! 1628: struct mii_data *mii = &sc->sc_mii;
! 1629:
! 1630: if (mii->mii_instance) {
! 1631: struct mii_softc *miisc;
! 1632: LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
! 1633: mii_phy_reset(miisc);
! 1634: }
! 1635:
! 1636: return (mii_mediachg(&sc->sc_mii));
! 1637: }
! 1638:
! 1639: void
! 1640: cas_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
! 1641: {
! 1642: struct cas_softc *sc = ifp->if_softc;
! 1643:
! 1644: mii_pollstat(&sc->sc_mii);
! 1645: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 1646: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 1647: }
! 1648:
! 1649: /*
! 1650: * Process an ioctl request.
! 1651: */
! 1652: int
! 1653: cas_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1654: {
! 1655: struct cas_softc *sc = ifp->if_softc;
! 1656: struct ifaddr *ifa = (struct ifaddr *)data;
! 1657: struct ifreq *ifr = (struct ifreq *)data;
! 1658: int s, error = 0;
! 1659:
! 1660: s = splnet();
! 1661:
! 1662: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 1663: splx(s);
! 1664: return (error);
! 1665: }
! 1666:
! 1667: switch (cmd) {
! 1668:
! 1669: case SIOCSIFADDR:
! 1670: ifp->if_flags |= IFF_UP;
! 1671: if ((ifp->if_flags & IFF_RUNNING) == 0)
! 1672: cas_init(ifp);
! 1673: #ifdef INET
! 1674: if (ifa->ifa_addr->sa_family == AF_INET)
! 1675: arp_ifinit(&sc->sc_arpcom, ifa);
! 1676: #endif
! 1677: break;
! 1678:
! 1679: case SIOCSIFFLAGS:
! 1680: if (ifp->if_flags & IFF_UP) {
! 1681: if ((ifp->if_flags & IFF_RUNNING) &&
! 1682: ((ifp->if_flags ^ sc->sc_if_flags) &
! 1683: (IFF_ALLMULTI | IFF_PROMISC)) != 0)
! 1684: cas_setladrf(sc);
! 1685: else {
! 1686: if ((ifp->if_flags & IFF_RUNNING) == 0)
! 1687: cas_init(ifp);
! 1688: }
! 1689: } else {
! 1690: if (ifp->if_flags & IFF_RUNNING)
! 1691: cas_stop(ifp, 1);
! 1692: }
! 1693: sc->sc_if_flags = ifp->if_flags;
! 1694:
! 1695: #ifdef CAS_DEBUG
! 1696: sc->sc_debug = (ifp->if_flags & IFF_DEBUG) != 0 ? 1 : 0;
! 1697: #endif
! 1698: break;
! 1699:
! 1700: case SIOCSIFMTU:
! 1701: if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
! 1702: error = EINVAL;
! 1703: } else if (ifp->if_mtu != ifr->ifr_mtu) {
! 1704: ifp->if_mtu = ifr->ifr_mtu;
! 1705: }
! 1706: break;
! 1707:
! 1708: case SIOCADDMULTI:
! 1709: case SIOCDELMULTI:
! 1710: error = (cmd == SIOCADDMULTI) ?
! 1711: ether_addmulti(ifr, &sc->sc_arpcom) :
! 1712: ether_delmulti(ifr, &sc->sc_arpcom);
! 1713:
! 1714: if (error == ENETRESET) {
! 1715: /*
! 1716: * Multicast list has changed; set the hardware filter
! 1717: * accordingly.
! 1718: */
! 1719: if (ifp->if_flags & IFF_RUNNING)
! 1720: cas_setladrf(sc);
! 1721: error = 0;
! 1722: }
! 1723: break;
! 1724:
! 1725: case SIOCGIFMEDIA:
! 1726: case SIOCSIFMEDIA:
! 1727: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 1728: break;
! 1729:
! 1730: default:
! 1731: error = EINVAL;
! 1732: break;
! 1733: }
! 1734:
! 1735: splx(s);
! 1736: return (error);
! 1737: }
! 1738:
! 1739:
! 1740: void
! 1741: cas_shutdown(void *arg)
! 1742: {
! 1743: struct cas_softc *sc = (struct cas_softc *)arg;
! 1744: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1745:
! 1746: cas_stop(ifp, 1);
! 1747: }
! 1748:
! 1749: /*
! 1750: * Set up the logical address filter.
! 1751: */
! 1752: void
! 1753: cas_setladrf(struct cas_softc *sc)
! 1754: {
! 1755: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1756: struct ether_multi *enm;
! 1757: struct ether_multistep step;
! 1758: struct arpcom *ac = &sc->sc_arpcom;
! 1759: bus_space_tag_t t = sc->sc_memt;
! 1760: bus_space_handle_t h = sc->sc_memh;
! 1761: u_int32_t crc, hash[16], v;
! 1762: int i;
! 1763:
! 1764: /* Get current RX configuration */
! 1765: v = bus_space_read_4(t, h, CAS_MAC_RX_CONFIG);
! 1766:
! 1767:
! 1768: /*
! 1769: * Turn off promiscuous mode, promiscuous group mode (all multicast),
! 1770: * and hash filter. Depending on the case, the right bit will be
! 1771: * enabled.
! 1772: */
! 1773: v &= ~(CAS_MAC_RX_PROMISCUOUS|CAS_MAC_RX_HASH_FILTER|
! 1774: CAS_MAC_RX_PROMISC_GRP);
! 1775:
! 1776: if ((ifp->if_flags & IFF_PROMISC) != 0) {
! 1777: /* Turn on promiscuous mode */
! 1778: v |= CAS_MAC_RX_PROMISCUOUS;
! 1779: ifp->if_flags |= IFF_ALLMULTI;
! 1780: goto chipit;
! 1781: }
! 1782:
! 1783: /*
! 1784: * Set up multicast address filter by passing all multicast addresses
! 1785: * through a crc generator, and then using the high order 8 bits as an
! 1786: * index into the 256 bit logical address filter. The high order 4
! 1787: * bits selects the word, while the other 4 bits select the bit within
! 1788: * the word (where bit 0 is the MSB).
! 1789: */
! 1790:
! 1791: /* Clear hash table */
! 1792: for (i = 0; i < 16; i++)
! 1793: hash[i] = 0;
! 1794:
! 1795:
! 1796: ETHER_FIRST_MULTI(step, ac, enm);
! 1797: while (enm != NULL) {
! 1798: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 1799: /*
! 1800: * We must listen to a range of multicast addresses.
! 1801: * For now, just accept all multicasts, rather than
! 1802: * trying to set only those filter bits needed to match
! 1803: * the range. (At this time, the only use of address
! 1804: * ranges is for IP multicast routing, for which the
! 1805: * range is big enough to require all bits set.)
! 1806: * XXX use the addr filter for this
! 1807: */
! 1808: ifp->if_flags |= IFF_ALLMULTI;
! 1809: v |= CAS_MAC_RX_PROMISC_GRP;
! 1810: goto chipit;
! 1811: }
! 1812:
! 1813: crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
! 1814:
! 1815: /* Just want the 8 most significant bits. */
! 1816: crc >>= 24;
! 1817:
! 1818: /* Set the corresponding bit in the filter. */
! 1819: hash[crc >> 4] |= 1 << (15 - (crc & 15));
! 1820:
! 1821: ETHER_NEXT_MULTI(step, enm);
! 1822: }
! 1823:
! 1824: v |= CAS_MAC_RX_HASH_FILTER;
! 1825: ifp->if_flags &= ~IFF_ALLMULTI;
! 1826:
! 1827: /* Now load the hash table into the chip (if we are using it) */
! 1828: for (i = 0; i < 16; i++) {
! 1829: bus_space_write_4(t, h,
! 1830: CAS_MAC_HASH0 + i * (CAS_MAC_HASH1-CAS_MAC_HASH0),
! 1831: hash[i]);
! 1832: }
! 1833:
! 1834: chipit:
! 1835: bus_space_write_4(t, h, CAS_MAC_RX_CONFIG, v);
! 1836: }
! 1837:
! 1838: int
! 1839: cas_encap(struct cas_softc *sc, struct mbuf *mhead, u_int32_t *bixp)
! 1840: {
! 1841: u_int64_t flags;
! 1842: u_int32_t cur, frag, i;
! 1843: bus_dmamap_t map;
! 1844:
! 1845: cur = frag = *bixp;
! 1846: map = sc->sc_txd[cur].sd_map;
! 1847:
! 1848: if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, mhead,
! 1849: BUS_DMA_NOWAIT) != 0) {
! 1850: return (ENOBUFS);
! 1851: }
! 1852:
! 1853: if ((sc->sc_tx_cnt + map->dm_nsegs) > (CAS_NTXDESC - 2)) {
! 1854: bus_dmamap_unload(sc->sc_dmatag, map);
! 1855: return (ENOBUFS);
! 1856: }
! 1857:
! 1858: bus_dmamap_sync(sc->sc_dmatag, map, 0, map->dm_mapsize,
! 1859: BUS_DMASYNC_PREWRITE);
! 1860:
! 1861: for (i = 0; i < map->dm_nsegs; i++) {
! 1862: sc->sc_txdescs[frag].cd_addr =
! 1863: CAS_DMA_WRITE(map->dm_segs[i].ds_addr);
! 1864: flags = (map->dm_segs[i].ds_len & CAS_TD_BUFSIZE) |
! 1865: (i == 0 ? CAS_TD_START_OF_PACKET : 0) |
! 1866: ((i == (map->dm_nsegs - 1)) ? CAS_TD_END_OF_PACKET : 0);
! 1867: sc->sc_txdescs[frag].cd_flags = CAS_DMA_WRITE(flags);
! 1868: bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap,
! 1869: CAS_CDTXOFF(frag), sizeof(struct cas_desc),
! 1870: BUS_DMASYNC_PREWRITE);
! 1871: cur = frag;
! 1872: if (++frag == CAS_NTXDESC)
! 1873: frag = 0;
! 1874: }
! 1875:
! 1876: sc->sc_tx_cnt += map->dm_nsegs;
! 1877: sc->sc_txd[*bixp].sd_map = sc->sc_txd[cur].sd_map;
! 1878: sc->sc_txd[cur].sd_map = map;
! 1879: sc->sc_txd[cur].sd_mbuf = mhead;
! 1880:
! 1881: bus_space_write_4(sc->sc_memt, sc->sc_memh, CAS_TX_KICK, frag);
! 1882:
! 1883: *bixp = frag;
! 1884:
! 1885: /* sync descriptors */
! 1886:
! 1887: return (0);
! 1888: }
! 1889:
! 1890: /*
! 1891: * Transmit interrupt.
! 1892: */
! 1893: int
! 1894: cas_tint(struct cas_softc *sc, u_int32_t status)
! 1895: {
! 1896: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1897: struct cas_sxd *sd;
! 1898: u_int32_t cons, hwcons;
! 1899:
! 1900: hwcons = status >> 19;
! 1901: cons = sc->sc_tx_cons;
! 1902: while (cons != hwcons) {
! 1903: sd = &sc->sc_txd[cons];
! 1904: if (sd->sd_mbuf != NULL) {
! 1905: bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0,
! 1906: sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 1907: bus_dmamap_unload(sc->sc_dmatag, sd->sd_map);
! 1908: m_freem(sd->sd_mbuf);
! 1909: sd->sd_mbuf = NULL;
! 1910: }
! 1911: sc->sc_tx_cnt--;
! 1912: ifp->if_opackets++;
! 1913: if (++cons == CAS_NTXDESC)
! 1914: cons = 0;
! 1915: }
! 1916: sc->sc_tx_cons = cons;
! 1917:
! 1918: cas_start(ifp);
! 1919:
! 1920: if (sc->sc_tx_cnt == 0)
! 1921: ifp->if_timer = 0;
! 1922:
! 1923: return (1);
! 1924: }
! 1925:
! 1926: void
! 1927: cas_start(struct ifnet *ifp)
! 1928: {
! 1929: struct cas_softc *sc = ifp->if_softc;
! 1930: struct mbuf *m;
! 1931: u_int32_t bix;
! 1932:
! 1933: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 1934: return;
! 1935:
! 1936: bix = sc->sc_tx_prod;
! 1937: while (sc->sc_txd[bix].sd_mbuf == NULL) {
! 1938: IFQ_POLL(&ifp->if_snd, m);
! 1939: if (m == NULL)
! 1940: break;
! 1941:
! 1942: #if NBPFILTER > 0
! 1943: /*
! 1944: * If BPF is listening on this interface, let it see the
! 1945: * packet before we commit it to the wire.
! 1946: */
! 1947: if (ifp->if_bpf)
! 1948: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 1949: #endif
! 1950:
! 1951: /*
! 1952: * Encapsulate this packet and start it going...
! 1953: * or fail...
! 1954: */
! 1955: if (cas_encap(sc, m, &bix)) {
! 1956: ifp->if_timer = 2;
! 1957: break;
! 1958: }
! 1959:
! 1960: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1961: ifp->if_timer = 5;
! 1962: }
! 1963:
! 1964: sc->sc_tx_prod = bix;
! 1965: }
CVSweb