159816Smdodd/*- 259816Smdodd * Copyright (c) 2000 Matthew N. Dodd 359816Smdodd * All rights reserved. 459816Smdodd * 559816Smdodd * Redistribution and use in source and binary forms, with or without 659816Smdodd * modification, are permitted provided that the following conditions 759816Smdodd * are met: 859816Smdodd * 1. Redistributions of source code must retain the above copyright 959816Smdodd * notice, this list of conditions and the following disclaimer. 1059816Smdodd * 2. Redistributions in binary form must reproduce the above copyright 1159816Smdodd * notice, this list of conditions and the following disclaimer in the 1259816Smdodd * documentation and/or other materials provided with the distribution. 1359816Smdodd * 1459816Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559816Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659816Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759816Smdodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859816Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959816Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059816Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159816Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259816Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359816Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459816Smdodd * SUCH DAMAGE. 2559816Smdodd * 2659816Smdodd */ 2759816Smdodd 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD$"); 30119418Sobrien 3159816Smdodd#include <sys/param.h> 3259816Smdodd#include <sys/systm.h> 3359816Smdodd#include <sys/kernel.h> 3459816Smdodd#include <sys/socket.h> 3559816Smdodd 3659816Smdodd#include <sys/module.h> 3759816Smdodd#include <sys/bus.h> 3859816Smdodd 3959816Smdodd#include <machine/bus.h> 4059816Smdodd#include <machine/resource.h> 4159816Smdodd#include <sys/rman.h> 4259816Smdodd 4359816Smdodd#include <net/if.h> 4459816Smdodd#include <net/if_arp.h> 4559816Smdodd#include <net/if_media.h> 4659816Smdodd 4759816Smdodd 4859816Smdodd#include <isa/isavar.h> 4959816Smdodd#include <isa/pnpvar.h> 5059816Smdodd 5159816Smdodd#include <dev/ex/if_exreg.h> 5259816Smdodd#include <dev/ex/if_exvar.h> 5359816Smdodd 5459816Smdodd/* Bus Front End Functions */ 55131192Simpstatic void ex_isa_identify(driver_t *, device_t); 56131192Simpstatic int ex_isa_probe(device_t); 57131192Simpstatic int ex_isa_attach(device_t); 5859816Smdodd 59131192Simpstatic int ex_look_for_card(struct ex_softc *); 60131192Simp 6159816Smdodd#if 0 62131192Simpstatic void ex_pnp_wakeup(void *); 6359816Smdodd 6459816SmdoddSYSINIT(ex_pnpwakeup, SI_SUB_CPU, SI_ORDER_ANY, ex_pnp_wakeup, NULL); 6559816Smdodd#endif 6659816Smdodd 67112801Smdoddstatic device_method_t ex_isa_methods[] = { 6859816Smdodd /* Device interface */ 6959816Smdodd DEVMETHOD(device_identify, ex_isa_identify), 7059816Smdodd DEVMETHOD(device_probe, ex_isa_probe), 7159816Smdodd DEVMETHOD(device_attach, ex_isa_attach), 72112800Smdodd DEVMETHOD(device_detach, ex_detach), 7359816Smdodd 7459816Smdodd { 0, 0 } 7559816Smdodd}; 7659816Smdodd 77112801Smdoddstatic driver_t ex_isa_driver = { 7859816Smdodd "ex", 79112801Smdodd ex_isa_methods, 8059816Smdodd sizeof(struct ex_softc), 8159816Smdodd}; 8259816Smdodd 83112801SmdoddDRIVER_MODULE(ex, isa, ex_isa_driver, ex_devclass, 0, 0); 8459816Smdodd 8559816Smdoddstatic struct isa_pnp_id ex_ids[] = { 8659816Smdodd { 0x3110d425, NULL }, /* INT1031 */ 8759816Smdodd { 0x3010d425, NULL }, /* INT1030 */ 8859816Smdodd { 0, NULL }, 8959816Smdodd}; 9059816Smdodd 9159816Smdodd#if 0 9259816Smdodd#define EX_PNP_WAKE 0x279 9359816Smdodd 94131192Simpstatic uint8_t ex_pnp_wake_seq[] = 9559816Smdodd { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, 9659816Smdodd 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 9759816Smdodd 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, 9859816Smdodd 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43 }; 9959816Smdodd 10059816Smdoddstatic void 10159816Smdoddex_pnp_wakeup (void * dummy) 10259816Smdodd{ 10359816Smdodd int tmp; 10459816Smdodd 10559816Smdodd if (bootverbose) 10659816Smdodd printf("ex_pnp_wakeup()\n"); 10759816Smdodd 10859816Smdodd outb(EX_PNP_WAKE, 0); 10959816Smdodd outb(EX_PNP_WAKE, 0); 11059816Smdodd for (tmp = 0; tmp < 32; tmp++) { 11159816Smdodd outb(EX_PNP_WAKE, ex_pnp_wake_seq[tmp]); 11259816Smdodd } 11359816Smdodd} 11459816Smdodd#endif 11559816Smdodd 11659816Smdodd/* 11759816Smdodd * Non-destructive identify. 11859816Smdodd */ 11959816Smdoddstatic void 120131192Simpex_isa_identify(driver_t *driver, device_t parent) 12159816Smdodd{ 12259816Smdodd device_t child; 123131192Simp bus_addr_t ioport; 12459816Smdodd u_char enaddr[6]; 12559816Smdodd u_int irq; 12659816Smdodd int tmp; 12759816Smdodd const char * desc; 128131192Simp struct ex_softc sc; 129131192Simp int rid; 13059816Smdodd 13159816Smdodd if (bootverbose) 13259816Smdodd printf("ex_isa_identify()\n"); 13359816Smdodd 13459816Smdodd for (ioport = 0x200; ioport < 0x3a0; ioport += 0x10) { 135131192Simp rid = 0; 136179775Sjhb sc.ioport = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid, 137131192Simp ioport, ioport, 0x10, RF_ACTIVE); 138179775Sjhb if (sc.ioport == NULL) 139131192Simp continue; 14059816Smdodd 14159816Smdodd /* No board found at address */ 142131192Simp if (!ex_look_for_card(&sc)) { 143179775Sjhb bus_release_resource(parent, SYS_RES_IOPORT, rid, 144179775Sjhb sc.ioport); 14559816Smdodd continue; 14659816Smdodd } 14759816Smdodd 14859816Smdodd if (bootverbose) 149131247Simp printf("ex: Found card at 0x%03lx!\n", (unsigned long)ioport); 15059816Smdodd 15159816Smdodd /* Board in PnP mode */ 152131192Simp if (ex_eeprom_read(&sc, EE_W0) & EE_W0_PNP) { 15359816Smdodd /* Reset the card. */ 154131192Simp CSR_WRITE_1(&sc, CMD_REG, Reset_CMD); 15559816Smdodd DELAY(500); 15659816Smdodd if (bootverbose) 157131247Simp printf("ex: card at 0x%03lx in PnP mode!\n", (unsigned long)ioport); 158179775Sjhb bus_release_resource(parent, SYS_RES_IOPORT, rid, 159179775Sjhb sc.ioport); 16059816Smdodd continue; 16159816Smdodd } 16259816Smdodd 16359816Smdodd bzero(enaddr, sizeof(enaddr)); 16459816Smdodd 16559816Smdodd /* Reset the card. */ 166131192Simp CSR_WRITE_1(&sc, CMD_REG, Reset_CMD); 16759816Smdodd DELAY(400); 16859816Smdodd 169131192Simp ex_get_address(&sc, enaddr); 170131192Simp tmp = ex_eeprom_read(&sc, EE_W1) & EE_W1_INT_SEL; 17159816Smdodd 17259816Smdodd /* work out which set of irq <-> internal tables to use */ 17359816Smdodd if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) { 17459816Smdodd irq = plus_ee2irqmap[tmp]; 17559816Smdodd desc = "Intel Pro/10+"; 17659816Smdodd } else { 17759816Smdodd irq = ee2irqmap[tmp]; 17859816Smdodd desc = "Intel Pro/10"; 17959816Smdodd } 18059816Smdodd 181179775Sjhb bus_release_resource(parent, SYS_RES_IOPORT, rid, sc.ioport); 18259816Smdodd child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ex", -1); 18359816Smdodd device_set_desc_copy(child, desc); 18459816Smdodd device_set_driver(child, driver); 18559816Smdodd bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); 18659816Smdodd bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EX_IOSIZE); 18759816Smdodd if (bootverbose) 188131248Simp printf("ex: Adding board at 0x%03lx, irq %d\n", 189131248Simp (unsigned long)ioport, irq); 19059816Smdodd } 19159816Smdodd 19259816Smdodd return; 19359816Smdodd} 19459816Smdodd 19559816Smdoddstatic int 19659816Smdoddex_isa_probe(device_t dev) 19759816Smdodd{ 198131192Simp bus_addr_t iobase; 19959816Smdodd u_int irq; 20059816Smdodd char * irq2ee; 20159816Smdodd u_char * ee2irq; 20259816Smdodd u_char enaddr[6]; 20359816Smdodd int tmp; 20459816Smdodd int error; 205131192Simp struct ex_softc *sc = device_get_softc(dev); 20659816Smdodd 20759816Smdodd /* Check isapnp ids */ 20859816Smdodd error = ISA_PNP_PROBE(device_get_parent(dev), dev, ex_ids); 20959816Smdodd 21059816Smdodd /* If the card had a PnP ID that didn't match any we know about */ 211131192Simp if (error == ENXIO) 21259816Smdodd return(error); 21359816Smdodd 21459816Smdodd /* If we had some other problem. */ 215131192Simp if (!(error == 0 || error == ENOENT)) 21659816Smdodd return(error); 21759816Smdodd 218131192Simp error = ex_alloc_resources(dev); 219131192Simp if (error != 0) 220131192Simp goto bad; 22159816Smdodd iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0); 222131192Simp if (!ex_look_for_card(sc)) { 223131192Simp if (bootverbose) 224131247Simp printf("ex: no card found at 0x%03lx.\n", (unsigned long)iobase); 225131192Simp error = ENXIO; 226131192Simp goto bad; 22759816Smdodd } 22859816Smdodd if (bootverbose) 229131247Simp printf("ex: ex_isa_probe() found card at 0x%03lx\n", (unsigned long)iobase); 23059816Smdodd 23159816Smdodd /* 23259816Smdodd * Reset the card. 23359816Smdodd */ 234131192Simp CSR_WRITE_1(sc, CMD_REG, Reset_CMD); 23559816Smdodd DELAY(800); 23659816Smdodd 237131192Simp ex_get_address(sc, enaddr); 23859816Smdodd 23959816Smdodd /* work out which set of irq <-> internal tables to use */ 24059816Smdodd if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) { 24159816Smdodd irq2ee = plus_irq2eemap; 24259816Smdodd ee2irq = plus_ee2irqmap; 24359816Smdodd } else { 24459816Smdodd irq2ee = irq2eemap; 24559816Smdodd ee2irq = ee2irqmap; 24659816Smdodd } 24759816Smdodd 248131192Simp tmp = ex_eeprom_read(sc, EE_W1) & EE_W1_INT_SEL; 24959816Smdodd irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0); 25059816Smdodd if (irq > 0) { 25159816Smdodd /* This will happen if board is in PnP mode. */ 25259816Smdodd if (ee2irq[tmp] != irq) { 253182088Simp device_printf(dev, 254182088Simp "WARNING: IRQ mismatch: EEPROM %d, using %d\n", 25559816Smdodd ee2irq[tmp], irq); 25659816Smdodd } 25759816Smdodd } else { 25859816Smdodd irq = ee2irq[tmp]; 25959816Smdodd bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); 26059816Smdodd } 26159816Smdodd 26259816Smdodd if (irq == 0) { 26359816Smdodd printf("ex: invalid IRQ.\n"); 264131192Simp error = ENXIO; 26559816Smdodd } 26659816Smdodd 267131192Simpbad:; 268131192Simp ex_release_resources(dev); 269182088Simp return (error); 27059816Smdodd} 27159816Smdodd 27259816Smdoddstatic int 27359816Smdoddex_isa_attach(device_t dev) 27459816Smdodd{ 27559816Smdodd struct ex_softc * sc = device_get_softc(dev); 27659816Smdodd int error = 0; 277131192Simp uint16_t temp; 27859816Smdodd 27959816Smdodd sc->dev = dev; 28059816Smdodd sc->ioport_rid = 0; 28159816Smdodd sc->irq_rid = 0; 282182088Simp sc->flags |= HAS_INT_NO_REG; 28359816Smdodd 28459816Smdodd if ((error = ex_alloc_resources(dev)) != 0) { 28559816Smdodd device_printf(dev, "ex_alloc_resources() failed!\n"); 28659816Smdodd goto bad; 28759816Smdodd } 28859816Smdodd 28959816Smdodd /* 29059816Smdodd * Fill in several fields of the softc structure: 29159816Smdodd * - I/O base address. 29259816Smdodd * - Hardware Ethernet address. 29359816Smdodd * - IRQ number (if not supplied in config file, read it from EEPROM). 29459816Smdodd * - Connector type. 29559816Smdodd */ 29659816Smdodd sc->irq_no = rman_get_start(sc->irq); 29759816Smdodd 298147256Sbrooks ex_get_address(sc, sc->enaddr); 29959816Smdodd 300131192Simp temp = ex_eeprom_read(sc, EE_W0); 30159816Smdodd device_printf(sc->dev, "%s config, %s bus, ", 30259816Smdodd (temp & EE_W0_PNP) ? "PnP" : "Manual", 30359816Smdodd (temp & EE_W0_BUS16) ? "16-bit" : "8-bit"); 30459816Smdodd 305131192Simp temp = ex_eeprom_read(sc, EE_W6); 30659816Smdodd printf("board id 0x%03x, stepping 0x%01x\n", 30759816Smdodd (temp & EE_W6_BOARD_MASK) >> EE_W6_BOARD_SHIFT, 30859816Smdodd temp & EE_W6_STEP_MASK); 30959816Smdodd 31059816Smdodd if ((error = ex_attach(dev)) != 0) { 31159816Smdodd device_printf(dev, "ex_attach() failed!\n"); 31259816Smdodd goto bad; 31359816Smdodd } 31459816Smdodd 31559816Smdodd return(0); 31659816Smdoddbad: 31759816Smdodd ex_release_resources(dev); 31859816Smdodd return (error); 31959816Smdodd} 320131192Simp 321131192Simpstatic int 322131192Simpex_look_for_card(struct ex_softc *sc) 323131192Simp{ 324131192Simp int count1, count2; 325131192Simp 326131192Simp /* 327131192Simp * Check for the i82595 signature, and check that the round robin 328131192Simp * counter actually advances. 329131192Simp */ 330131192Simp if (((count1 = CSR_READ_1(sc, ID_REG)) & Id_Mask) != Id_Sig) 331131192Simp return(0); 332131192Simp count2 = CSR_READ_1(sc, ID_REG); 333131192Simp count2 = CSR_READ_1(sc, ID_REG); 334131192Simp count2 = CSR_READ_1(sc, ID_REG); 335131192Simp 336131192Simp return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits)); 337131192Simp} 338