if_ed_wd80x3.c revision 142200
1/*- 2 * Copyright (c) 2005, M. Warner Losh 3 * All rights reserved. 4 * Copyright (c) 1995, David Greenman 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/dev/ed/if_ed_wd80x3.c 142200 2005-02-22 03:37:04Z imp $"); 32 33#include "opt_ed.h" 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/sockio.h> 38#include <sys/mbuf.h> 39#include <sys/kernel.h> 40#include <sys/socket.h> 41#include <sys/syslog.h> 42 43#include <sys/bus.h> 44 45#include <machine/bus.h> 46#include <sys/rman.h> 47#include <machine/resource.h> 48 49#include <net/ethernet.h> 50#include <net/if.h> 51#include <net/if_arp.h> 52#include <net/if_dl.h> 53#include <net/if_mib.h> 54#include <net/if_media.h> 55 56#include <net/bpf.h> 57 58#include <dev/ed/if_edreg.h> 59#include <dev/ed/if_edvar.h> 60 61/* 62 * Interrupt conversion table for WD/SMC ASIC/83C584 63 */ 64static uint16_t ed_intr_val[] = { 65 9, 66 3, 67 5, 68 7, 69 10, 70 11, 71 15, 72 4 73}; 74 75/* 76 * Interrupt conversion table for 83C790 77 */ 78static uint16_t ed_790_intr_val[] = { 79 0, 80 9, 81 3, 82 5, 83 7, 84 10, 85 11, 86 15 87}; 88 89/* 90 * Probe and vendor-specific initialization routine for SMC/WD80x3 boards 91 */ 92int 93ed_probe_WD80x3_generic(device_t dev, int flags, uint16_t *intr_vals[]) 94{ 95 struct ed_softc *sc = device_get_softc(dev); 96 int error; 97 int i; 98 u_int memsize; 99 u_char iptr, isa16bit, sum, totalsum; 100 u_long irq, junk, pmem; 101 102 sc->chip_type = ED_CHIP_TYPE_DP8390; 103 104 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { 105 totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER; 106 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_POW); 107 DELAY(10000); 108 } 109 else 110 totalsum = ED_WD_ROM_CHECKSUM_TOTAL; 111 112 /* 113 * Attempt to do a checksum over the station address PROM. If it 114 * fails, it's probably not a SMC/WD board. There is a problem with 115 * this, though: some clone WD boards don't pass the checksum test. 116 * Danpex boards for one. 117 */ 118 for (sum = 0, i = 0; i < 8; ++i) 119 sum += ed_asic_inb(sc, ED_WD_PROM + i); 120 121 if (sum != totalsum) { 122 123 /* 124 * Checksum is invalid. This often happens with cheap WD8003E 125 * clones. In this case, the checksum byte (the eighth byte) 126 * seems to always be zero. 127 */ 128 if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E || 129 ed_asic_inb(sc, ED_WD_PROM + 7) != 0) 130 return (ENXIO); 131 } 132 /* reset card to force it into a known state. */ 133 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) 134 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); 135 else 136 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST); 137 138 DELAY(100); 139 ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST); 140 /* wait in the case this card is reading its EEROM */ 141 DELAY(5000); 142 143 sc->vendor = ED_VENDOR_WD_SMC; 144 sc->type = ed_asic_inb(sc, ED_WD_CARD_ID); 145 146 /* 147 * Set initial values for width/size. 148 */ 149 memsize = 8192; 150 isa16bit = 0; 151 switch (sc->type) { 152 case ED_TYPE_WD8003S: 153 sc->type_str = "WD8003S"; 154 break; 155 case ED_TYPE_WD8003E: 156 sc->type_str = "WD8003E"; 157 break; 158 case ED_TYPE_WD8003EB: 159 sc->type_str = "WD8003EB"; 160 break; 161 case ED_TYPE_WD8003W: 162 sc->type_str = "WD8003W"; 163 break; 164 case ED_TYPE_WD8013EBT: 165 sc->type_str = "WD8013EBT"; 166 memsize = 16384; 167 isa16bit = 1; 168 break; 169 case ED_TYPE_WD8013W: 170 sc->type_str = "WD8013W"; 171 memsize = 16384; 172 isa16bit = 1; 173 break; 174 case ED_TYPE_WD8013EP: /* also WD8003EP */ 175 if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) { 176 isa16bit = 1; 177 memsize = 16384; 178 sc->type_str = "WD8013EP"; 179 } else 180 sc->type_str = "WD8003EP"; 181 break; 182 case ED_TYPE_WD8013WC: 183 sc->type_str = "WD8013WC"; 184 memsize = 16384; 185 isa16bit = 1; 186 break; 187 case ED_TYPE_WD8013EBP: 188 sc->type_str = "WD8013EBP"; 189 memsize = 16384; 190 isa16bit = 1; 191 break; 192 case ED_TYPE_WD8013EPC: 193 sc->type_str = "WD8013EPC"; 194 memsize = 16384; 195 isa16bit = 1; 196 break; 197 case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */ 198 case ED_TYPE_SMC8216T: 199 if (sc->type == ED_TYPE_SMC8216C) 200 sc->type_str = "SMC8216/SMC8216C"; 201 else 202 sc->type_str = "SMC8216T"; 203 204 ed_asic_outb(sc, ED_WD790_HWR, 205 ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); 206 switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) { 207 case ED_WD790_RAR_SZ64: 208 memsize = 65536; 209 break; 210 case ED_WD790_RAR_SZ32: 211 memsize = 32768; 212 break; 213 case ED_WD790_RAR_SZ16: 214 memsize = 16384; 215 break; 216 case ED_WD790_RAR_SZ8: 217 /* 8216 has 16K shared mem -- 8416 has 8K */ 218 if (sc->type == ED_TYPE_SMC8216C) 219 sc->type_str = "SMC8416C/SMC8416BT"; 220 else 221 sc->type_str = "SMC8416T"; 222 memsize = 8192; 223 break; 224 } 225 ed_asic_outb(sc, ED_WD790_HWR, 226 ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); 227 228 isa16bit = 1; 229 sc->chip_type = ED_CHIP_TYPE_WD790; 230 break; 231 case ED_TYPE_TOSHIBA1: 232 sc->type_str = "Toshiba1"; 233 memsize = 32768; 234 isa16bit = 1; 235 break; 236 case ED_TYPE_TOSHIBA4: 237 sc->type_str = "Toshiba4"; 238 memsize = 32768; 239 isa16bit = 1; 240 break; 241 default: 242 sc->type_str = ""; 243 break; 244 } 245 246 /* 247 * Make some adjustments to initial values depending on what is found 248 * in the ICR. 249 */ 250 if (isa16bit && (sc->type != ED_TYPE_WD8013EBT) 251 && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) 252 && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { 253 isa16bit = 0; 254 memsize = 8192; 255 } 256 257 /* Override memsize? XXX */ 258 error = ed_alloc_memory(dev, 0, memsize); 259 if (error) 260 return (error); 261 sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); 262 263#ifdef ED_DEBUG 264 printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n", 265 sc->type, sc->type_str, isa16bit, memsize, 266 rman_get_size(sc->mem_res)); 267 for (i = 0; i < 8; i++) 268 printf("%x -> %x\n", i, ed_asic_inb(sc, i)); 269#endif 270 pmem = rman_get_start(sc->mem_res); 271 error = ed_isa_mem_ok(dev, pmem, memsize); 272 if (error) 273 return (error); 274 275 /* 276 * (note that if the user specifies both of the following flags that 277 * '8bit' mode intentionally has precedence) 278 */ 279 if (flags & ED_FLAGS_FORCE_16BIT_MODE) 280 isa16bit = 1; 281 if (flags & ED_FLAGS_FORCE_8BIT_MODE) 282 isa16bit = 0; 283 284 /* 285 * If possible, get the assigned interrupt number from the card and 286 * use it. 287 */ 288 if ((sc->type & ED_WD_SOFTCONFIG) && 289 (sc->chip_type != ED_CHIP_TYPE_WD790)) { 290 291 /* 292 * Assemble together the encoded interrupt number. 293 */ 294 iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) | 295 ((ed_asic_inb(sc, ED_WD_IRR) & 296 (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); 297 298 /* 299 * If no interrupt specified (or "?"), use what the board tells us. 300 */ 301 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 302 if (error && intr_vals[0] != NULL) 303 error = bus_set_resource(dev, SYS_RES_IRQ, 0, 304 intr_vals[0][iptr], 1); 305 if (error) 306 return (error); 307 308 /* 309 * Enable the interrupt. 310 */ 311 ed_asic_outb(sc, ED_WD_IRR, 312 ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN); 313 } 314 if (sc->chip_type == ED_CHIP_TYPE_WD790) { 315 ed_asic_outb(sc, ED_WD790_HWR, 316 ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); 317 iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) | 318 (ed_asic_inb(sc, ED_WD790_GCR) & 319 (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2); 320 ed_asic_outb(sc, ED_WD790_HWR, 321 ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); 322 323 /* 324 * If no interrupt specified (or "?"), use what the board tells us. 325 */ 326 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 327 if (error && intr_vals[1] != NULL) 328 error = bus_set_resource(dev, SYS_RES_IRQ, 0, 329 intr_vals[1][iptr], 1); 330 if (error) 331 return (error); 332 333 /* 334 * Enable interrupts. 335 */ 336 ed_asic_outb(sc, ED_WD790_ICR, 337 ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL); 338 } 339 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 340 if (error) { 341 device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n", 342 sc->type_str); 343 return (ENXIO); 344 } 345 sc->isa16bit = isa16bit; 346 sc->mem_shared = 1; 347 348 /* 349 * allocate one xmit buffer if < 16k, two buffers otherwise 350 */ 351 if (memsize < 16384 || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) 352 sc->txb_cnt = 1; 353 else 354 sc->txb_cnt = 2; 355 sc->tx_page_start = ED_WD_PAGE_OFFSET; 356 sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt; 357 sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE; 358 sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start); 359 sc->mem_size = memsize; 360 sc->mem_end = sc->mem_start + memsize; 361 362 /* 363 * Get station address from on-board ROM 364 */ 365 for (i = 0; i < ETHER_ADDR_LEN; ++i) 366 sc->arpcom.ac_enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i); 367 368 /* 369 * Set upper address bits and 8/16 bit access to shared memory. 370 */ 371 if (isa16bit) { 372 if (sc->chip_type == ED_CHIP_TYPE_WD790) 373 sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR); 374 else 375 sc->wd_laar_proto = ED_WD_LAAR_L16EN | 376 ((pmem >> 19) & ED_WD_LAAR_ADDRHI); 377 /* 378 * Enable 16bit access 379 */ 380 ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto | 381 ED_WD_LAAR_M16EN); 382 } else { 383 if (((sc->type & ED_WD_SOFTCONFIG) || 384 (sc->type == ED_TYPE_TOSHIBA1) || 385 (sc->type == ED_TYPE_TOSHIBA4) || 386 (sc->type == ED_TYPE_WD8013EBT)) && 387 (sc->chip_type != ED_CHIP_TYPE_WD790)) { 388 sc->wd_laar_proto = (pmem >> 19) & 389 ED_WD_LAAR_ADDRHI; 390 ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto); 391 } 392 } 393 394 /* 395 * Set address and enable interface shared memory. 396 */ 397 if (sc->chip_type != ED_CHIP_TYPE_WD790) { 398 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { 399 ed_asic_outb(sc, ED_WD_MSR + 1, 400 ((pmem >> 8) & 0xe0) | 4); 401 ed_asic_outb(sc, ED_WD_MSR + 2, ((pmem >> 16) & 0x0f)); 402 ed_asic_outb(sc, ED_WD_MSR, 403 ED_WD_MSR_MENB | ED_WD_MSR_POW); 404 } else { 405 ed_asic_outb(sc, ED_WD_MSR, ((pmem >> 13) & 406 ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); 407 } 408 sc->cr_proto = ED_CR_RD2; 409 } else { 410 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB); 411 ed_asic_outb(sc, ED_WD790_HWR, 412 (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH)); 413 ed_asic_outb(sc, ED_WD790_RAR, 414 ((pmem >> 13) & 0x0f) | ((pmem >> 11) & 0x40) | 415 (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0)); 416 ed_asic_outb(sc, ED_WD790_HWR, 417 (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH)); 418 sc->cr_proto = 0; 419 } 420 421 /* 422 * Disable 16bit access to shared memory - we leave it 423 * disabled so that 1) machines reboot properly when the board 424 * is set 16 bit mode and there are conflicting 8bit 425 * devices/ROMS in the same 128k address space as this boards 426 * shared memory. and 2) so that other 8 bit devices with 427 * shared memory can be used in this 128k region, too. 428 */ 429 error = ed_clear_memory(dev); 430 ed_disable_16bit_access(sc); 431 return (error); 432} 433 434int 435ed_probe_WD80x3(device_t dev, int port_rid, int flags) 436{ 437 struct ed_softc *sc = device_get_softc(dev); 438 int error; 439 static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val}; 440 441 error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS); 442 if (error) 443 return (error); 444 445 sc->asic_offset = ED_WD_ASIC_OFFSET; 446 sc->nic_offset = ED_WD_NIC_OFFSET; 447 448 return ed_probe_WD80x3_generic(dev, flags, intr_vals); 449} 450