1112790Smdodd/*- 2112790Smdodd * Copyright (c) 2003 Matthew N. Dodd 3112790Smdodd * All rights reserved. 4112790Smdodd * 5112790Smdodd * Redistribution and use in source and binary forms, with or without 6112790Smdodd * modification, are permitted provided that the following conditions 7112790Smdodd * are met: 8112790Smdodd * 1. Redistributions of source code must retain the above copyright 9112790Smdodd * notice, this list of conditions and the following disclaimer. 10112790Smdodd * 2. Redistributions in binary form must reproduce the above copyright 11112790Smdodd * notice, this list of conditions and the following disclaimer in the 12112790Smdodd * documentation and/or other materials provided with the distribution. 13112790Smdodd * 14112790Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15112790Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16112790Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17112790Smdodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18112790Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19112790Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20112790Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21112790Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22112790Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23112790Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24112790Smdodd * SUCH DAMAGE. 25112790Smdodd * 26112790Smdodd * Portions: 27112790Smdodd * Copyright (c) 1992, 1993, University of Vermont and State 28112790Smdodd * Agricultural College. 29112790Smdodd * Copyright (c) 1992, 1993, Garrett A. Wollman. 30112790Smdodd * Copyright (c) 1990, 1991, William F. Jolitz 31112790Smdodd * Copyright (c) 1990, The Regents of the University of California 32112790Smdodd * Copyright (c) 1993, 1994, Charles M. Hannum 33112790Smdodd * Copyright (c) 1993, 1994, 1995, Rodney W. Grimes 34112790Smdodd * Copyright (c) 1997, Aaron C. Smith 35112790Smdodd * 36112790Smdodd * See if_ie.c for applicable license. 37112790Smdodd */ 38112790Smdodd 39119418Sobrien#include <sys/cdefs.h> 40119418Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/dev/ie/if_ie_isa.c 297793 2016-04-10 23:07:00Z pfg $"); 41119418Sobrien 42112790Smdodd#include <sys/param.h> 43112790Smdodd#include <sys/systm.h> 44257324Sglebius#include <sys/lock.h> 45112790Smdodd#include <sys/kernel.h> 46257324Sglebius#include <sys/malloc.h> 47257324Sglebius#include <sys/mutex.h> 48112790Smdodd#include <sys/socket.h> 49112790Smdodd 50112790Smdodd#include <sys/module.h> 51112790Smdodd#include <sys/bus.h> 52112790Smdodd 53112790Smdodd#include <machine/bus.h> 54112790Smdodd#include <machine/resource.h> 55112790Smdodd#include <sys/rman.h> 56112790Smdodd 57112790Smdodd#include <machine/md_var.h> 58112790Smdodd 59112790Smdodd#include <net/if.h> 60112790Smdodd#include <net/if_media.h> 61112790Smdodd 62112790Smdodd#include <isa/isavar.h> 63112790Smdodd#include <isa/pnpvar.h> 64112790Smdodd 65112790Smdodd#include <i386/isa/elink.h> 66112790Smdodd 67112790Smdodd#include <dev/ic/i82586.h> 68112790Smdodd#include <dev/ie/if_ie507.h> 69112790Smdodd#include <dev/ie/if_iee16.h> 70112790Smdodd#include <dev/ie/if_iereg.h> 71112790Smdodd#include <dev/ie/if_ievar.h> 72112790Smdodd 73112790Smdoddstatic int ie_modevent (module_t, int, void *); 74112790Smdodd 75112790Smdoddstatic void ie_isa_3C507_identify (driver_t *, device_t); 76112790Smdoddstatic int ie_isa_3C507_probe (device_t); 77112790Smdoddstatic int ie_isa_3C507_attach (device_t); 78112790Smdoddstatic int ie_3C507_port_check (u_int32_t); 79112790Smdodd 80112790Smdoddstatic void ie_isa_ee16_identify (driver_t *, device_t); 81112790Smdoddstatic int ie_isa_ee16_probe (device_t); 82112790Smdoddstatic int ie_isa_ee16_attach (device_t); 83181134Sjhbstatic int ie_isa_ee16_shutdown (device_t); 84112790Smdoddstatic int ie_ee16_port_check (u_int32_t port); 85112790Smdoddstatic u_int16_t ie_ee16_hw_read_eeprom (u_int32_t port, int loc); 86112790Smdodd 87112790Smdoddstatic int ie_isa_sl_probe (device_t); 88112790Smdoddstatic int ie_isa_sl_attach (device_t); 89112790Smdoddstatic enum ie_hardware ie_isa_sl_get_hard_type (u_int32_t); 90112790Smdodd 91112790Smdodd/* 92112790Smdodd * 3Com 3C507 Etherlink 16 93112790Smdodd */ 94112790Smdodd#define IE_3C507_IOBASE_LOW 0x200 95112790Smdodd#define IE_3C507_IOBASE_HIGH 0x3e0 96112790Smdodd#define IE_3C507_IOSIZE 16 97112790Smdodd 98112790Smdodd#define IE_3C507_IRQ_MASK 0x0f 99112790Smdodd 100112790Smdodd#define IE_3C507_MADDR_HIGH 0x20 101112790Smdodd#define IE_3C507_MADDR_MASK 0x1c 102112790Smdodd#define IE_3C507_MADDR_BASE 0xc0000 103112790Smdodd#define IE_3C507_MADDR_SHIFT 12 104112790Smdodd 105112790Smdodd#define IE_3C507_MSIZE_MASK 3 106112790Smdodd#define IE_3C507_MSIZE_SHIFT 14 107112790Smdodd 108112790Smdoddstatic void 109112790Smdoddie_isa_3C507_identify (driver_t *driver, device_t parent) 110112790Smdodd{ 111112790Smdodd char * desc = "3Com 3C507 Etherlink 16"; 112112790Smdodd device_t child; 113112790Smdodd u_int32_t port, maddr, msize; 114112790Smdodd u_int8_t irq, data; 115112790Smdodd int error; 116112790Smdodd 117112790Smdodd /* Reset and put card in CONFIG state without changing address. */ 118112790Smdodd elink_reset(); 119112790Smdodd elink_idseq(ELINK_507_POLY); 120112790Smdodd elink_idseq(ELINK_507_POLY); 121112790Smdodd outb(ELINK_ID_PORT, 0xff); 122112790Smdodd 123112790Smdodd for (port = IE_3C507_IOBASE_LOW; 124112790Smdodd port <= IE_3C507_IOBASE_HIGH; 125112790Smdodd port += IE_3C507_IOSIZE) { 126112790Smdodd 127112790Smdodd if (ie_3C507_port_check(port)) { 128153110Sru#ifdef DEBUG 129112790Smdodd if (bootverbose) { 130112790Smdodd device_printf(parent, 131112790Smdodd "(if_ie) (3C507) not found at port %#x\n", 132112790Smdodd port); 133112790Smdodd } 134112790Smdodd#endif 135112790Smdodd continue; 136112790Smdodd } 137112790Smdodd 138112790Smdodd outb(port + IE507_CTRL, EL_CTRL_NRST); 139112790Smdodd 140112790Smdodd data = inb(port + IE507_IRQ); 141112790Smdodd irq = data & IE_3C507_IRQ_MASK; 142112790Smdodd 143112790Smdodd data = inb(port + IE507_MADDR); 144112790Smdodd 145112790Smdodd if (data & IE_3C507_MADDR_HIGH) { 146112790Smdodd if (bootverbose) { 147112790Smdodd device_printf(parent, 148112790Smdodd "(if_ie) can't map 3C507 RAM in high memory\n"); 149112790Smdodd } 150112790Smdodd continue; 151112790Smdodd } 152112790Smdodd 153112790Smdodd maddr = IE_3C507_MADDR_BASE + 154112790Smdodd ((data & IE_3C507_MADDR_MASK) 155112790Smdodd << IE_3C507_MADDR_SHIFT); 156112790Smdodd msize = ((data & IE_3C507_MSIZE_MASK) + 1) 157112790Smdodd << IE_3C507_MSIZE_SHIFT; 158112790Smdodd 159112790Smdodd child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1); 160112790Smdodd device_set_desc_copy(child, desc); 161112790Smdodd device_set_driver(child, driver); 162112790Smdodd 163112790Smdodd error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); 164112790Smdodd if (error) { 165112790Smdodd device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n", 166112790Smdodd irq); 167112790Smdodd error = device_delete_child(parent, child); 168112790Smdodd continue; 169112790Smdodd } 170112790Smdodd 171112790Smdodd error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_3C507_IOSIZE); 172112790Smdodd if (error) { 173112790Smdodd device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n", 174112790Smdodd port, port+IE_3C507_IOSIZE); 175112790Smdodd error = device_delete_child(parent, child); 176112790Smdodd continue; 177112790Smdodd } 178112790Smdodd 179112790Smdodd error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); 180112790Smdodd if (error) { 181112790Smdodd device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n", 182112790Smdodd maddr, maddr+msize); 183112790Smdodd error = device_delete_child(parent, child); 184112790Smdodd continue; 185112790Smdodd } 186112790Smdodd 187112790Smdodd if (bootverbose) { 188112790Smdodd device_printf(parent, 189112790Smdodd "(if_ie) <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n", 190112790Smdodd desc, 191112790Smdodd port, (port + IE_3C507_IOSIZE) - 1, 192112790Smdodd irq, 193112790Smdodd (u_long)maddr, (u_long)(maddr + msize) - 1, 194112790Smdodd (msize / 1024)); 195112790Smdodd } 196112790Smdodd } 197112790Smdodd 198112790Smdodd /* go to RUN state */ 199112790Smdodd outb(ELINK_ID_PORT, 0x00); 200112790Smdodd elink_idseq(ELINK_507_POLY); 201112790Smdodd outb(ELINK_ID_PORT, 0x00); 202112790Smdodd 203112790Smdodd return; 204112790Smdodd} 205112790Smdodd 206112790Smdoddstatic int 207112790Smdoddie_isa_3C507_probe (device_t dev) 208112790Smdodd{ 209112790Smdodd u_int32_t iobase; 210112790Smdodd 211112790Smdodd /* No ISA-PnP support */ 212112790Smdodd if (isa_get_vendorid(dev)) { 213112790Smdodd return (ENXIO); 214112790Smdodd } 215112790Smdodd 216112790Smdodd /* No ISA-HINT support */ 217112790Smdodd if (!device_get_desc(dev)) { 218112790Smdodd return (EBUSY); 219112790Smdodd } 220112790Smdodd 221112790Smdodd /* Have we at least an ioport? */ 222112790Smdodd if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0) { 223112790Smdodd return (ENXIO); 224112790Smdodd } 225112790Smdodd 226112790Smdodd /* Is this thing really a 3c507? */ 227112790Smdodd if (ie_3C507_port_check(iobase)) { 228112790Smdodd return (ENXIO); 229112790Smdodd } 230112790Smdodd 231112790Smdodd return (0); 232112790Smdodd} 233112790Smdodd 234112790Smdoddstatic int 235112790Smdoddie_isa_3C507_attach (device_t dev) 236112790Smdodd{ 237112790Smdodd struct ie_softc * sc; 238112790Smdodd int error; 239112790Smdodd 240112790Smdodd sc = device_get_softc(dev); 241112790Smdodd 242112790Smdodd sc->io_rid = 0; 243112790Smdodd sc->irq_rid = 0; 244112790Smdodd sc->mem_rid = 0; 245112790Smdodd 246112790Smdodd error = ie_alloc_resources(dev); 247112790Smdodd if (error) { 248112790Smdodd goto bad; 249112790Smdodd } 250112790Smdodd 251112790Smdodd sc->bus_use = 0; 252112790Smdodd sc->ie_reset_586 = el_reset_586; 253112790Smdodd sc->ie_chan_attn = el_chan_attn; 254112790Smdodd sc->hard_type = IE_3C507; 255112790Smdodd sc->hard_vers = 0; 256112790Smdodd 257112790Smdodd outb(PORT(sc) + IE507_CTRL, EL_CTRL_NORMAL); 258112790Smdodd 259112790Smdodd if (!check_ie_present(sc)) { 260112790Smdodd error = ENXIO; 261112790Smdodd goto bad; 262112790Smdodd } 263112790Smdodd 264147256Sbrooks sl_read_ether(sc, sc->enaddr); 265112790Smdodd 266112790Smdodd /* Clear the interrupt latch just in case. */ 267112790Smdodd outb(PORT(sc) + IE507_ICTRL, 1); 268112790Smdodd 269112790Smdodd error = ie_attach(dev); 270112790Smdodd if (error) { 271112790Smdodd device_printf(dev, "ie_attach() failed.\n"); 272112790Smdodd goto bad; 273112790Smdodd } 274112790Smdodd 275112790Smdodd return (0); 276112790Smdoddbad: 277112790Smdodd ie_release_resources(dev); 278112790Smdodd 279112790Smdodd return (error); 280112790Smdodd} 281112790Smdodd 282112790Smdodd/* 283112790Smdodd * If a 3c507 is present, return 0 284112790Smdodd * else, return 1. 285112790Smdodd */ 286112790Smdoddstatic int 287112790Smdoddie_3C507_port_check (u_int32_t port) 288112790Smdodd{ 289112790Smdodd u_char * signature = "*3COM*"; 290112790Smdodd int i; 291112790Smdodd 292112790Smdodd for (i = 0; i < 6; i++) 293112790Smdodd if (inb(port + i) != signature[i]) 294112790Smdodd return (ENXIO); 295112790Smdodd 296112790Smdodd return (0); 297112790Smdodd} 298112790Smdodd 299112790Smdodd/* 300112790Smdodd * Intel EtherExpress 16 301112790Smdodd */ 302112790Smdodd#define IE_EE16_ID_PORT 0x0f 303112790Smdodd#define IE_EE16_ID 0xbaba 304112790Smdodd#define IE_EE16_EEPROM_CONFIG1 0x00 305112790Smdodd#define IE_EE16_EEPROM_IRQ_MASK 0xe000 306112790Smdodd#define IE_EE16_EEPROM_IRQ_SHIFT 13 307112790Smdodd#define IE_EE16_EEPROM_MEMCFG 0x06 308112790Smdodd#define IE_EE16_IOSIZE 16 309112790Smdodd 310112790Smdodd/* 311112790Smdodd * TODO: 312112790Smdodd * Test for 8/16 bit mode. 313112790Smdodd * Test for invalid mem sizes. 314112790Smdodd */ 315112790Smdoddstatic void 316112790Smdoddie_isa_ee16_identify (driver_t *driver, device_t parent) 317112790Smdodd{ 318112790Smdodd char * desc = "Intel EtherExpress 16"; 319112790Smdodd device_t child; 320112790Smdodd u_int16_t ports[] = { 321112790Smdodd 0x300, 0x310, 0x320, 0x330, 322112790Smdodd 0x340, 0x350, 0x360, 0x370, 323112790Smdodd 0x200, 0x210, 0x220, 0x230, 324112790Smdodd 0x240, 0x250, 0x260, 0x270, 325112790Smdodd 0 326112790Smdodd }; 327112790Smdodd u_int16_t irqs[] = { 0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0 }; 328112790Smdodd u_int32_t port, maddr, msize; 329112790Smdodd u_int8_t irq; 330112790Smdodd u_int16_t data; 331112790Smdodd int i, error; 332112790Smdodd 333112790Smdodd for (i = 0; ports[i]; i++) { 334112790Smdodd port = ports[i]; 335112790Smdodd 336112790Smdodd if (ie_ee16_port_check(port)) { 337153110Sru#ifdef DEBUG 338112790Smdodd if (bootverbose) { 339112790Smdodd device_printf(parent, 340112790Smdodd "if_ie: (EE16) not found at port %#x\n", 341112790Smdodd port); 342112790Smdodd } 343112790Smdodd#endif 344112790Smdodd continue; 345112790Smdodd } 346112790Smdodd 347112790Smdodd /* reset any ee16 at the current iobase */ 348112790Smdodd outb(port + IEE16_ECTRL, IEE16_RESET_ASIC); 349112790Smdodd outb(port + IEE16_ECTRL, 0); 350112790Smdodd DELAY(240); 351112790Smdodd 352112790Smdodd data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_CONFIG1); 353112790Smdodd irq = irqs[((data & IE_EE16_EEPROM_IRQ_MASK) 354112790Smdodd >> IE_EE16_EEPROM_IRQ_SHIFT)]; 355112790Smdodd 356112790Smdodd data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_MEMCFG); 357112790Smdodd maddr = 0xc0000 + ((ffs(data & 0x00ff) - 1) * 0x4000); 358112790Smdodd msize = (fls((data & 0x00ff) >> (ffs(data & 0x00ff) - 1))) 359112790Smdodd * 0x4000; 360112790Smdodd 361112790Smdodd child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1); 362112790Smdodd device_set_desc_copy(child, desc); 363112790Smdodd device_set_driver(child, driver); 364112790Smdodd 365112790Smdodd error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); 366112790Smdodd if (error) { 367112790Smdodd device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n", 368112790Smdodd irq); 369112790Smdodd error = device_delete_child(parent, child); 370112790Smdodd continue; 371112790Smdodd } 372112790Smdodd 373112790Smdodd error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_EE16_IOSIZE); 374112790Smdodd if (error) { 375112790Smdodd device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n", 376112790Smdodd port, port+IE_EE16_IOSIZE); 377112790Smdodd error = device_delete_child(parent, child); 378112790Smdodd continue; 379112790Smdodd } 380112790Smdodd 381112790Smdodd error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); 382112790Smdodd if (error) { 383112790Smdodd device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n", 384112790Smdodd maddr, maddr+msize); 385112790Smdodd error = device_delete_child(parent, child); 386112790Smdodd continue; 387112790Smdodd } 388112790Smdodd 389112790Smdodd if (bootverbose) { 390112790Smdodd device_printf(parent, 391112790Smdodd "if_ie: <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n", 392112790Smdodd desc, 393112790Smdodd port, (port + IE_EE16_IOSIZE) - 1, 394112790Smdodd irq, 395112790Smdodd (u_long)maddr, (u_long)(maddr + msize) - 1, 396112790Smdodd (msize / 1024)); 397112790Smdodd } 398112790Smdodd } 399112790Smdodd 400112790Smdodd return; 401112790Smdodd} 402112790Smdodd 403112790Smdoddstatic int 404112790Smdoddie_isa_ee16_probe (device_t dev) 405112790Smdodd{ 406112790Smdodd u_int32_t iobase; 407112790Smdodd 408112790Smdodd /* No ISA-PnP support */ 409112790Smdodd if (isa_get_vendorid(dev)) 410112790Smdodd return (ENXIO); 411112790Smdodd 412112790Smdodd /* No ISA-HINT support */ 413112790Smdodd if (!device_get_desc(dev)) 414112790Smdodd return (EBUSY); 415112790Smdodd 416112790Smdodd /* Have we at least an ioport? */ 417112790Smdodd if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0) 418112790Smdodd return (ENXIO); 419112790Smdodd 420112790Smdodd /* Is this really an EE16? */ 421112790Smdodd if (ie_ee16_port_check(iobase)) 422112790Smdodd return (ENXIO); 423112790Smdodd 424112790Smdodd return (0); 425112790Smdodd} 426112790Smdodd 427112790Smdoddstatic int 428112790Smdoddie_isa_ee16_attach (device_t dev) 429112790Smdodd{ 430112790Smdodd struct ie_softc * sc; 431112790Smdodd int i, error; 432112790Smdodd u_int16_t checksum; 433112790Smdodd u_short eaddrtemp, pg, adjust, decode, edecode; 434112790Smdodd u_char bart_config; 435112790Smdodd 436112790Smdodd sc = device_get_softc(dev); 437112790Smdodd 438112790Smdodd sc->io_rid = 0; 439112790Smdodd sc->irq_rid = 0; 440112790Smdodd sc->mem_rid = 0; 441112790Smdodd 442112790Smdodd error = ie_alloc_resources(dev); 443112790Smdodd if (error) { 444112790Smdodd goto bad; 445112790Smdodd } 446112790Smdodd 447112790Smdodd sc->bus_use = 0; 448112790Smdodd sc->ie_reset_586 = ee16_reset_586; 449112790Smdodd sc->ie_chan_attn = ee16_chan_attn; 450112790Smdodd sc->hard_type = IE_EE16; 451112790Smdodd sc->hard_vers = 0; 452112790Smdodd sc->iomem = 0; 453112790Smdodd 454112790Smdodd /* reset any ee16 at the current iobase */ 455112790Smdodd outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_ASIC); 456112790Smdodd outb(PORT(sc) + IEE16_ECTRL, 0); 457112790Smdodd DELAY(240); 458112790Smdodd 459112790Smdodd /* Is this really an EE16? */ 460112790Smdodd if (ie_ee16_port_check(PORT(sc))) { 461112790Smdodd device_printf(dev, "ie_ee16_port_check() failed\n"); 462112790Smdodd error = ENXIO; 463112790Smdodd goto bad; 464112790Smdodd } 465112790Smdodd 466112790Smdodd /* need to put the 586 in RESET while we access the eeprom. */ 467112790Smdodd outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_586); 468112790Smdodd 469112790Smdodd /* read the eeprom and checksum it, should == IE_E16_ID */ 470112790Smdodd checksum = 0; 471112790Smdodd for (i = 0; i < 0x40; i++) 472112790Smdodd checksum += ie_ee16_hw_read_eeprom(PORT(sc), i); 473112790Smdodd 474112790Smdodd if (checksum != IE_EE16_ID) { 475112790Smdodd device_printf(dev, "invalid eeprom checksum: %x\n", checksum); 476112790Smdodd error = ENXIO; 477112790Smdodd goto bad; 478112790Smdodd } 479112790Smdodd 480112790Smdodd if ((kvtop(sc->iomembot) < 0xC0000) || 481112790Smdodd (kvtop(sc->iomembot) + sc->iosize > 0xF0000)) { 482112790Smdodd device_printf(sc->dev, "mapped memory location %p out of range\n", 483112790Smdodd (void *)sc->iomembot); 484112790Smdodd error = ENXIO; 485112790Smdodd goto bad; 486112790Smdodd } 487112790Smdodd 488112790Smdodd pg = ((kvtop(sc->iomembot)) & 0x3C000) >> 14; 489112790Smdodd adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2; 490112790Smdodd decode = ((1 << (sc->iosize / 16384)) - 1) << pg; 491112790Smdodd edecode = ((~decode >> 4) & 0xF0) | (decode >> 8); 492112790Smdodd 493112790Smdodd /* ZZZ This should be checked against eeprom location 6, low byte */ 494112790Smdodd outb(PORT(sc) + IEE16_MEMDEC, decode & 0xFF); 495112790Smdodd /* ZZZ This should be checked against eeprom location 1, low byte */ 496112790Smdodd outb(PORT(sc) + IEE16_MCTRL, adjust); 497112790Smdodd /* ZZZ Now if I could find this one I would have it made */ 498112790Smdodd outb(PORT(sc) + IEE16_MPCTRL, (~decode & 0xFF)); 499112790Smdodd /* ZZZ I think this is location 6, high byte */ 500112790Smdodd outb(PORT(sc) + IEE16_MECTRL, edecode); /* XXX disable Exxx */ 501112790Smdodd 502112790Smdodd#if 0 503112790Smdodd (void) kvtop(sc->iomembot); 504112790Smdodd#endif 505112790Smdodd 506112790Smdodd /* 507112790Smdodd * first prime the stupid bart DRAM controller so that it works, 508112790Smdodd * then zero out all of memory. 509112790Smdodd */ 510112790Smdodd bzero(sc->iomembot, 32); 511112790Smdodd bzero(sc->iomembot, sc->iosize); 512112790Smdodd 513112790Smdodd /* Get the encoded interrupt number from the EEPROM */ 514112790Smdodd sc->irq_encoded = ie_ee16_hw_read_eeprom(PORT(sc), 515112790Smdodd IE_EE16_EEPROM_CONFIG1); 516112790Smdodd sc->irq_encoded = (sc->irq_encoded & IE_EE16_EEPROM_IRQ_MASK) >> 517112790Smdodd IE_EE16_EEPROM_IRQ_SHIFT; 518112790Smdodd 519112790Smdodd /* 520112790Smdodd * Get the hardware ethernet address from the EEPROM and save it in 521112790Smdodd * the softc for use by the 586 setup code. 522112790Smdodd */ 523112790Smdodd eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_HIGH); 524147256Sbrooks sc->enaddr[1] = eaddrtemp & 0xFF; 525147256Sbrooks sc->enaddr[0] = eaddrtemp >> 8; 526112790Smdodd eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_MID); 527147256Sbrooks sc->enaddr[3] = eaddrtemp & 0xFF; 528147256Sbrooks sc->enaddr[2] = eaddrtemp >> 8; 529112790Smdodd eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_LOW); 530147256Sbrooks sc->enaddr[5] = eaddrtemp & 0xFF; 531147256Sbrooks sc->enaddr[4] = eaddrtemp >> 8; 532112790Smdodd 533112790Smdodd /* disable the board interrupts */ 534112790Smdodd outb(PORT(sc) + IEE16_IRQ, sc->irq_encoded); 535112790Smdodd 536112790Smdodd /* enable loopback to keep bad packets off the wire */ 537112790Smdodd bart_config = inb(PORT(sc) + IEE16_CONFIG); 538112790Smdodd bart_config |= IEE16_BART_LOOPBACK; 539112790Smdodd bart_config |= IEE16_BART_MCS16_TEST;/* inb doesn't get bit! */ 540112790Smdodd outb(PORT(sc) + IEE16_CONFIG, bart_config); 541112790Smdodd bart_config = inb(PORT(sc) + IEE16_CONFIG); 542112790Smdodd 543112790Smdodd /* take the board out of reset state */ 544112790Smdodd outb(PORT(sc) + IEE16_ECTRL, 0); 545112790Smdodd DELAY(100); 546112790Smdodd 547112790Smdodd if (!check_ie_present(sc)) { 548112790Smdodd device_printf(dev, "check_ie_present() returned false.\n"); 549112790Smdodd error = ENXIO; 550112790Smdodd goto bad; 551112790Smdodd } 552112790Smdodd 553112790Smdodd error = ie_attach(dev); 554112790Smdodd if (error) { 555112790Smdodd device_printf(dev, "ie_attach() failed.\n"); 556112790Smdodd goto bad; 557112790Smdodd } 558112790Smdodd 559112790Smdodd return (0); 560112790Smdoddbad: 561112790Smdodd ie_release_resources(dev); 562112790Smdodd 563112790Smdodd return (error); 564112790Smdodd} 565112790Smdodd 566181134Sjhbstatic int 567181134Sjhbie_isa_ee16_shutdown(device_t dev) 568181134Sjhb{ 569181134Sjhb struct ie_softc * sc; 570181134Sjhb 571181134Sjhb sc = device_get_softc(dev); 572181134Sjhb IE_LOCK(sc); 573181134Sjhb ee16_shutdown(sc); 574181134Sjhb IE_UNLOCK(sc); 575181134Sjhb 576181134Sjhb return (0); 577181134Sjhb} 578181134Sjhb 579112790Smdodd/* 580112790Smdodd * If an EE16 is present, return 0 581112790Smdodd * else, return 1. 582112790Smdodd */ 583112790Smdoddstatic int 584112790Smdoddie_ee16_port_check (u_int32_t port) 585112790Smdodd{ 586112790Smdodd int i; 587112790Smdodd u_int16_t board_id; 588112790Smdodd u_int8_t data; 589112790Smdodd 590112790Smdodd board_id = 0; 591112790Smdodd for (i = 0; i < 4; i++) { 592112790Smdodd data = inb(port + IE_EE16_ID_PORT); 593112790Smdodd board_id |= ((data >> 4) << ((data & 0x03) << 2)); 594112790Smdodd } 595112790Smdodd 596112790Smdodd if (board_id != IE_EE16_ID) 597112790Smdodd return (1); 598112790Smdodd 599112790Smdodd return (0); 600112790Smdodd} 601112790Smdodd 602112790Smdoddstatic void 603112790Smdoddie_ee16_hw_eeprom_clock (u_int32_t port, int state) 604112790Smdodd{ 605112790Smdodd u_int8_t ectrl; 606112790Smdodd 607112790Smdodd ectrl = inb(port + IEE16_ECTRL); 608112790Smdodd ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK); 609112790Smdodd 610112790Smdodd if (state) { 611112790Smdodd ectrl |= IEE16_ECTRL_EESK; 612112790Smdodd } 613112790Smdodd outb(port + IEE16_ECTRL, ectrl); 614112790Smdodd DELAY(9); /* EESK must be stable for 8.38 uSec */ 615112790Smdodd} 616112790Smdodd 617112790Smdoddstatic void 618112790Smdoddie_ee16_hw_eeprom_out (u_int32_t port, u_int16_t edata, int count) 619112790Smdodd{ 620112790Smdodd u_int8_t ectrl; 621112790Smdodd int i; 622112790Smdodd 623112790Smdodd ectrl = inb(port + IEE16_ECTRL); 624112790Smdodd ectrl &= ~IEE16_RESET_ASIC; 625112790Smdodd 626112790Smdodd for (i = count - 1; i >= 0; i--) { 627112790Smdodd ectrl &= ~IEE16_ECTRL_EEDI; 628112790Smdodd if (edata & (1 << i)) { 629112790Smdodd ectrl |= IEE16_ECTRL_EEDI; 630112790Smdodd } 631112790Smdodd outb(port + IEE16_ECTRL, ectrl); 632112790Smdodd DELAY(1); /* eeprom data must be setup for 0.4 uSec */ 633112790Smdodd ie_ee16_hw_eeprom_clock(port, 1); 634112790Smdodd ie_ee16_hw_eeprom_clock(port, 0); 635112790Smdodd } 636112790Smdodd ectrl &= ~IEE16_ECTRL_EEDI; 637112790Smdodd outb(port + IEE16_ECTRL, ectrl); 638112790Smdodd DELAY(1); /* eeprom data must be held for 0.4 uSec */ 639112790Smdodd 640112790Smdodd return; 641112790Smdodd} 642112790Smdodd 643112790Smdoddstatic u_int16_t 644112790Smdoddie_ee16_hw_eeprom_in (u_int32_t port) 645112790Smdodd{ 646112790Smdodd u_int8_t ectrl; 647112790Smdodd u_int16_t edata; 648112790Smdodd int i; 649112790Smdodd 650112790Smdodd ectrl = inb(port + IEE16_ECTRL); 651112790Smdodd ectrl &= ~IEE16_RESET_ASIC; 652112790Smdodd 653112790Smdodd for (edata = 0, i = 0; i < 16; i++) { 654112790Smdodd edata = edata << 1; 655112790Smdodd ie_ee16_hw_eeprom_clock(port, 1); 656112790Smdodd ectrl = inb(port + IEE16_ECTRL); 657112790Smdodd if (ectrl & IEE16_ECTRL_EEDO) { 658112790Smdodd edata |= 1; 659112790Smdodd } 660112790Smdodd ie_ee16_hw_eeprom_clock(port, 0); 661112790Smdodd } 662112790Smdodd return (edata); 663112790Smdodd} 664112790Smdodd 665112790Smdoddstatic u_int16_t 666112790Smdoddie_ee16_hw_read_eeprom (u_int32_t port, int loc) 667112790Smdodd{ 668112790Smdodd u_int8_t ectrl; 669112790Smdodd u_int16_t edata; 670112790Smdodd 671112790Smdodd ectrl = inb(port + IEE16_ECTRL); 672112790Smdodd ectrl &= IEE16_ECTRL_MASK; 673112790Smdodd ectrl |= IEE16_ECTRL_EECS; 674112790Smdodd outb(port + IEE16_ECTRL, ectrl); 675112790Smdodd 676112790Smdodd ie_ee16_hw_eeprom_out(port, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1); 677112790Smdodd ie_ee16_hw_eeprom_out(port, loc, IEE16_EEPROM_ADDR_SIZE); 678112790Smdodd edata = ie_ee16_hw_eeprom_in(port); 679112790Smdodd 680112790Smdodd ectrl = inb(port + IEE16_ECTRL); 681112790Smdodd ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS); 682112790Smdodd outb(port + IEE16_ECTRL, ectrl); 683112790Smdodd 684112790Smdodd ie_ee16_hw_eeprom_clock(port, 1); 685112790Smdodd ie_ee16_hw_eeprom_clock(port, 0); 686112790Smdodd 687112790Smdodd return (edata); 688112790Smdodd} 689112790Smdodd 690112790Smdodd/* 691112790Smdodd * AT&T StarLan/ 692112790Smdodd */ 693112790Smdodd 694112790Smdoddstatic int 695112790Smdoddie_isa_sl_probe (device_t dev) 696112790Smdodd{ 697112790Smdodd u_int32_t iobase; 698112790Smdodd 699112790Smdodd /* No ISA-PnP support */ 700112790Smdodd if (isa_get_vendorid(dev)) 701112790Smdodd return (ENXIO); 702112790Smdodd 703112790Smdodd /* ISA-HINT support only! */ 704112790Smdodd if (device_get_desc(dev)) 705112790Smdodd return (EBUSY); 706112790Smdodd 707112790Smdodd /* Have we at least an ioport? */ 708112790Smdodd if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0) 709112790Smdodd return (ENXIO); 710112790Smdodd 711112790Smdodd /* Is this really an SL board? */ 712112790Smdodd if (ie_isa_sl_get_hard_type(iobase) == IE_NONE) 713112790Smdodd return (ENXIO); 714112790Smdodd 715112790Smdodd return (ENXIO); 716112790Smdodd} 717112790Smdodd 718112790Smdoddstatic int 719112790Smdoddie_isa_sl_attach (device_t dev) 720112790Smdodd{ 721112790Smdodd struct ie_softc * sc; 722112790Smdodd int error; 723112790Smdodd 724112790Smdodd sc = device_get_softc(dev); 725112790Smdodd 726112790Smdodd sc->io_rid = 0; 727112790Smdodd sc->irq_rid = 0; 728112790Smdodd sc->mem_rid = 0; 729112790Smdodd 730112790Smdodd error = ie_alloc_resources(dev); 731112790Smdodd if (error) { 732112790Smdodd goto bad; 733112790Smdodd } 734112790Smdodd 735112790Smdodd /* Is this really an SL board? */ 736112790Smdodd if ((sc->hard_type = ie_isa_sl_get_hard_type(PORT(sc))) == IE_NONE) { 737112790Smdodd error = ENXIO; 738112790Smdodd goto bad; 739112790Smdodd } 740112790Smdodd 741112790Smdodd sc->hard_vers = SL_REV(inb(PORT(sc) + IEATT_REVISION)); 742112790Smdodd if (sc->hard_type == IE_NI5210) { 743112790Smdodd sc->bus_use = 1; 744112790Smdodd } else { 745112790Smdodd sc->bus_use = 0; 746112790Smdodd } 747112790Smdodd 748112790Smdodd sc->ie_reset_586 = sl_reset_586; 749112790Smdodd sc->ie_chan_attn = sl_chan_attn; 750112790Smdodd 751112790Smdodd if (!check_ie_present(sc)) { 752112790Smdodd error = ENXIO; 753112790Smdodd goto bad; 754112790Smdodd } 755112790Smdodd 756112790Smdodd switch (sc->hard_type) { 757112790Smdodd case IE_EN100: 758112790Smdodd case IE_STARLAN10: 759112790Smdodd case IE_SLFIBER: 760112790Smdodd case IE_NI5210: 761147256Sbrooks sl_read_ether(sc, sc->enaddr); 762112790Smdodd break; 763112790Smdodd default: 764112790Smdodd if (bootverbose) 765112790Smdodd device_printf(sc->dev, "unknown AT&T board type code %d\n", sc->hard_type); 766112790Smdodd error = ENXIO; 767112790Smdodd goto bad; 768112790Smdodd break; 769112790Smdodd } 770112790Smdodd 771112790Smdodd error = ie_attach(dev); 772112790Smdodd if (error) { 773112790Smdodd device_printf(dev, "ie_attach() failed.\n"); 774112790Smdodd goto bad; 775112790Smdodd } 776112790Smdodd 777112790Smdodd return (0); 778112790Smdoddbad: 779112790Smdodd ie_release_resources(dev); 780112790Smdodd 781112790Smdodd return (error); 782112790Smdodd} 783112790Smdodd 784112790Smdoddstatic enum ie_hardware 785112790Smdoddie_isa_sl_get_hard_type (u_int32_t port) 786112790Smdodd{ 787112790Smdodd u_char c; 788112790Smdodd enum ie_hardware retval; 789112790Smdodd 790112790Smdodd c = inb(port + IEATT_REVISION); 791112790Smdodd switch (SL_BOARD(c)) { 792112790Smdodd case SL1_BOARD: 793112790Smdodd if (inb(port + IEATT_ATTRIB) != NI5210_BOARD) 794112790Smdodd retval = IE_NONE; 795112790Smdodd retval = IE_NI5210; 796112790Smdodd break; 797112790Smdodd case SL10_BOARD: 798112790Smdodd retval = IE_STARLAN10; 799112790Smdodd break; 800112790Smdodd case EN100_BOARD: 801112790Smdodd retval = IE_EN100; 802112790Smdodd break; 803112790Smdodd case SLFIBER_BOARD: 804112790Smdodd retval = IE_SLFIBER; 805112790Smdodd break; 806112790Smdodd default: 807112790Smdodd retval = IE_NONE; 808112790Smdodd } 809112790Smdodd return (retval); 810112790Smdodd} 811112790Smdodd 812112790Smdoddstatic devclass_t ie_devclass; 813112790Smdodd 814112790Smdoddstatic device_method_t ie_isa_3C507_methods[] = { 815112790Smdodd DEVMETHOD(device_identify, ie_isa_3C507_identify), 816112790Smdodd DEVMETHOD(device_probe, ie_isa_3C507_probe), 817112790Smdodd DEVMETHOD(device_attach, ie_isa_3C507_attach), 818112790Smdodd DEVMETHOD(device_detach, ie_detach), 819112790Smdodd { 0, 0 } 820112790Smdodd}; 821179559Sjhb 822112790Smdoddstatic driver_t ie_isa_3C507_driver = { 823112790Smdodd "ie", 824112790Smdodd ie_isa_3C507_methods, 825112790Smdodd sizeof(struct ie_softc), 826112790Smdodd}; 827179559Sjhb 828112790SmdoddDRIVER_MODULE(ie_3C507, isa, ie_isa_3C507_driver, ie_devclass, ie_modevent, 0); 829112790SmdoddMODULE_DEPEND(ie_3C507, elink, 1, 1, 1); 830112790Smdodd 831112790Smdoddstatic device_method_t ie_isa_ee16_methods[] = { 832112790Smdodd DEVMETHOD(device_identify, ie_isa_ee16_identify), 833112790Smdodd DEVMETHOD(device_probe, ie_isa_ee16_probe), 834112790Smdodd DEVMETHOD(device_attach, ie_isa_ee16_attach), 835181134Sjhb DEVMETHOD(device_shutdown, ie_isa_ee16_shutdown), 836112790Smdodd DEVMETHOD(device_detach, ie_detach), 837112790Smdodd { 0, 0 } 838112790Smdodd}; 839179559Sjhb 840112790Smdoddstatic driver_t ie_isa_ee16_driver = { 841112790Smdodd "ie", 842112790Smdodd ie_isa_ee16_methods, 843112790Smdodd sizeof(struct ie_softc), 844112790Smdodd}; 845112790Smdodd 846179559SjhbDRIVER_MODULE(ie, isa, ie_isa_ee16_driver, ie_devclass, ie_modevent, 0); 847179559Sjhb 848112790Smdoddstatic device_method_t ie_isa_sl_methods[] = { 849112790Smdodd DEVMETHOD(device_probe, ie_isa_sl_probe), 850112790Smdodd DEVMETHOD(device_attach, ie_isa_sl_attach), 851112790Smdodd DEVMETHOD(device_detach, ie_detach), 852112790Smdodd { 0, 0 } 853112790Smdodd}; 854179559Sjhb 855112790Smdoddstatic driver_t ie_isa_sl_driver = { 856112790Smdodd "ie", 857112790Smdodd ie_isa_sl_methods, 858112790Smdodd sizeof(struct ie_softc), 859112790Smdodd}; 860179559Sjhb 861112790SmdoddDRIVER_MODULE(ie_SL, isa, ie_isa_sl_driver, ie_devclass, ie_modevent, 0); 862112790Smdodd 863112790Smdoddstatic int 864112790Smdoddie_modevent (mod, what, arg) 865112790Smdodd module_t mod; 866112790Smdodd int what; 867112790Smdodd void * arg; 868112790Smdodd{ 869112790Smdodd device_t * devs; 870112790Smdodd int count; 871112790Smdodd int i; 872112790Smdodd 873112790Smdodd switch (what) { 874112790Smdodd case MOD_LOAD: 875112790Smdodd break; 876112790Smdodd case MOD_UNLOAD: 877112790Smdodd devclass_get_devices(ie_devclass, &devs, &count); 878112790Smdodd for (i = 0; i < count; i++) 879112790Smdodd device_delete_child(device_get_parent(devs[i]), devs[i]); 880241066Skevlo free(devs, M_TEMP); 881112790Smdodd break; 882112790Smdodd default: 883112790Smdodd break; 884297793Spfg } 885112790Smdodd 886112790Smdodd return (0); 887112790Smdodd} 888