if_ed_wd80x3.c revision 141586
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 141586 2005-02-09 20:03:40Z 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 89static void 90ed_disable_16bit_access(struct ed_softc *sc) 91{ 92 /* 93 * Disable 16 bit access to shared memory 94 */ 95 if (sc->isa16bit) { 96 if (sc->chip_type == ED_CHIP_TYPE_WD790) 97 ed_asic_outb(sc, ED_WD_MSR, 0x00); 98 ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto & 99 ~ED_WD_LAAR_M16EN); 100 } 101} 102 103/* 104 * Probe and vendor-specific initialization routine for SMC/WD80x3 boards 105 */ 106int 107ed_probe_WD80x3_generic(device_t dev, int flags, uint16_t *intr_vals[]) 108{ 109 struct ed_softc *sc = device_get_softc(dev); 110 int error; 111 int i; 112 u_int memsize; 113 u_char iptr, isa16bit, sum, totalsum; 114 u_long irq, junk, pmem; 115 116 sc->chip_type = ED_CHIP_TYPE_DP8390; 117 118 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { 119 totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER; 120 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_POW); 121 DELAY(10000); 122 } 123 else 124 totalsum = ED_WD_ROM_CHECKSUM_TOTAL; 125 126 /* 127 * Attempt to do a checksum over the station address PROM. If it 128 * fails, it's probably not a SMC/WD board. There is a problem with 129 * this, though: some clone WD boards don't pass the checksum test. 130 * Danpex boards for one. 131 */ 132 for (sum = 0, i = 0; i < 8; ++i) 133 sum += ed_asic_inb(sc, ED_WD_PROM + i); 134 135 if (sum != totalsum) { 136 137 /* 138 * Checksum is invalid. This often happens with cheap WD8003E 139 * clones. In this case, the checksum byte (the eighth byte) 140 * seems to always be zero. 141 */ 142 if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E || 143 ed_asic_inb(sc, ED_WD_PROM + 7) != 0) 144 return (ENXIO); 145 } 146 /* reset card to force it into a known state. */ 147 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) 148 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); 149 else 150 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST); 151 152 DELAY(100); 153 ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST); 154 /* wait in the case this card is reading its EEROM */ 155 DELAY(5000); 156 157 sc->vendor = ED_VENDOR_WD_SMC; 158 sc->type = ed_asic_inb(sc, ED_WD_CARD_ID); 159 160 /* 161 * Set initial values for width/size. 162 */ 163 memsize = 8192; 164 isa16bit = 0; 165 switch (sc->type) { 166 case ED_TYPE_WD8003S: 167 sc->type_str = "WD8003S"; 168 break; 169 case ED_TYPE_WD8003E: 170 sc->type_str = "WD8003E"; 171 break; 172 case ED_TYPE_WD8003EB: 173 sc->type_str = "WD8003EB"; 174 break; 175 case ED_TYPE_WD8003W: 176 sc->type_str = "WD8003W"; 177 break; 178 case ED_TYPE_WD8013EBT: 179 sc->type_str = "WD8013EBT"; 180 memsize = 16384; 181 isa16bit = 1; 182 break; 183 case ED_TYPE_WD8013W: 184 sc->type_str = "WD8013W"; 185 memsize = 16384; 186 isa16bit = 1; 187 break; 188 case ED_TYPE_WD8013EP: /* also WD8003EP */ 189 if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) { 190 isa16bit = 1; 191 memsize = 16384; 192 sc->type_str = "WD8013EP"; 193 } else 194 sc->type_str = "WD8003EP"; 195 break; 196 case ED_TYPE_WD8013WC: 197 sc->type_str = "WD8013WC"; 198 memsize = 16384; 199 isa16bit = 1; 200 break; 201 case ED_TYPE_WD8013EBP: 202 sc->type_str = "WD8013EBP"; 203 memsize = 16384; 204 isa16bit = 1; 205 break; 206 case ED_TYPE_WD8013EPC: 207 sc->type_str = "WD8013EPC"; 208 memsize = 16384; 209 isa16bit = 1; 210 break; 211 case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */ 212 case ED_TYPE_SMC8216T: 213 if (sc->type == ED_TYPE_SMC8216C) 214 sc->type_str = "SMC8216/SMC8216C"; 215 else 216 sc->type_str = "SMC8216T"; 217 218 ed_asic_outb(sc, ED_WD790_HWR, 219 ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); 220 switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) { 221 case ED_WD790_RAR_SZ64: 222 memsize = 65536; 223 break; 224 case ED_WD790_RAR_SZ32: 225 memsize = 32768; 226 break; 227 case ED_WD790_RAR_SZ16: 228 memsize = 16384; 229 break; 230 case ED_WD790_RAR_SZ8: 231 /* 8216 has 16K shared mem -- 8416 has 8K */ 232 if (sc->type == ED_TYPE_SMC8216C) 233 sc->type_str = "SMC8416C/SMC8416BT"; 234 else 235 sc->type_str = "SMC8416T"; 236 memsize = 8192; 237 break; 238 } 239 ed_asic_outb(sc, ED_WD790_HWR, 240 ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); 241 242 isa16bit = 1; 243 sc->chip_type = ED_CHIP_TYPE_WD790; 244 break; 245 case ED_TYPE_TOSHIBA1: 246 sc->type_str = "Toshiba1"; 247 memsize = 32768; 248 isa16bit = 1; 249 break; 250 case ED_TYPE_TOSHIBA4: 251 sc->type_str = "Toshiba4"; 252 memsize = 32768; 253 isa16bit = 1; 254 break; 255 default: 256 sc->type_str = ""; 257 break; 258 } 259 260 /* 261 * Make some adjustments to initial values depending on what is found 262 * in the ICR. 263 */ 264 if (isa16bit && (sc->type != ED_TYPE_WD8013EBT) 265 && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) 266 && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { 267 isa16bit = 0; 268 memsize = 8192; 269 } 270 271 /* Override memsize? XXX */ 272 error = ed_alloc_memory(dev, 0, memsize); 273 if (error) 274 return (error); 275 sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); 276 277#ifdef ED_DEBUG 278 printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n", 279 sc->type, sc->type_str, isa16bit, memsize, 280 rman_get_size(sc->mem_res)); 281 for (i = 0; i < 8; i++) 282 printf("%x -> %x\n", i, ed_asic_inb(sc, i)); 283#endif 284 pmem = rman_get_start(sc->mem_res); 285 error = ed_isa_mem_ok(dev, pmem, memsize); 286 if (error) 287 return (error); 288 289 /* 290 * (note that if the user specifies both of the following flags that 291 * '8bit' mode intentionally has precedence) 292 */ 293 if (flags & ED_FLAGS_FORCE_16BIT_MODE) 294 isa16bit = 1; 295 if (flags & ED_FLAGS_FORCE_8BIT_MODE) 296 isa16bit = 0; 297 298 /* 299 * If possible, get the assigned interrupt number from the card and 300 * use it. 301 */ 302 if ((sc->type & ED_WD_SOFTCONFIG) && 303 (sc->chip_type != ED_CHIP_TYPE_WD790)) { 304 305 /* 306 * Assemble together the encoded interrupt number. 307 */ 308 iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) | 309 ((ed_asic_inb(sc, ED_WD_IRR) & 310 (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); 311 312 /* 313 * If no interrupt specified (or "?"), use what the board tells us. 314 */ 315 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 316 if (error && intr_vals[0] != NULL) 317 error = bus_set_resource(dev, SYS_RES_IRQ, 0, 318 intr_vals[0][iptr], 1); 319 if (error) 320 return (error); 321 322 /* 323 * Enable the interrupt. 324 */ 325 ed_asic_outb(sc, ED_WD_IRR, 326 ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN); 327 } 328 if (sc->chip_type == ED_CHIP_TYPE_WD790) { 329 ed_asic_outb(sc, ED_WD790_HWR, 330 ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); 331 iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) | 332 (ed_asic_inb(sc, ED_WD790_GCR) & 333 (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2); 334 ed_asic_outb(sc, ED_WD790_HWR, 335 ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); 336 337 /* 338 * If no interrupt specified (or "?"), use what the board tells us. 339 */ 340 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 341 if (error && intr_vals[1] != NULL) 342 error = bus_set_resource(dev, SYS_RES_IRQ, 0, 343 intr_vals[1][iptr], 1); 344 if (error) 345 return (error); 346 347 /* 348 * Enable interrupts. 349 */ 350 ed_asic_outb(sc, ED_WD790_ICR, 351 ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL); 352 } 353 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 354 if (error) { 355 device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n", 356 sc->type_str); 357 return (ENXIO); 358 } 359 sc->isa16bit = isa16bit; 360 sc->mem_shared = 1; 361 362 /* 363 * allocate one xmit buffer if < 16k, two buffers otherwise 364 */ 365 if (memsize < 16384 || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) 366 sc->txb_cnt = 1; 367 else 368 sc->txb_cnt = 2; 369 sc->tx_page_start = ED_WD_PAGE_OFFSET; 370 sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt; 371 sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE; 372 sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start); 373 sc->mem_size = memsize; 374 sc->mem_end = sc->mem_start + memsize; 375 376 /* 377 * Get station address from on-board ROM 378 */ 379 for (i = 0; i < ETHER_ADDR_LEN; ++i) 380 sc->arpcom.ac_enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i); 381 382 /* 383 * Set upper address bits and 8/16 bit access to shared memory. 384 */ 385 if (isa16bit) { 386 if (sc->chip_type == ED_CHIP_TYPE_WD790) 387 sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR); 388 else 389 sc->wd_laar_proto = ED_WD_LAAR_L16EN | 390 ((pmem >> 19) & ED_WD_LAAR_ADDRHI); 391 /* 392 * Enable 16bit access 393 */ 394 ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto | 395 ED_WD_LAAR_M16EN); 396 } else { 397 if (((sc->type & ED_WD_SOFTCONFIG) || 398 (sc->type == ED_TYPE_TOSHIBA1) || 399 (sc->type == ED_TYPE_TOSHIBA4) || 400 (sc->type == ED_TYPE_WD8013EBT)) && 401 (sc->chip_type != ED_CHIP_TYPE_WD790)) { 402 sc->wd_laar_proto = (pmem >> 19) & 403 ED_WD_LAAR_ADDRHI; 404 ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto); 405 } 406 } 407 408 /* 409 * Set address and enable interface shared memory. 410 */ 411 if (sc->chip_type != ED_CHIP_TYPE_WD790) { 412 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { 413 ed_asic_outb(sc, ED_WD_MSR + 1, 414 ((pmem >> 8) & 0xe0) | 4); 415 ed_asic_outb(sc, ED_WD_MSR + 2, ((pmem >> 16) & 0x0f)); 416 ed_asic_outb(sc, ED_WD_MSR, 417 ED_WD_MSR_MENB | ED_WD_MSR_POW); 418 } else { 419 ed_asic_outb(sc, ED_WD_MSR, ((pmem >> 13) & 420 ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); 421 } 422 sc->cr_proto = ED_CR_RD2; 423 } else { 424 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB); 425 ed_asic_outb(sc, ED_WD790_HWR, 426 (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH)); 427 ed_asic_outb(sc, ED_WD790_RAR, 428 ((pmem >> 13) & 0x0f) | ((pmem >> 11) & 0x40) | 429 (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0)); 430 ed_asic_outb(sc, ED_WD790_HWR, 431 (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH)); 432 sc->cr_proto = 0; 433 } 434 435 error = ed_clear_memory(dev); 436 if (error) { 437 ed_disable_16bit_access(sc); 438 return (error); 439 } 440 441 /* 442 * Disable 16bit access to shared memory - we leave it 443 * disabled so that 1) machines reboot properly when the board 444 * is set 16 bit mode and there are conflicting 8bit 445 * devices/ROMS in the same 128k address space as this boards 446 * shared memory. and 2) so that other 8 bit devices with 447 * shared memory can be used in this 128k region, too. 448 */ 449 ed_disable_16bit_access(sc); 450 return (0); 451} 452 453int 454ed_probe_WD80x3(device_t dev, int port_rid, int flags) 455{ 456 struct ed_softc *sc = device_get_softc(dev); 457 int error; 458 static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val}; 459 460 error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS); 461 if (error) 462 return (error); 463 464 sc->asic_offset = ED_WD_ASIC_OFFSET; 465 sc->nic_offset = ED_WD_NIC_OFFSET; 466 467 return ed_probe_WD80x3_generic(dev, flags, intr_vals); 468} 469