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