1141586Simp/*- 2141586Simp * Copyright (c) 2005, M. Warner Losh 3141586Simp * All rights reserved. 4141586Simp * Copyright (c) 1995, David Greenman 5141586Simp * All rights reserved. 6141586Simp * 7141586Simp * Redistribution and use in source and binary forms, with or without 8141586Simp * modification, are permitted provided that the following conditions 9141586Simp * are met: 10141586Simp * 1. Redistributions of source code must retain the above copyright 11141586Simp * notice unmodified, this list of conditions, and the following 12141586Simp * disclaimer. 13141586Simp * 2. Redistributions in binary form must reproduce the above copyright 14141586Simp * notice, this list of conditions and the following disclaimer in the 15141586Simp * documentation and/or other materials provided with the distribution. 16141586Simp * 17141586Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18141586Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19141586Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20141586Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21141586Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22141586Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23141586Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24141586Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25141586Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26141586Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27141586Simp * SUCH DAMAGE. 28141586Simp */ 29141586Simp 30141586Simp#include <sys/cdefs.h> 31141586Simp__FBSDID("$FreeBSD$"); 32141586Simp 33141586Simp#include "opt_ed.h" 34141586Simp 35141586Simp#include <sys/param.h> 36141586Simp#include <sys/systm.h> 37141586Simp#include <sys/sockio.h> 38141586Simp#include <sys/mbuf.h> 39141586Simp#include <sys/kernel.h> 40141586Simp#include <sys/socket.h> 41141586Simp#include <sys/syslog.h> 42141586Simp 43141586Simp#include <sys/bus.h> 44141586Simp 45141586Simp#include <machine/bus.h> 46141586Simp#include <sys/rman.h> 47141586Simp#include <machine/resource.h> 48141586Simp 49141586Simp#include <net/ethernet.h> 50141586Simp#include <net/if.h> 51141586Simp#include <net/if_arp.h> 52141586Simp#include <net/if_dl.h> 53141586Simp#include <net/if_mib.h> 54141586Simp#include <net/if_media.h> 55141586Simp 56141586Simp#include <net/bpf.h> 57141586Simp 58141586Simp#include <dev/ed/if_edreg.h> 59141586Simp#include <dev/ed/if_edvar.h> 60141586Simp 61141586Simp/* 62141586Simp * Interrupt conversion table for WD/SMC ASIC/83C584 63141586Simp */ 64141586Simpstatic uint16_t ed_intr_val[] = { 65141586Simp 9, 66141586Simp 3, 67141586Simp 5, 68141586Simp 7, 69141586Simp 10, 70141586Simp 11, 71141586Simp 15, 72141586Simp 4 73141586Simp}; 74141586Simp 75141586Simp/* 76141586Simp * Interrupt conversion table for 83C790 77141586Simp */ 78141586Simpstatic uint16_t ed_790_intr_val[] = { 79141586Simp 0, 80141586Simp 9, 81141586Simp 3, 82141586Simp 5, 83141586Simp 7, 84141586Simp 10, 85141586Simp 11, 86141586Simp 15 87141586Simp}; 88141586Simp 89141586Simp/* 90141586Simp * Probe and vendor-specific initialization routine for SMC/WD80x3 boards 91141586Simp */ 92141586Simpint 93141586Simped_probe_WD80x3_generic(device_t dev, int flags, uint16_t *intr_vals[]) 94141586Simp{ 95141586Simp struct ed_softc *sc = device_get_softc(dev); 96141586Simp int error; 97141586Simp int i; 98141586Simp u_int memsize; 99141586Simp u_char iptr, isa16bit, sum, totalsum; 100141586Simp u_long irq, junk, pmem; 101141586Simp 102141586Simp sc->chip_type = ED_CHIP_TYPE_DP8390; 103141586Simp 104141586Simp if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { 105141586Simp totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER; 106141586Simp ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_POW); 107141586Simp DELAY(10000); 108141586Simp } 109141586Simp else 110141586Simp totalsum = ED_WD_ROM_CHECKSUM_TOTAL; 111141586Simp 112141586Simp /* 113141586Simp * Attempt to do a checksum over the station address PROM. If it 114141586Simp * fails, it's probably not a SMC/WD board. There is a problem with 115141586Simp * this, though: some clone WD boards don't pass the checksum test. 116141586Simp * Danpex boards for one. 117141586Simp */ 118141586Simp for (sum = 0, i = 0; i < 8; ++i) 119141586Simp sum += ed_asic_inb(sc, ED_WD_PROM + i); 120141586Simp 121141586Simp if (sum != totalsum) { 122141586Simp /* 123141586Simp * Checksum is invalid. This often happens with cheap WD8003E 124141586Simp * clones. In this case, the checksum byte (the eighth byte) 125141586Simp * seems to always be zero. 126141586Simp */ 127141586Simp if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E || 128141586Simp ed_asic_inb(sc, ED_WD_PROM + 7) != 0) 129141586Simp return (ENXIO); 130141586Simp } 131141586Simp /* reset card to force it into a known state. */ 132141586Simp if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) 133141586Simp ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); 134141586Simp else 135141586Simp ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST); 136141586Simp 137141586Simp DELAY(100); 138141586Simp ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST); 139141586Simp /* wait in the case this card is reading its EEROM */ 140141586Simp DELAY(5000); 141141586Simp 142141586Simp sc->vendor = ED_VENDOR_WD_SMC; 143141586Simp sc->type = ed_asic_inb(sc, ED_WD_CARD_ID); 144141586Simp 145141586Simp /* 146141586Simp * Set initial values for width/size. 147141586Simp */ 148141586Simp memsize = 8192; 149141586Simp isa16bit = 0; 150141586Simp switch (sc->type) { 151141586Simp case ED_TYPE_WD8003S: 152141586Simp sc->type_str = "WD8003S"; 153141586Simp break; 154141586Simp case ED_TYPE_WD8003E: 155141586Simp sc->type_str = "WD8003E"; 156141586Simp break; 157141586Simp case ED_TYPE_WD8003EB: 158141586Simp sc->type_str = "WD8003EB"; 159141586Simp break; 160141586Simp case ED_TYPE_WD8003W: 161141586Simp sc->type_str = "WD8003W"; 162141586Simp break; 163141586Simp case ED_TYPE_WD8013EBT: 164141586Simp sc->type_str = "WD8013EBT"; 165141586Simp memsize = 16384; 166141586Simp isa16bit = 1; 167141586Simp break; 168141586Simp case ED_TYPE_WD8013W: 169141586Simp sc->type_str = "WD8013W"; 170141586Simp memsize = 16384; 171141586Simp isa16bit = 1; 172141586Simp break; 173141586Simp case ED_TYPE_WD8013EP: /* also WD8003EP */ 174141586Simp if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) { 175141586Simp isa16bit = 1; 176141586Simp memsize = 16384; 177141586Simp sc->type_str = "WD8013EP"; 178141586Simp } else 179141586Simp sc->type_str = "WD8003EP"; 180141586Simp break; 181141586Simp case ED_TYPE_WD8013WC: 182141586Simp sc->type_str = "WD8013WC"; 183141586Simp memsize = 16384; 184141586Simp isa16bit = 1; 185141586Simp break; 186141586Simp case ED_TYPE_WD8013EBP: 187141586Simp sc->type_str = "WD8013EBP"; 188141586Simp memsize = 16384; 189141586Simp isa16bit = 1; 190141586Simp break; 191141586Simp case ED_TYPE_WD8013EPC: 192141586Simp sc->type_str = "WD8013EPC"; 193141586Simp memsize = 16384; 194141586Simp isa16bit = 1; 195141586Simp break; 196141586Simp case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */ 197141586Simp case ED_TYPE_SMC8216T: 198141586Simp if (sc->type == ED_TYPE_SMC8216C) 199141586Simp sc->type_str = "SMC8216/SMC8216C"; 200141586Simp else 201141586Simp sc->type_str = "SMC8216T"; 202141586Simp 203141586Simp ed_asic_outb(sc, ED_WD790_HWR, 204141586Simp ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); 205141586Simp switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) { 206141586Simp case ED_WD790_RAR_SZ64: 207141586Simp memsize = 65536; 208141586Simp break; 209141586Simp case ED_WD790_RAR_SZ32: 210141586Simp memsize = 32768; 211141586Simp break; 212141586Simp case ED_WD790_RAR_SZ16: 213141586Simp memsize = 16384; 214141586Simp break; 215141586Simp case ED_WD790_RAR_SZ8: 216141586Simp /* 8216 has 16K shared mem -- 8416 has 8K */ 217141586Simp if (sc->type == ED_TYPE_SMC8216C) 218141586Simp sc->type_str = "SMC8416C/SMC8416BT"; 219141586Simp else 220141586Simp sc->type_str = "SMC8416T"; 221141586Simp memsize = 8192; 222141586Simp break; 223141586Simp } 224141586Simp ed_asic_outb(sc, ED_WD790_HWR, 225141586Simp ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); 226141586Simp 227141586Simp isa16bit = 1; 228141586Simp sc->chip_type = ED_CHIP_TYPE_WD790; 229141586Simp break; 230141586Simp case ED_TYPE_TOSHIBA1: 231141586Simp sc->type_str = "Toshiba1"; 232141586Simp memsize = 32768; 233141586Simp isa16bit = 1; 234141586Simp break; 235141586Simp case ED_TYPE_TOSHIBA4: 236141586Simp sc->type_str = "Toshiba4"; 237141586Simp memsize = 32768; 238141586Simp isa16bit = 1; 239141586Simp break; 240141586Simp default: 241141586Simp sc->type_str = ""; 242141586Simp break; 243141586Simp } 244141586Simp 245141586Simp /* 246141586Simp * Make some adjustments to initial values depending on what is found 247141586Simp * in the ICR. 248141586Simp */ 249141586Simp if (isa16bit && (sc->type != ED_TYPE_WD8013EBT) 250141586Simp && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) 251141586Simp && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { 252141586Simp isa16bit = 0; 253141586Simp memsize = 8192; 254141586Simp } 255141586Simp 256141586Simp /* Override memsize? XXX */ 257141586Simp error = ed_alloc_memory(dev, 0, memsize); 258141586Simp if (error) 259141586Simp return (error); 260149558Simp sc->mem_start = 0; 261141586Simp 262141586Simp#ifdef ED_DEBUG 263141586Simp printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n", 264141586Simp sc->type, sc->type_str, isa16bit, memsize, 265141586Simp rman_get_size(sc->mem_res)); 266141586Simp for (i = 0; i < 8; i++) 267141586Simp printf("%x -> %x\n", i, ed_asic_inb(sc, i)); 268141586Simp#endif 269141586Simp pmem = rman_get_start(sc->mem_res); 270190483Simp if (!(flags & ED_FLAGS_PCCARD)) { 271190483Simp error = ed_isa_mem_ok(dev, pmem, memsize); 272190483Simp if (error) 273190483Simp return (error); 274190483Simp } 275141586Simp 276141586Simp /* 277141586Simp * (note that if the user specifies both of the following flags that 278141586Simp * '8bit' mode intentionally has precedence) 279141586Simp */ 280141586Simp if (flags & ED_FLAGS_FORCE_16BIT_MODE) 281141586Simp isa16bit = 1; 282141586Simp if (flags & ED_FLAGS_FORCE_8BIT_MODE) 283141586Simp isa16bit = 0; 284141586Simp 285141586Simp /* 286141586Simp * If possible, get the assigned interrupt number from the card and 287141586Simp * use it. 288141586Simp */ 289141586Simp if ((sc->type & ED_WD_SOFTCONFIG) && 290141586Simp (sc->chip_type != ED_CHIP_TYPE_WD790)) { 291141586Simp 292141586Simp /* 293141586Simp * Assemble together the encoded interrupt number. 294141586Simp */ 295141586Simp iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) | 296141586Simp ((ed_asic_inb(sc, ED_WD_IRR) & 297141586Simp (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); 298141586Simp 299141586Simp /* 300141586Simp * If no interrupt specified (or "?"), use what the board tells us. 301141586Simp */ 302141586Simp error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 303141586Simp if (error && intr_vals[0] != NULL) 304141586Simp error = bus_set_resource(dev, SYS_RES_IRQ, 0, 305141586Simp intr_vals[0][iptr], 1); 306141586Simp if (error) 307141586Simp return (error); 308141586Simp 309141586Simp /* 310141586Simp * Enable the interrupt. 311141586Simp */ 312141586Simp ed_asic_outb(sc, ED_WD_IRR, 313141586Simp ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN); 314141586Simp } 315141586Simp if (sc->chip_type == ED_CHIP_TYPE_WD790) { 316141586Simp ed_asic_outb(sc, ED_WD790_HWR, 317141586Simp ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); 318141586Simp iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) | 319141586Simp (ed_asic_inb(sc, ED_WD790_GCR) & 320141586Simp (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2); 321141586Simp ed_asic_outb(sc, ED_WD790_HWR, 322141586Simp ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); 323141586Simp 324141586Simp /* 325141586Simp * If no interrupt specified (or "?"), use what the board tells us. 326141586Simp */ 327141586Simp error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 328141586Simp if (error && intr_vals[1] != NULL) 329141586Simp error = bus_set_resource(dev, SYS_RES_IRQ, 0, 330141586Simp intr_vals[1][iptr], 1); 331141586Simp if (error) 332141586Simp return (error); 333141586Simp 334141586Simp /* 335141586Simp * Enable interrupts. 336141586Simp */ 337141586Simp ed_asic_outb(sc, ED_WD790_ICR, 338141586Simp ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL); 339141586Simp } 340141586Simp error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 341141586Simp if (error) { 342141586Simp device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n", 343141586Simp sc->type_str); 344141586Simp return (ENXIO); 345141586Simp } 346141586Simp sc->isa16bit = isa16bit; 347141586Simp sc->mem_shared = 1; 348141586Simp 349141586Simp /* 350141586Simp * allocate one xmit buffer if < 16k, two buffers otherwise 351141586Simp */ 352141586Simp if (memsize < 16384 || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) 353141586Simp sc->txb_cnt = 1; 354141586Simp else 355141586Simp sc->txb_cnt = 2; 356141586Simp sc->tx_page_start = ED_WD_PAGE_OFFSET; 357141586Simp sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt; 358141586Simp sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE; 359141586Simp sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start); 360141586Simp sc->mem_size = memsize; 361141586Simp sc->mem_end = sc->mem_start + memsize; 362141586Simp 363141586Simp /* 364141586Simp * Get station address from on-board ROM 365141586Simp */ 366141586Simp for (i = 0; i < ETHER_ADDR_LEN; ++i) 367147256Sbrooks sc->enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i); 368141586Simp 369141586Simp /* 370141586Simp * Set upper address bits and 8/16 bit access to shared memory. 371141586Simp */ 372141586Simp if (isa16bit) { 373141586Simp if (sc->chip_type == ED_CHIP_TYPE_WD790) 374141586Simp sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR); 375141586Simp else 376141586Simp sc->wd_laar_proto = ED_WD_LAAR_L16EN | 377141586Simp ((pmem >> 19) & ED_WD_LAAR_ADDRHI); 378141586Simp /* 379141586Simp * Enable 16bit access 380141586Simp */ 381141586Simp ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto | 382141586Simp ED_WD_LAAR_M16EN); 383141586Simp } else { 384141586Simp if (((sc->type & ED_WD_SOFTCONFIG) || 385141586Simp (sc->type == ED_TYPE_TOSHIBA1) || 386141586Simp (sc->type == ED_TYPE_TOSHIBA4) || 387141586Simp (sc->type == ED_TYPE_WD8013EBT)) && 388141586Simp (sc->chip_type != ED_CHIP_TYPE_WD790)) { 389141586Simp sc->wd_laar_proto = (pmem >> 19) & 390141586Simp ED_WD_LAAR_ADDRHI; 391141586Simp ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto); 392141586Simp } 393141586Simp } 394141586Simp 395141586Simp /* 396141586Simp * Set address and enable interface shared memory. 397141586Simp */ 398141586Simp if (sc->chip_type != ED_CHIP_TYPE_WD790) { 399141586Simp if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { 400141586Simp ed_asic_outb(sc, ED_WD_MSR + 1, 401141586Simp ((pmem >> 8) & 0xe0) | 4); 402141586Simp ed_asic_outb(sc, ED_WD_MSR + 2, ((pmem >> 16) & 0x0f)); 403141586Simp ed_asic_outb(sc, ED_WD_MSR, 404141586Simp ED_WD_MSR_MENB | ED_WD_MSR_POW); 405141586Simp } else { 406141586Simp ed_asic_outb(sc, ED_WD_MSR, ((pmem >> 13) & 407141586Simp ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); 408141586Simp } 409141586Simp sc->cr_proto = ED_CR_RD2; 410141586Simp } else { 411141586Simp ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB); 412141586Simp ed_asic_outb(sc, ED_WD790_HWR, 413141586Simp (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH)); 414141586Simp ed_asic_outb(sc, ED_WD790_RAR, 415141586Simp ((pmem >> 13) & 0x0f) | ((pmem >> 11) & 0x40) | 416141586Simp (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0)); 417141586Simp ed_asic_outb(sc, ED_WD790_HWR, 418141586Simp (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH)); 419141586Simp sc->cr_proto = 0; 420141586Simp } 421141586Simp 422141586Simp /* 423141586Simp * Disable 16bit access to shared memory - we leave it 424141586Simp * disabled so that 1) machines reboot properly when the board 425141586Simp * is set 16 bit mode and there are conflicting 8bit 426141586Simp * devices/ROMS in the same 128k address space as this boards 427141586Simp * shared memory. and 2) so that other 8 bit devices with 428141586Simp * shared memory can be used in this 128k region, too. 429141586Simp */ 430142200Simp error = ed_clear_memory(dev); 431141586Simp ed_disable_16bit_access(sc); 432154924Simp sc->sc_write_mbufs = ed_shmem_write_mbufs; 433142200Simp return (error); 434141586Simp} 435141586Simp 436141586Simpint 437141586Simped_probe_WD80x3(device_t dev, int port_rid, int flags) 438141586Simp{ 439141586Simp struct ed_softc *sc = device_get_softc(dev); 440141586Simp int error; 441141586Simp static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val}; 442141586Simp 443141586Simp error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS); 444141586Simp if (error) 445141586Simp return (error); 446141586Simp 447141586Simp sc->asic_offset = ED_WD_ASIC_OFFSET; 448141586Simp sc->nic_offset = ED_WD_NIC_OFFSET; 449141586Simp 450141586Simp return ed_probe_WD80x3_generic(dev, flags, intr_vals); 451141586Simp} 452