Annotation of sys/dev/pci/if_lmc_obsd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_lmc_obsd.c,v 1.19 2005/11/07 00:29:21 brad Exp $ */
! 2: /* $NetBSD: if_lmc_nbsd.c,v 1.1 1999/03/25 03:32:43 explorer Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1997-1999 LAN Media Corporation (LMC)
! 6: * All rights reserved. www.lanmedia.com
! 7: *
! 8: * This code is written by Michael Graff <graff@vix.com> for LMC.
! 9: * The code is derived from permitted modifications to software created
! 10: * by Matt Thomas (matt@3am-software.com).
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above
! 18: * copyright notice, this list of conditions and the following disclaimer
! 19: * in the documentation and/or other materials provided with the
! 20: * distribution.
! 21: * 3. All marketing or advertising materials mentioning features or
! 22: * use of this software must display the following acknowledgement:
! 23: * This product includes software developed by LAN Media Corporation
! 24: * and its contributors.
! 25: * 4. Neither the name of LAN Media Corporation nor the names of its
! 26: * contributors may be used to endorse or promote products derived
! 27: * from this software without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY LAN MEDIA CORPORATION AND CONTRIBUTORS
! 30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 39: * THE POSSIBILITY OF SUCH DAMAGE.
! 40: */
! 41:
! 42: /*-
! 43: * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com)
! 44: * All rights reserved.
! 45: *
! 46: * Redistribution and use in source and binary forms, with or without
! 47: * modification, are permitted provided that the following conditions
! 48: * are met:
! 49: * 1. Redistributions of source code must retain the above copyright
! 50: * notice, this list of conditions and the following disclaimer.
! 51: * 2. The name of the author may not be used to endorse or promote products
! 52: * derived from this software without specific prior written permission
! 53: *
! 54: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 55: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 56: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 57: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 58: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 59: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 60: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 61: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 62: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 63: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 64: */
! 65:
! 66: #include "bpfilter.h"
! 67:
! 68: #include <sys/param.h>
! 69: #include <sys/systm.h>
! 70: #include <sys/mbuf.h>
! 71: #include <sys/socket.h>
! 72: #include <sys/ioctl.h>
! 73: #include <sys/errno.h>
! 74: #include <sys/malloc.h>
! 75: #include <sys/kernel.h>
! 76: #include <sys/proc.h> /* only for declaration of wakeup() used by vm.h */
! 77: #include <sys/device.h>
! 78:
! 79: #include <dev/pci/pcidevs.h>
! 80:
! 81: #include <net/if.h>
! 82: #include <net/if_types.h>
! 83: #include <net/if_dl.h>
! 84: #include <net/netisr.h>
! 85:
! 86: #if NBPFILTER > 0
! 87: #include <net/bpf.h>
! 88: #endif
! 89:
! 90: #include <net/if_sppp.h>
! 91:
! 92: #include <machine/bus.h>
! 93:
! 94: #include <dev/pci/pcireg.h>
! 95: #include <dev/pci/pcivar.h>
! 96: #include <dev/ic/dc21040reg.h>
! 97:
! 98: #include <dev/pci/if_lmc_types.h>
! 99: #include <dev/pci/if_lmcioctl.h>
! 100: #include <dev/pci/if_lmcvar.h>
! 101:
! 102: /*
! 103: * This file is INCLUDED (gross, I know, but...)
! 104: */
! 105:
! 106: static void lmc_shutdown(void *arg);
! 107: static int lmc_busdma_init(lmc_softc_t * const sc);
! 108: static int lmc_busdma_allocmem(lmc_softc_t * const sc, size_t size,
! 109: bus_dmamap_t *map_p, lmc_desc_t **desc_p);
! 110:
! 111: static int
! 112: lmc_pci_probe(struct device *parent,
! 113: void *match,
! 114: void *aux)
! 115: {
! 116: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
! 117: u_int32_t id;
! 118:
! 119: /*
! 120: * check first for the DEC chip we expect to find. We expect
! 121: * 21140A, pass 2.2 or higher.
! 122: */
! 123: if (PCI_VENDORID(pa->pa_id) != PCI_VENDOR_DEC)
! 124: return 0;
! 125: if (PCI_CHIPID(pa->pa_id) != PCI_PRODUCT_DEC_21140)
! 126: return 0;
! 127: id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CFRV) & 0xff;
! 128: if (id < 0x22)
! 129: return 0;
! 130:
! 131: /*
! 132: * Next, check the subsystem ID and see if it matches what we
! 133: * expect.
! 134: */
! 135: id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SSID);
! 136: if (PCI_VENDORID(id) != PCI_VENDOR_LMC)
! 137: return 0;
! 138: if ((PCI_CHIPID(id) != PCI_PRODUCT_LMC_HSSI)
! 139: && (PCI_CHIPID(id) != PCI_PRODUCT_LMC_HSSIC)
! 140: && (PCI_CHIPID(id) != PCI_PRODUCT_LMC_DS3)
! 141: && (PCI_CHIPID(id) != PCI_PRODUCT_LMC_SSI)
! 142: && (PCI_CHIPID(id) != PCI_PRODUCT_LMC_DS1))
! 143: return 0;
! 144:
! 145: return 20; /* must be > than any other tulip driver */
! 146: }
! 147:
! 148: static void lmc_pci_attach(struct device * const parent,
! 149: struct device * const self, void * const aux);
! 150:
! 151: struct cfattach lmc_ca = {
! 152: sizeof(lmc_softc_t), lmc_pci_probe, lmc_pci_attach
! 153: };
! 154:
! 155: struct cfdriver lmc_cd = {
! 156: 0, "lmc", DV_IFNET
! 157: };
! 158:
! 159: static void
! 160: lmc_pci_attach(struct device * const parent,
! 161: struct device * const self, void * const aux)
! 162: {
! 163: u_int32_t revinfo, cfdainfo, id, ssid;
! 164: pci_intr_handle_t intrhandle;
! 165: const char *intrstr;
! 166: unsigned csroffset = LMC_PCI_CSROFFSET;
! 167: unsigned csrsize = LMC_PCI_CSRSIZE;
! 168: lmc_csrptr_t csr_base;
! 169: lmc_spl_t s;
! 170: lmc_intrfunc_t (*intr_rtn)(void *) = lmc_intr_normal;
! 171: lmc_softc_t * const sc = (lmc_softc_t *) self;
! 172: struct pci_attach_args * const pa = (struct pci_attach_args *) aux;
! 173: extern lmc_media_t lmc_hssi_media;
! 174: extern lmc_media_t lmc_ds3_media;
! 175: extern lmc_media_t lmc_t1_media;
! 176: extern lmc_media_t lmc_ssi_media;
! 177:
! 178: revinfo = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CFRV) & 0xFF;
! 179: id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CFID);
! 180: cfdainfo = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CFDA);
! 181: ssid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SSID);
! 182:
! 183: switch (PCI_CHIPID(ssid)) {
! 184: case PCI_PRODUCT_LMC_HSSI:
! 185: printf(": HSSI\n");
! 186: sc->lmc_media = &lmc_hssi_media;
! 187: break;
! 188: case PCI_PRODUCT_LMC_HSSIC:
! 189: printf(": HSSIc\n");
! 190: sc->lmc_media = &lmc_hssi_media;
! 191: break;
! 192: case PCI_PRODUCT_LMC_DS3:
! 193: printf(": DS3\n");
! 194: sc->lmc_media = &lmc_ds3_media;
! 195: break;
! 196: case PCI_PRODUCT_LMC_SSI:
! 197: printf(": SSI\n");
! 198: sc->lmc_media = &lmc_ssi_media;
! 199: break;
! 200: case PCI_PRODUCT_LMC_DS1:
! 201: printf(": T1\n");
! 202: sc->lmc_media = &lmc_t1_media;
! 203: break;
! 204: }
! 205:
! 206: sc->lmc_pci_busno = parent;
! 207: sc->lmc_pci_devno = pa->pa_device;
! 208:
! 209: sc->lmc_chipid = LMC_21140A;
! 210: sc->lmc_features |= LMC_HAVE_STOREFWD;
! 211: if (sc->lmc_chipid == LMC_21140A && revinfo <= 0x22)
! 212: sc->lmc_features |= LMC_HAVE_RXBADOVRFLW;
! 213:
! 214: if (cfdainfo & (TULIP_CFDA_SLEEP | TULIP_CFDA_SNOOZE)) {
! 215: cfdainfo &= ~(TULIP_CFDA_SLEEP | TULIP_CFDA_SNOOZE);
! 216: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_CFDA, cfdainfo);
! 217: DELAY(11 * 1000);
! 218: }
! 219:
! 220: bcopy(self->dv_xname, sc->lmc_if.if_xname, IFNAMSIZ);
! 221: sc->lmc_if.if_softc = sc;
! 222: sc->lmc_pc = pa->pa_pc;
! 223:
! 224: sc->lmc_revinfo = revinfo;
! 225: sc->lmc_if.if_softc = sc;
! 226:
! 227: csr_base = 0;
! 228: {
! 229: bus_space_tag_t iot, memt;
! 230: bus_space_handle_t ioh, memh;
! 231: int ioh_valid, memh_valid;
! 232:
! 233: ioh_valid = (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO,
! 234: 0, &iot, &ioh, NULL, NULL, 0) == 0);
! 235: memh_valid = (pci_mapreg_map(pa, PCI_CBMA,
! 236: PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &memt,
! 237: &memh, NULL, NULL, 0) == 0);
! 238:
! 239: if (memh_valid) {
! 240: sc->lmc_bustag = memt;
! 241: sc->lmc_bushandle = memh;
! 242: } else if (ioh_valid) {
! 243: sc->lmc_bustag = iot;
! 244: sc->lmc_bushandle = ioh;
! 245: } else {
! 246: printf("%s: unable to map device registers\n",
! 247: sc->lmc_dev.dv_xname);
! 248: return;
! 249: }
! 250: }
! 251:
! 252: sc->lmc_dmatag = pa->pa_dmat;
! 253: if ((lmc_busdma_init(sc)) != 0) {
! 254: printf("error initing bus_dma\n");
! 255: return;
! 256: }
! 257:
! 258: lmc_initcsrs(sc, csr_base + csroffset, csrsize);
! 259: lmc_initring(sc, &sc->lmc_rxinfo, sc->lmc_rxdescs,
! 260: LMC_RXDESCS);
! 261: lmc_initring(sc, &sc->lmc_txinfo, sc->lmc_txdescs,
! 262: LMC_TXDESCS);
! 263:
! 264: lmc_gpio_mkinput(sc, 0xff);
! 265: sc->lmc_gpio = 0; /* drive no signals yet */
! 266:
! 267: sc->lmc_media->defaults(sc);
! 268:
! 269: sc->lmc_media->set_link_status(sc, LMC_LINK_DOWN); /* down */
! 270:
! 271: /*
! 272: * Make sure there won't be any interrupts or such...
! 273: */
! 274: LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
! 275:
! 276: /*
! 277: * Wait 10 microseconds (actually 50 PCI cycles but at
! 278: * 33MHz that comes to two microseconds but wait a
! 279: * bit longer anyways)
! 280: */
! 281: DELAY(100);
! 282:
! 283: lmc_read_macaddr(sc);
! 284:
! 285: if (pci_intr_map(pa, &intrhandle)) {
! 286: printf("%s: couldn't map interrupt\n",
! 287: sc->lmc_dev.dv_xname);
! 288: return;
! 289: }
! 290: intrstr = pci_intr_string(pa->pa_pc, intrhandle);
! 291:
! 292: sc->lmc_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET,
! 293: intr_rtn, sc, self->dv_xname);
! 294:
! 295: if (sc->lmc_ih == NULL) {
! 296: printf("%s: couldn't establish interrupt",
! 297: sc->lmc_dev.dv_xname);
! 298: if (intrstr != NULL)
! 299: printf(" at %s", intrstr);
! 300: printf("\n");
! 301: return;
! 302: }
! 303:
! 304: printf("%s: pass %d.%d, serial " LMC_EADDR_FMT ", %s\n",
! 305: sc->lmc_dev.dv_xname,
! 306: (sc->lmc_revinfo & 0xF0) >> 4, sc->lmc_revinfo & 0x0F,
! 307: LMC_EADDR_ARGS(sc->lmc_enaddr), intrstr);
! 308:
! 309: sc->lmc_ats = shutdownhook_establish(lmc_shutdown, sc);
! 310: if (sc->lmc_ats == NULL)
! 311: printf("%s: warning: couldn't establish shutdown hook\n",
! 312: sc->lmc_xname);
! 313:
! 314: s = LMC_RAISESPL();
! 315: lmc_dec_reset(sc);
! 316: lmc_reset(sc);
! 317: lmc_attach(sc);
! 318: LMC_RESTORESPL(s);
! 319: }
! 320:
! 321: static void
! 322: lmc_shutdown(void *arg)
! 323: {
! 324: lmc_softc_t * const sc = arg;
! 325: LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
! 326: DELAY(10);
! 327:
! 328: sc->lmc_miireg16 = 0; /* deassert ready, and all others too */
! 329: lmc_led_on(sc, LMC_MII16_LED_ALL);
! 330: }
! 331:
! 332: static int
! 333: lmc_busdma_allocmem(
! 334: lmc_softc_t * const sc,
! 335: size_t size,
! 336: bus_dmamap_t *map_p,
! 337: lmc_desc_t **desc_p)
! 338: {
! 339: bus_dma_segment_t segs[1];
! 340: int nsegs, error;
! 341: error = bus_dmamem_alloc(sc->lmc_dmatag, size, 1, NBPG,
! 342: segs, sizeof(segs)/sizeof(segs[0]),
! 343: &nsegs, BUS_DMA_NOWAIT);
! 344: if (error == 0) {
! 345: void *desc;
! 346: error = bus_dmamem_map(sc->lmc_dmatag, segs, nsegs, size,
! 347: (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
! 348: if (error == 0) {
! 349: bus_dmamap_t map;
! 350: error = bus_dmamap_create(sc->lmc_dmatag, size, 1, size, 0,
! 351: BUS_DMA_NOWAIT, &map);
! 352: if (error == 0) {
! 353: error = bus_dmamap_load(sc->lmc_dmatag, map, desc,
! 354: size, NULL, BUS_DMA_NOWAIT);
! 355: if (error)
! 356: bus_dmamap_destroy(sc->lmc_dmatag, map);
! 357: else
! 358: *map_p = map;
! 359: }
! 360: if (error)
! 361: bus_dmamem_unmap(sc->lmc_dmatag, desc, size);
! 362: }
! 363: if (error)
! 364: bus_dmamem_free(sc->lmc_dmatag, segs, nsegs);
! 365: else
! 366: *desc_p = desc;
! 367: }
! 368: return error;
! 369: }
! 370:
! 371: static int
! 372: lmc_busdma_init(
! 373: lmc_softc_t * const sc)
! 374: {
! 375: int error = 0;
! 376:
! 377: /*
! 378: * Allocate space and dmamap for transmit ring
! 379: */
! 380: if (error == 0) {
! 381: error = lmc_busdma_allocmem(sc, sizeof(lmc_desc_t) * LMC_TXDESCS,
! 382: &sc->lmc_txdescmap,
! 383: &sc->lmc_txdescs);
! 384: }
! 385:
! 386: /*
! 387: * Allocate dmamaps for each transmit descriptors
! 388: */
! 389: if (error == 0) {
! 390: while (error == 0 && sc->lmc_txmaps_free < LMC_TXDESCS) {
! 391: bus_dmamap_t map;
! 392: if ((error = LMC_TXMAP_CREATE(sc, &map)) == 0)
! 393: sc->lmc_txmaps[sc->lmc_txmaps_free++] = map;
! 394: }
! 395: if (error) {
! 396: while (sc->lmc_txmaps_free > 0)
! 397: bus_dmamap_destroy(sc->lmc_dmatag,
! 398: sc->lmc_txmaps[--sc->lmc_txmaps_free]);
! 399: }
! 400: }
! 401:
! 402: /*
! 403: * Allocate space and dmamap for receive ring
! 404: */
! 405: if (error == 0) {
! 406: error = lmc_busdma_allocmem(sc, sizeof(lmc_desc_t) * LMC_RXDESCS,
! 407: &sc->lmc_rxdescmap,
! 408: &sc->lmc_rxdescs);
! 409: }
! 410:
! 411: /*
! 412: * Allocate dmamaps for each receive descriptors
! 413: */
! 414: if (error == 0) {
! 415: while (error == 0 && sc->lmc_rxmaps_free < LMC_RXDESCS) {
! 416: bus_dmamap_t map;
! 417: if ((error = LMC_RXMAP_CREATE(sc, &map)) == 0)
! 418: sc->lmc_rxmaps[sc->lmc_rxmaps_free++] = map;
! 419: }
! 420: if (error) {
! 421: while (sc->lmc_rxmaps_free > 0)
! 422: bus_dmamap_destroy(sc->lmc_dmatag,
! 423: sc->lmc_rxmaps[--sc->lmc_rxmaps_free]);
! 424: }
! 425: }
! 426:
! 427: return error;
! 428: }
CVSweb