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