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