1 /* $NetBSD: if_we_isa.c,v 1.4 2001/11/13 08:01:21 lukem 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.4 2001/11/13 08:01:21 lukem 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 struct cfattach we_isa_ca = { 97 sizeof(struct we_softc), we_isa_probe, we_isa_attach 98 }; 99 100 extern struct cfdriver we_cd; 101 102 static const char *we_params __P((bus_space_tag_t, bus_space_handle_t, 103 u_int8_t *, bus_size_t *, int *, int *)); 104 105 static const int we_584_irq[] = { 106 9, 3, 5, 7, 10, 11, 15, 4, 107 }; 108 #define NWE_584_IRQ (sizeof(we_584_irq) / sizeof(we_584_irq[0])) 109 110 static const int we_790_irq[] = { 111 IRQUNK, 9, 3, 5, 7, 10, 11, 15, 112 }; 113 #define NWE_790_IRQ (sizeof(we_790_irq) / sizeof(we_790_irq[0])) 114 115 /* 116 * Delay needed when switching 16-bit access to shared memory. 117 */ 118 #define WE_DELAY(wsc) delay(3) 119 120 /* 121 * Enable card RAM, and 16-bit access. 122 */ 123 #define WE_MEM_ENABLE(wsc) \ 124 do { \ 125 if ((wsc)->sc_16bitp) \ 126 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 127 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \ 128 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 129 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \ 130 WE_DELAY((wsc)); \ 131 } while (0) 132 133 /* 134 * Disable card RAM, and 16-bit access. 135 */ 136 #define WE_MEM_DISABLE(wsc) \ 137 do { \ 138 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 139 WE_MSR, (wsc)->sc_msr_proto); \ 140 if ((wsc)->sc_16bitp) \ 141 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 142 WE_LAAR, (wsc)->sc_laar_proto); \ 143 WE_DELAY((wsc)); \ 144 } while (0) 145 146 int 147 we_isa_probe(parent, cf, aux) 148 struct device *parent; 149 struct cfdata *cf; 150 void *aux; 151 { 152 struct isa_attach_args *ia = aux; 153 bus_space_tag_t asict, memt; 154 bus_space_handle_t asich, memh; 155 bus_size_t memsize; 156 int asich_valid, memh_valid; 157 int i, is790, rv = 0; 158 u_int8_t x, type; 159 160 asict = ia->ia_iot; 161 memt = ia->ia_memt; 162 163 asich_valid = memh_valid = 0; 164 165 /* Disallow wildcarded i/o addresses. */ 166 if (ia->ia_iobase == ISACF_PORT_DEFAULT) 167 return (0); 168 169 /* Disallow wildcarded mem address. */ 170 if (ia->ia_maddr == ISACF_IOMEM_DEFAULT) 171 return (0); 172 173 /* Attempt to map the device. */ 174 if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich)) 175 goto out; 176 asich_valid = 1; 177 178 #ifdef TOSH_ETHER 179 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_POW); 180 #endif 181 182 /* 183 * Attempt to do a checksum over the station address PROM. 184 * If it fails, it's probably not a WD/SMC board. There is 185 * a problem with this, though. Some clone WD8003E boards 186 * (e.g. Danpex) won't pass the checksum. In this case, 187 * the checksum byte always seems to be 0. 188 */ 189 for (x = 0, i = 0; i < 8; i++) 190 x += bus_space_read_1(asict, asich, WE_PROM + i); 191 192 if (x != WE_ROM_CHECKSUM_TOTAL) { 193 /* Make sure it's an 8003E clone... */ 194 if (bus_space_read_1(asict, asich, WE_CARD_ID) != 195 WE_TYPE_WD8003E) 196 goto out; 197 198 /* Check the checksum byte. */ 199 if (bus_space_read_1(asict, asich, WE_PROM + 7) != 0) 200 goto out; 201 } 202 203 /* 204 * Reset the card to force it into a known state. 205 */ 206 #ifdef TOSH_ETHER 207 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST | WE_MSR_POW); 208 #else 209 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST); 210 #endif 211 delay(100); 212 213 bus_space_write_1(asict, asich, WE_MSR, 214 bus_space_read_1(asict, asich, WE_MSR) & ~WE_MSR_RST); 215 216 /* Wait in case the card is reading it's EEPROM. */ 217 delay(5000); 218 219 /* 220 * Get parameters. 221 */ 222 if (we_params(asict, asich, &type, &memsize, NULL, &is790) == NULL) 223 goto out; 224 225 /* Allow user to override probed value. */ 226 if (ia->ia_msize) 227 memsize = ia->ia_msize; 228 229 /* Attempt to map the memory space. */ 230 if (bus_space_map(memt, ia->ia_maddr, memsize, 0, &memh)) 231 goto out; 232 memh_valid = 1; 233 234 /* 235 * If possible, get the assigned interrupt number from the card 236 * and use it. 237 */ 238 if (is790) { 239 u_int8_t hwr; 240 241 /* Assemble together the encoded interrupt number. */ 242 hwr = bus_space_read_1(asict, asich, WE790_HWR); 243 bus_space_write_1(asict, asich, WE790_HWR, 244 hwr | WE790_HWR_SWH); 245 246 x = bus_space_read_1(asict, asich, WE790_GCR); 247 i = ((x & WE790_GCR_IR2) >> 4) | 248 ((x & (WE790_GCR_IR1|WE790_GCR_IR0)) >> 2); 249 bus_space_write_1(asict, asich, WE790_HWR, 250 hwr & ~WE790_HWR_SWH); 251 252 if (ia->ia_irq != IRQUNK && ia->ia_irq != we_790_irq[i]) 253 printf("%s%d: overriding IRQ %d to %d\n", 254 we_cd.cd_name, cf->cf_unit, ia->ia_irq, 255 we_790_irq[i]); 256 ia->ia_irq = we_790_irq[i]; 257 } else if (type & WE_SOFTCONFIG) { 258 /* Assemble together the encoded interrupt number. */ 259 i = (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_IR2) | 260 ((bus_space_read_1(asict, asich, WE_IRR) & 261 (WE_IRR_IR0 | WE_IRR_IR1)) >> 5); 262 263 if (ia->ia_irq != IRQUNK && ia->ia_irq != we_584_irq[i]) 264 printf("%s%d: overriding IRQ %d to %d\n", 265 we_cd.cd_name, cf->cf_unit, ia->ia_irq, 266 we_584_irq[i]); 267 ia->ia_irq = we_584_irq[i]; 268 } 269 270 /* So, we say we've found it! */ 271 ia->ia_iosize = WE_NPORTS; 272 ia->ia_msize = memsize; 273 rv = 1; 274 275 out: 276 if (asich_valid) 277 bus_space_unmap(asict, asich, WE_NPORTS); 278 if (memh_valid) 279 bus_space_unmap(memt, memh, memsize); 280 return (rv); 281 } 282 283 void 284 we_isa_attach(parent, self, aux) 285 struct device *parent, *self; 286 void *aux; 287 { 288 struct we_softc *wsc = (struct we_softc *)self; 289 struct dp8390_softc *sc = &wsc->sc_dp8390; 290 struct isa_attach_args *ia = aux; 291 bus_space_tag_t nict, asict, memt; 292 bus_space_handle_t nich, asich, memh; 293 const char *typestr; 294 295 printf("\n"); 296 297 nict = asict = ia->ia_iot; 298 memt = ia->ia_memt; 299 300 /* Map the device. */ 301 if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich)) { 302 printf("%s: can't map nic i/o space\n", 303 sc->sc_dev.dv_xname); 304 return; 305 } 306 307 if (bus_space_subregion(asict, asich, WE_NIC_OFFSET, WE_NIC_NPORTS, 308 &nich)) { 309 printf("%s: can't subregion i/o space\n", 310 sc->sc_dev.dv_xname); 311 return; 312 } 313 314 typestr = we_params(asict, asich, &wsc->sc_type, NULL, 315 &wsc->sc_16bitp, &sc->is790); 316 if (typestr == NULL) { 317 printf("%s: where did the card go?\n", sc->sc_dev.dv_xname); 318 return; 319 } 320 321 /* 322 * Map memory space. Note we use the size that might have 323 * been overridden by the user. 324 */ 325 if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh)) { 326 printf("%s: can't map shared memory\n", 327 sc->sc_dev.dv_xname); 328 return; 329 } 330 331 wsc->sc_asict = asict; 332 wsc->sc_asich = asich; 333 334 sc->sc_regt = nict; 335 sc->sc_regh = nich; 336 337 sc->sc_buft = memt; 338 sc->sc_bufh = memh; 339 340 wsc->sc_maddr = ia->ia_maddr; 341 sc->mem_size = ia->ia_msize; 342 343 /* Interface is always enabled. */ 344 sc->sc_enabled = 1; 345 346 if (we_config(self, wsc, typestr)) 347 return; 348 349 /* 350 * Enable the configured interrupt. 351 */ 352 if (sc->is790) 353 bus_space_write_1(asict, asich, WE790_ICR, 354 bus_space_read_1(asict, asich, WE790_ICR) | 355 WE790_ICR_EIL); 356 else if (wsc->sc_type & WE_SOFTCONFIG) 357 bus_space_write_1(asict, asich, WE_IRR, 358 bus_space_read_1(asict, asich, WE_IRR) | WE_IRR_IEN); 359 else if (ia->ia_irq == IRQUNK) { 360 printf("%s: can't wildcard IRQ on a %s\n", 361 sc->sc_dev.dv_xname, typestr); 362 return; 363 } 364 365 /* Establish interrupt handler. */ 366 wsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 367 IPL_NET, dp8390_intr, sc); 368 if (wsc->sc_ih == NULL) 369 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); 370 } 371 372 static const char * 373 we_params(asict, asich, typep, memsizep, is16bitp, is790p) 374 bus_space_tag_t asict; 375 bus_space_handle_t asich; 376 u_int8_t *typep; 377 bus_size_t *memsizep; 378 int *is16bitp, *is790p; 379 { 380 const char *typestr; 381 bus_size_t memsize; 382 int is16bit, is790; 383 u_int8_t type; 384 385 memsize = 8192; 386 is16bit = is790 = 0; 387 388 type = bus_space_read_1(asict, asich, WE_CARD_ID); 389 switch (type) { 390 case WE_TYPE_WD8003S: 391 typestr = "WD8003S"; 392 break; 393 case WE_TYPE_WD8003E: 394 typestr = "WD8003E"; 395 break; 396 case WE_TYPE_WD8003EB: 397 typestr = "WD8003EB"; 398 break; 399 case WE_TYPE_WD8003W: 400 typestr = "WD8003W"; 401 break; 402 case WE_TYPE_WD8013EBT: 403 typestr = "WD8013EBT"; 404 memsize = 16384; 405 is16bit = 1; 406 break; 407 case WE_TYPE_WD8013W: 408 typestr = "WD8013W"; 409 memsize = 16384; 410 is16bit = 1; 411 break; 412 case WE_TYPE_WD8013EP: /* also WD8003EP */ 413 if (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) { 414 is16bit = 1; 415 memsize = 16384; 416 typestr = "WD8013EP"; 417 } else 418 typestr = "WD8003EP"; 419 break; 420 case WE_TYPE_WD8013WC: 421 typestr = "WD8013WC"; 422 memsize = 16384; 423 is16bit = 1; 424 break; 425 case WE_TYPE_WD8013EBP: 426 typestr = "WD8013EBP"; 427 memsize = 16384; 428 is16bit = 1; 429 break; 430 case WE_TYPE_WD8013EPC: 431 typestr = "WD8013EPC"; 432 memsize = 16384; 433 is16bit = 1; 434 break; 435 case WE_TYPE_SMC8216C: 436 case WE_TYPE_SMC8216T: 437 { 438 u_int8_t hwr; 439 440 typestr = (type == WE_TYPE_SMC8216C) ? 441 "SMC8216/SMC8216C" : "SMC8216T"; 442 443 hwr = bus_space_read_1(asict, asich, WE790_HWR); 444 bus_space_write_1(asict, asich, WE790_HWR, 445 hwr | WE790_HWR_SWH); 446 switch (bus_space_read_1(asict, asich, WE790_RAR) & 447 WE790_RAR_SZ64) { 448 case WE790_RAR_SZ64: 449 memsize = 65536; 450 break; 451 case WE790_RAR_SZ32: 452 memsize = 32768; 453 break; 454 case WE790_RAR_SZ16: 455 memsize = 16384; 456 break; 457 case WE790_RAR_SZ8: 458 /* 8216 has 16K shared mem -- 8416 has 8K */ 459 typestr = (type == WE_TYPE_SMC8216C) ? 460 "SMC8416C/SMC8416BT" : "SMC8416T"; 461 memsize = 8192; 462 break; 463 } 464 bus_space_write_1(asict, asich, WE790_HWR, hwr); 465 466 is16bit = 1; 467 is790 = 1; 468 break; 469 } 470 #ifdef TOSH_ETHER 471 case WE_TYPE_TOSHIBA1: 472 typestr = "Toshiba1"; 473 memsize = 32768; 474 is16bit = 1; 475 break; 476 case WE_TYPE_TOSHIBA4: 477 typestr = "Toshiba4"; 478 memsize = 32768; 479 is16bit = 1; 480 break; 481 #endif 482 default: 483 /* Not one we recognize. */ 484 return (NULL); 485 } 486 487 /* 488 * Make some adjustments to initial values depending on what is 489 * found in the ICR. 490 */ 491 if (is16bit && (type != WE_TYPE_WD8013EBT) && 492 #ifdef TOSH_ETHER 493 (type != WE_TYPE_TOSHIBA1 && type != WE_TYPE_TOSHIBA4) && 494 #endif 495 (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) == 0) { 496 is16bit = 0; 497 memsize = 8192; 498 } 499 500 #ifdef WE_DEBUG 501 { 502 int i; 503 504 printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, " 505 "memsize = %d\n", type, typestr, is16bit, memsize); 506 for (i = 0; i < 8; i++) 507 printf(" %d -> 0x%x\n", i, 508 bus_space_read_1(asict, asich, i)); 509 } 510 #endif 511 512 if (typep != NULL) 513 *typep = type; 514 if (memsizep != NULL) 515 *memsizep = memsize; 516 if (is16bitp != NULL) 517 *is16bitp = is16bit; 518 if (is790p != NULL) 519 *is790p = is790; 520 return (typestr); 521 } 522