/*- * Copyright (c) 2002 Matthew N. Dodd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * * =================================== * HARP | Host ATM Research Platform * =================================== * * * This Host ATM Research Platform ("HARP") file (the "Software") is * made available by Network Computing Services, Inc. ("NetworkCS") * "AS IS". NetworkCS does not provide maintenance, improvements or * support of any kind. * * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. * In no event shall NetworkCS be responsible for any damages, including * but not limited to consequential damages, arising from or relating to * any use of the Software or related support. * * Copyright 1994-1998 Network Computing Services, Inc. * * Copies of this Software may be made, however, the above copyright * notice must be reproduced on all copies. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include devclass_t hea_devclass; static int hea_modevent(module_t, int, void *); int hea_alloc (device_t dev) { struct hea_softc *sc; int error; sc = (struct hea_softc *)device_get_softc(dev); error = 0; sc->mem = bus_alloc_resource(dev, sc->mem_type, &sc->mem_rid, 0, ~0, 1, RF_ACTIVE); if (sc->mem == NULL) { device_printf(dev, "Unable to allocate memory resource.\n"); error = ENXIO; goto fail; } sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->irq == NULL) { device_printf(dev, "Unable to allocate interrupt resource.\n"); error = ENXIO; goto fail; } mtx_init(&sc->mtx, device_get_nameunit(dev), "Interrupt lock", MTX_DEF|MTX_RECURSE); fail: return (error); } int hea_free (device_t dev) { struct hea_softc *sc; sc = (struct hea_softc *)device_get_softc(dev); if (sc->mem) bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem); if (sc->irq_ih) bus_teardown_intr(dev, sc->irq, sc->irq_ih); if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); /* * Destroy the mutex. */ if (mtx_initialized(&sc->mtx) != 0) mtx_destroy(&sc->mtx); return (0); } int hea_attach (device_t dev) { struct hea_softc *sc; Eni_unit *eup; int error; long val; sc = (struct hea_softc *)device_get_softc(dev); eup = &sc->eup; error = 0; /* * Start initializing it */ eup->eu_unit = device_get_unit(dev); eup->eu_mtu = ENI_IFF_MTU; eup->eu_vcc_zone = eni_vcc_zone; eup->eu_nif_zone = eni_nif_zone; eup->eu_ioctl = eni_atm_ioctl; eup->eu_instvcc = eni_instvcc; eup->eu_openvcc = eni_openvcc; eup->eu_closevcc = eni_closevcc; eup->eu_output = eni_output; eup->eu_pcitag = dev; eup->eu_softc = (void *)sc; /* * Map memory structures into adapter space */ eup->eu_suni = (Eni_mem)(eup->eu_base + SUNI_OFFSET); eup->eu_midway = (Eni_mem)(eup->eu_base + MIDWAY_OFFSET); eup->eu_vcitbl = (VCI_Table *)(eup->eu_base + VCITBL_OFFSET); eup->eu_rxdma = (Eni_mem)(eup->eu_base + RXQUEUE_OFFSET); eup->eu_txdma = (Eni_mem)(eup->eu_base + TXQUEUE_OFFSET); eup->eu_svclist = (Eni_mem)(eup->eu_base + SVCLIST_OFFSET); eup->eu_servread = 0; /* * Reset the midway chip */ eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET; /* * Size and test adapter memory. Initialize our adapter memory * allocater. */ if (eni_init_memory(eup) < 0) { /* * Adapter memory test failed. Clean up and * return. */ device_printf(dev, "memory test failed.\n"); error = ENXIO; goto fail; } if (eup->eu_type == TYPE_ADP) { int i; #define MID_ADPMACOFF 0xffc0 /* mac address offset (adaptec only) */ for (i = 0; i < sizeof(struct mac_addr); i++) { eup->eu_pif.pif_macaddr.ma_data[i] = bus_space_read_1(rman_get_bustag(sc->mem), rman_get_bushandle(sc->mem), MID_ADPMACOFF + i); } } else if (eup->eu_type == TYPE_ENI) { /* * Read the contents of the SEEPROM */ eni_read_seeprom(eup); /* * Copy MAC address to PIF and config structures */ bcopy((caddr_t)&eup->eu_seeprom[SEPROM_MAC_OFF], (caddr_t)&eup->eu_pif.pif_macaddr, sizeof(struct mac_addr)); /* * Copy serial number into config space */ eup->eu_config.ac_serial = ntohl(*(u_long *)&eup->eu_seeprom[SEPROM_SN_OFF]); } else { device_printf(dev, "Unknown adapter type!\n"); error = ENXIO; goto fail; } eup->eu_config.ac_macaddr = eup->eu_pif.pif_macaddr; /* * Setup some of the adapter configuration */ /* * Get MIDWAY ID */ val = eup->eu_midway[MIDWAY_ID]; eup->eu_config.ac_vendor = VENDOR_ENI; eup->eu_config.ac_vendapi = VENDAPI_ENI_1; eup->eu_config.ac_device = DEV_ENI_155P; eup->eu_config.ac_media = val & MEDIA_MASK ? MEDIA_UTP155 : MEDIA_OC3C; eup->eu_pif.pif_pcr = ATM_PCR_OC3C; /* * Make a hw version number from the ID register values. * Format: {Midway ID}.{Mother board ID}.{Daughter board ID} */ snprintf(eup->eu_config.ac_hard_vers, sizeof(eup->eu_config.ac_hard_vers), "%ld/%ld/%ld", (val >> ID_SHIFT) & ID_MASK, (val >> MID_SHIFT) & MID_MASK, (val >> DID_SHIFT) & DID_MASK ); /* * There is no software version number */ eup->eu_config.ac_firm_vers[0] = '\0'; /* * Save device ram info for user-level programs * NOTE: This really points to start of EEPROM * and includes all the device registers in the * lower 2 Megabytes. */ eup->eu_config.ac_ram = (long)eup->eu_base; eup->eu_config.ac_ramsize = eup->eu_ramsize + ENI_REG_SIZE; /* * Setup max VPI/VCI values */ eup->eu_pif.pif_maxvpi = ENI_MAX_VPI; eup->eu_pif.pif_maxvci = ENI_MAX_VCI; /* * Register this interface with ATM core services */ error = atm_physif_register((Cmn_unit *)eup, ENI_DEV_NAME, eni_services); if (error) goto fail; eni_units[device_get_unit(dev)] = eup; /* * Initialize driver processing */ error = eni_init(eup); if (error) { device_printf(dev, "adapter init failed.\n"); goto fail; } fail: return (error); } int hea_detach (device_t dev) { struct hea_softc *sc; Eni_unit *eup; int error; sc = (struct hea_softc *)device_get_softc(dev); eup = &sc->eup; error = 0; /* * De-Register this interface with ATM core services */ error = atm_physif_deregister((Cmn_unit *)eup); /* * Reset the board. */ hea_reset(dev); hea_free(dev); return (error); } void hea_intr (void * arg) { struct hea_softc *sc; sc = (struct hea_softc *)arg; HEA_LOCK(sc); eni_intr(&sc->eup); HEA_UNLOCK(sc); return; } void hea_reset (device_t dev) { struct hea_softc *sc; Eni_unit *eup; sc = (struct hea_softc *)device_get_softc(dev); eup = &sc->eup; /* * We should really close down any open VCI's and * release all memory (TX and RX) buffers. For now, * we assume we're shutting the card down for good. */ if (eup->eu_midway) { /* * Issue RESET command to Midway chip */ eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET; /* * Delay to allow everything to terminate */ DELAY(MIDWAY_DELAY); } return; } static int hea_modevent (module_t mod, int type, void *data) { int error; error = 0; switch (type) { case MOD_LOAD: eni_nif_zone = uma_zcreate("eni nif", sizeof(struct atm_nif), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); if (eni_nif_zone == NULL) panic("%s(): uma_zcreate nif", __func__); uma_zone_set_max(eni_nif_zone, 52); eni_vcc_zone = uma_zcreate("eni vcc", sizeof(Eni_vcc), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); if (eni_vcc_zone == NULL) panic("%s(): uma_zcreate vcc", __func__); uma_zone_set_max(eni_vcc_zone, 100); break; case MOD_UNLOAD: uma_zdestroy(eni_nif_zone); uma_zdestroy(eni_vcc_zone); break; default: break; } return (error); } static moduledata_t hea_moduledata = { "hea", hea_modevent, NULL }; DECLARE_MODULE(hea, hea_moduledata, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_VERSION(hea, 1);