1 /* $NetBSD: if_we_isa.c,v 1.8 2002/10/02 03:10:48 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Device driver for National Semiconductor DS8390/WD83C690 based ethernet 42 * adapters. 43 * 44 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. 45 * 46 * Copyright (C) 1993, David Greenman. This software may be used, modified, 47 * copied, distributed, and sold, in both source and binary form provided that 48 * the above copyright and these terms are retained. Under no circumstances is 49 * the author responsible for the proper functioning of this software, nor does 50 * the author assume any responsibility for damages incurred with its use. 51 */ 52 53 /* 54 * Device driver for the Western Digital/SMC 8003 and 8013 series, 55 * and the SMC Elite Ultra (8216). 56 */ 57 58 #include <sys/cdefs.h> 59 __KERNEL_RCSID(0, "$NetBSD: if_we_isa.c,v 1.8 2002/10/02 03:10:48 thorpej Exp $"); 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/device.h> 64 #include <sys/socket.h> 65 #include <sys/mbuf.h> 66 #include <sys/syslog.h> 67 68 #include <net/if.h> 69 #include <net/if_dl.h> 70 #include <net/if_types.h> 71 #include <net/if_media.h> 72 73 #include <net/if_ether.h> 74 75 #include <machine/bus.h> 76 #include <machine/bswap.h> 77 #include <machine/intr.h> 78 79 #include <dev/isa/isareg.h> 80 #include <dev/isa/isavar.h> 81 82 #include <dev/ic/dp8390reg.h> 83 #include <dev/ic/dp8390var.h> 84 #include <dev/ic/wereg.h> 85 #include <dev/ic/wevar.h> 86 87 #ifndef __BUS_SPACE_HAS_STREAM_METHODS 88 #define bus_space_read_region_stream_2 bus_space_read_region_2 89 #define bus_space_write_stream_2 bus_space_write_2 90 #define bus_space_write_region_stream_2 bus_space_write_region_2 91 #endif 92 93 int we_isa_probe __P((struct device *, struct cfdata *, void *)); 94 void we_isa_attach __P((struct device *, struct device *, void *)); 95 96 CFATTACH_DECL(we_isa, sizeof(struct we_softc), 97 we_isa_probe, we_isa_attach, NULL, NULL); 98 99 extern struct cfdriver we_cd; 100 101 static const char *we_params __P((bus_space_tag_t, bus_space_handle_t, 102 u_int8_t *, bus_size_t *, int *, int *)); 103 104 static const int we_584_irq[] = { 105 9, 3, 5, 7, 10, 11, 15, 4, 106 }; 107 #define NWE_584_IRQ (sizeof(we_584_irq) / sizeof(we_584_irq[0])) 108 109 static const int we_790_irq[] = { 110 ISACF_IRQ_DEFAULT, 9, 3, 5, 7, 10, 11, 15, 111 }; 112 #define NWE_790_IRQ (sizeof(we_790_irq) / sizeof(we_790_irq[0])) 113 114 /* 115 * Delay needed when switching 16-bit access to shared memory. 116 */ 117 #define WE_DELAY(wsc) delay(3) 118 119 /* 120 * Enable card RAM, and 16-bit access. 121 */ 122 #define WE_MEM_ENABLE(wsc) \ 123 do { \ 124 if ((wsc)->sc_16bitp) \ 125 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 126 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \ 127 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 128 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \ 129 WE_DELAY((wsc)); \ 130 } while (0) 131 132 /* 133 * Disable card RAM, and 16-bit access. 134 */ 135 #define WE_MEM_DISABLE(wsc) \ 136 do { \ 137 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 138 WE_MSR, (wsc)->sc_msr_proto); \ 139 if ((wsc)->sc_16bitp) \ 140 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 141 WE_LAAR, (wsc)->sc_laar_proto); \ 142 WE_DELAY((wsc)); \ 143 } while (0) 144 145 int 146 we_isa_probe(parent, cf, aux) 147 struct device *parent; 148 struct cfdata *cf; 149 void *aux; 150 { 151 struct isa_attach_args *ia = aux; 152 bus_space_tag_t asict, memt; 153 bus_space_handle_t asich, memh; 154 bus_size_t memsize; 155 int asich_valid, memh_valid; 156 int i, is790, rv = 0; 157 u_int8_t x, type; 158 159 asict = ia->ia_iot; 160 memt = ia->ia_memt; 161 162 asich_valid = memh_valid = 0; 163 164 if (ia->ia_nio < 1) 165 return (0); 166 if (ia->ia_niomem < 1) 167 return (0); 168 if (ia->ia_nirq < 1) 169 return (0); 170 171 if (ISA_DIRECT_CONFIG(ia)) 172 return (0); 173 174 /* Disallow wildcarded i/o addresses. */ 175 if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT) 176 return (0); 177 178 /* Disallow wildcarded mem address. */ 179 if (ia->ia_iomem[0].ir_addr == ISACF_IOMEM_DEFAULT) 180 return (0); 181 182 /* Attempt to map the device. */ 183 if (bus_space_map(asict, ia->ia_io[0].ir_addr, WE_NPORTS, 0, &asich)) 184 goto out; 185 asich_valid = 1; 186 187 #ifdef TOSH_ETHER 188 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_POW); 189 #endif 190 191 /* 192 * Attempt to do a checksum over the station address PROM. 193 * If it fails, it's probably not a WD/SMC board. There is 194 * a problem with this, though. Some clone WD8003E boards 195 * (e.g. Danpex) won't pass the checksum. In this case, 196 * the checksum byte always seems to be 0. 197 */ 198 for (x = 0, i = 0; i < 8; i++) 199 x += bus_space_read_1(asict, asich, WE_PROM + i); 200 201 if (x != WE_ROM_CHECKSUM_TOTAL) { 202 /* Make sure it's an 8003E clone... */ 203 if (bus_space_read_1(asict, asich, WE_CARD_ID) != 204 WE_TYPE_WD8003E) 205 goto out; 206 207 /* Check the checksum byte. */ 208 if (bus_space_read_1(asict, asich, WE_PROM + 7) != 0) 209 goto out; 210 } 211 212 /* 213 * Reset the card to force it into a known state. 214 */ 215 #ifdef TOSH_ETHER 216 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST | WE_MSR_POW); 217 #else 218 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST); 219 #endif 220 delay(100); 221 222 bus_space_write_1(asict, asich, WE_MSR, 223 bus_space_read_1(asict, asich, WE_MSR) & ~WE_MSR_RST); 224 225 /* Wait in case the card is reading it's EEPROM. */ 226 delay(5000); 227 228 /* 229 * Get parameters. 230 */ 231 if (we_params(asict, asich, &type, &memsize, NULL, &is790) == NULL) 232 goto out; 233 234 /* Allow user to override probed value. */ 235 if (ia->ia_iomem[0].ir_size) 236 memsize = ia->ia_iomem[0].ir_size; 237 238 /* Attempt to map the memory space. */ 239 if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, memsize, 0, &memh)) 240 goto out; 241 memh_valid = 1; 242 243 /* 244 * If possible, get the assigned interrupt number from the card 245 * and use it. 246 */ 247 if (is790) { 248 u_int8_t hwr; 249 250 /* Assemble together the encoded interrupt number. */ 251 hwr = bus_space_read_1(asict, asich, WE790_HWR); 252 bus_space_write_1(asict, asich, WE790_HWR, 253 hwr | WE790_HWR_SWH); 254 255 x = bus_space_read_1(asict, asich, WE790_GCR); 256 i = ((x & WE790_GCR_IR2) >> 4) | 257 ((x & (WE790_GCR_IR1|WE790_GCR_IR0)) >> 2); 258 bus_space_write_1(asict, asich, WE790_HWR, 259 hwr & ~WE790_HWR_SWH); 260 261 if (ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT && 262 ia->ia_irq[0].ir_irq != we_790_irq[i]) 263 printf("%s%d: overriding configured IRQ %d to %d\n", 264 we_cd.cd_name, cf->cf_unit, ia->ia_irq[0].ir_irq, 265 we_790_irq[i]); 266 ia->ia_irq[0].ir_irq = we_790_irq[i]; 267 } else if (type & WE_SOFTCONFIG) { 268 /* Assemble together the encoded interrupt number. */ 269 i = (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_IR2) | 270 ((bus_space_read_1(asict, asich, WE_IRR) & 271 (WE_IRR_IR0 | WE_IRR_IR1)) >> 5); 272 273 if (ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT && 274 ia->ia_irq[0].ir_irq != we_584_irq[i]) 275 printf("%s%d: overriding configured IRQ %d to %d\n", 276 we_cd.cd_name, cf->cf_unit, ia->ia_irq[0].ir_irq, 277 we_584_irq[i]); 278 ia->ia_irq[0].ir_irq = we_584_irq[i]; 279 } 280 281 /* So, we say we've found it! */ 282 ia->ia_nio = 1; 283 ia->ia_io[0].ir_size = WE_NPORTS; 284 285 ia->ia_niomem = 1; 286 ia->ia_iomem[0].ir_size = memsize; 287 288 ia->ia_nirq = 1; 289 290 ia->ia_ndrq = 0; 291 292 rv = 1; 293 294 out: 295 if (asich_valid) 296 bus_space_unmap(asict, asich, WE_NPORTS); 297 if (memh_valid) 298 bus_space_unmap(memt, memh, memsize); 299 return (rv); 300 } 301 302 void 303 we_isa_attach(parent, self, aux) 304 struct device *parent, *self; 305 void *aux; 306 { 307 struct we_softc *wsc = (struct we_softc *)self; 308 struct dp8390_softc *sc = &wsc->sc_dp8390; 309 struct isa_attach_args *ia = aux; 310 bus_space_tag_t nict, asict, memt; 311 bus_space_handle_t nich, asich, memh; 312 const char *typestr; 313 314 printf("\n"); 315 316 nict = asict = ia->ia_iot; 317 memt = ia->ia_memt; 318 319 /* Map the device. */ 320 if (bus_space_map(asict, ia->ia_io[0].ir_addr, WE_NPORTS, 0, &asich)) { 321 printf("%s: can't map nic i/o space\n", 322 sc->sc_dev.dv_xname); 323 return; 324 } 325 326 if (bus_space_subregion(asict, asich, WE_NIC_OFFSET, WE_NIC_NPORTS, 327 &nich)) { 328 printf("%s: can't subregion i/o space\n", 329 sc->sc_dev.dv_xname); 330 return; 331 } 332 333 typestr = we_params(asict, asich, &wsc->sc_type, NULL, 334 &wsc->sc_16bitp, &sc->is790); 335 if (typestr == NULL) { 336 printf("%s: where did the card go?\n", sc->sc_dev.dv_xname); 337 return; 338 } 339 340 /* 341 * Map memory space. Note we use the size that might have 342 * been overridden by the user. 343 */ 344 if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, 345 ia->ia_iomem[0].ir_size, 0, &memh)) { 346 printf("%s: can't map shared memory\n", 347 sc->sc_dev.dv_xname); 348 return; 349 } 350 351 wsc->sc_asict = asict; 352 wsc->sc_asich = asich; 353 354 sc->sc_regt = nict; 355 sc->sc_regh = nich; 356 357 sc->sc_buft = memt; 358 sc->sc_bufh = memh; 359 360 wsc->sc_maddr = ia->ia_iomem[0].ir_addr; 361 sc->mem_size = ia->ia_iomem[0].ir_size; 362 363 /* Interface is always enabled. */ 364 sc->sc_enabled = 1; 365 366 if (we_config(self, wsc, typestr)) 367 return; 368 369 /* 370 * Enable the configured interrupt. 371 */ 372 if (sc->is790) 373 bus_space_write_1(asict, asich, WE790_ICR, 374 bus_space_read_1(asict, asich, WE790_ICR) | 375 WE790_ICR_EIL); 376 else if (wsc->sc_type & WE_SOFTCONFIG) 377 bus_space_write_1(asict, asich, WE_IRR, 378 bus_space_read_1(asict, asich, WE_IRR) | WE_IRR_IEN); 379 else if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT) { 380 printf("%s: can't wildcard IRQ on a %s\n", 381 sc->sc_dev.dv_xname, typestr); 382 return; 383 } 384 385 /* Establish interrupt handler. */ 386 wsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, 387 IST_EDGE, IPL_NET, dp8390_intr, sc); 388 if (wsc->sc_ih == NULL) 389 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); 390 } 391 392 static const char * 393 we_params(asict, asich, typep, memsizep, is16bitp, is790p) 394 bus_space_tag_t asict; 395 bus_space_handle_t asich; 396 u_int8_t *typep; 397 bus_size_t *memsizep; 398 int *is16bitp, *is790p; 399 { 400 const char *typestr; 401 bus_size_t memsize; 402 int is16bit, is790; 403 u_int8_t type; 404 405 memsize = 8192; 406 is16bit = is790 = 0; 407 408 type = bus_space_read_1(asict, asich, WE_CARD_ID); 409 switch (type) { 410 case WE_TYPE_WD8003S: 411 typestr = "WD8003S"; 412 break; 413 case WE_TYPE_WD8003E: 414 typestr = "WD8003E"; 415 break; 416 case WE_TYPE_WD8003EB: 417 typestr = "WD8003EB"; 418 break; 419 case WE_TYPE_WD8003W: 420 typestr = "WD8003W"; 421 break; 422 case WE_TYPE_WD8013EBT: 423 typestr = "WD8013EBT"; 424 memsize = 16384; 425 is16bit = 1; 426 break; 427 case WE_TYPE_WD8013W: 428 typestr = "WD8013W"; 429 memsize = 16384; 430 is16bit = 1; 431 break; 432 case WE_TYPE_WD8013EP: /* also WD8003EP */ 433 if (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) { 434 is16bit = 1; 435 memsize = 16384; 436 typestr = "WD8013EP"; 437 } else 438 typestr = "WD8003EP"; 439 break; 440 case WE_TYPE_WD8013WC: 441 typestr = "WD8013WC"; 442 memsize = 16384; 443 is16bit = 1; 444 break; 445 case WE_TYPE_WD8013EBP: 446 typestr = "WD8013EBP"; 447 memsize = 16384; 448 is16bit = 1; 449 break; 450 case WE_TYPE_WD8013EPC: 451 typestr = "WD8013EPC"; 452 memsize = 16384; 453 is16bit = 1; 454 break; 455 case WE_TYPE_SMC8216C: 456 case WE_TYPE_SMC8216T: 457 { 458 u_int8_t hwr; 459 460 typestr = (type == WE_TYPE_SMC8216C) ? 461 "SMC8216/SMC8216C" : "SMC8216T"; 462 463 hwr = bus_space_read_1(asict, asich, WE790_HWR); 464 bus_space_write_1(asict, asich, WE790_HWR, 465 hwr | WE790_HWR_SWH); 466 switch (bus_space_read_1(asict, asich, WE790_RAR) & 467 WE790_RAR_SZ64) { 468 case WE790_RAR_SZ64: 469 memsize = 65536; 470 break; 471 case WE790_RAR_SZ32: 472 memsize = 32768; 473 break; 474 case WE790_RAR_SZ16: 475 memsize = 16384; 476 break; 477 case WE790_RAR_SZ8: 478 /* 8216 has 16K shared mem -- 8416 has 8K */ 479 typestr = (type == WE_TYPE_SMC8216C) ? 480 "SMC8416C/SMC8416BT" : "SMC8416T"; 481 memsize = 8192; 482 break; 483 } 484 bus_space_write_1(asict, asich, WE790_HWR, hwr); 485 486 is16bit = 1; 487 is790 = 1; 488 break; 489 } 490 #ifdef TOSH_ETHER 491 case WE_TYPE_TOSHIBA1: 492 typestr = "Toshiba1"; 493 memsize = 32768; 494 is16bit = 1; 495 break; 496 case WE_TYPE_TOSHIBA4: 497 typestr = "Toshiba4"; 498 memsize = 32768; 499 is16bit = 1; 500 break; 501 #endif 502 default: 503 /* Not one we recognize. */ 504 return (NULL); 505 } 506 507 /* 508 * Make some adjustments to initial values depending on what is 509 * found in the ICR. 510 */ 511 if (is16bit && (type != WE_TYPE_WD8013EBT) && 512 #ifdef TOSH_ETHER 513 (type != WE_TYPE_TOSHIBA1 && type != WE_TYPE_TOSHIBA4) && 514 #endif 515 (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) == 0) { 516 is16bit = 0; 517 memsize = 8192; 518 } 519 520 #ifdef WE_DEBUG 521 { 522 int i; 523 524 printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, " 525 "memsize = %d\n", type, typestr, is16bit, memsize); 526 for (i = 0; i < 8; i++) 527 printf(" %d -> 0x%x\n", i, 528 bus_space_read_1(asict, asich, i)); 529 } 530 #endif 531 532 if (typep != NULL) 533 *typep = type; 534 if (memsizep != NULL) 535 *memsizep = memsize; 536 if (is16bitp != NULL) 537 *is16bitp = is16bit; 538 if (is790p != NULL) 539 *is790p = is790; 540 return (typestr); 541 } 542