1 /* $NetBSD: if_le_isa.c,v 1.41 2005/12/24 20:27:41 perry Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause AND BSD-3-Clause 5 * 6 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 11 * Simulation Facility, NASA Ames Research Center. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /*- 36 * Copyright (c) 1992, 1993 37 * The Regents of the University of California. All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Ralph Campbell and Rick Macklem. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 67 */ 68 69 #include <sys/cdefs.h> 70 #include <sys/param.h> 71 #include <sys/systm.h> 72 #include <sys/bus.h> 73 #include <sys/endian.h> 74 #include <sys/kernel.h> 75 #include <sys/lock.h> 76 #include <sys/module.h> 77 #include <sys/mutex.h> 78 #include <sys/resource.h> 79 #include <sys/rman.h> 80 #include <sys/socket.h> 81 82 #include <net/ethernet.h> 83 #include <net/if.h> 84 #include <net/if_media.h> 85 86 #include <machine/bus.h> 87 #include <machine/resource.h> 88 89 #include <isa/isavar.h> 90 91 #include <dev/le/lancereg.h> 92 #include <dev/le/lancevar.h> 93 #include <dev/le/am7990var.h> 94 95 #define LE_ISA_MEMSIZE (16*1024) 96 #define PCNET_RDP 0x10 97 #define PCNET_RAP 0x12 98 99 struct le_isa_softc { 100 struct am7990_softc sc_am7990; /* glue to MI code */ 101 102 bus_size_t sc_rap; /* offsets to LANCE... */ 103 bus_size_t sc_rdp; /* ...registers */ 104 105 struct resource *sc_rres; 106 107 struct resource *sc_dres; 108 109 struct resource *sc_ires; 110 void *sc_ih; 111 112 bus_dma_tag_t sc_pdmat; 113 bus_dma_tag_t sc_dmat; 114 bus_dmamap_t sc_dmam; 115 }; 116 117 static device_probe_t le_isa_probe; 118 static device_attach_t le_isa_attach; 119 static device_detach_t le_isa_detach; 120 static device_resume_t le_isa_resume; 121 static device_suspend_t le_isa_suspend; 122 123 static device_method_t le_isa_methods[] = { 124 /* Device interface */ 125 DEVMETHOD(device_probe, le_isa_probe), 126 DEVMETHOD(device_attach, le_isa_attach), 127 DEVMETHOD(device_detach, le_isa_detach), 128 /* We can just use the suspend method here. */ 129 DEVMETHOD(device_shutdown, le_isa_suspend), 130 DEVMETHOD(device_suspend, le_isa_suspend), 131 DEVMETHOD(device_resume, le_isa_resume), 132 133 { 0, 0 } 134 }; 135 136 struct le_isa_param { 137 const char *name; 138 u_long iosize; 139 bus_size_t rap; 140 bus_size_t rdp; 141 bus_size_t macstart; 142 int macstride; 143 } static const le_isa_params[] = { 144 { "BICC Isolan", 24, 0xe, 0xc, 0, 2 }, 145 { "Novell NE2100", 16, 0x12, 0x10, 0, 1 } 146 }; 147 148 static struct isa_pnp_id le_isa_ids[] = { 149 { 0x0322690e, "Cabletron E2200 Single Chip" }, /* CSI2203 */ 150 { 0x0110490a, "Boca LANCard Combo" }, /* BRI1001 */ 151 { 0x0100a60a, "Melco Inc. LGY-IV" }, /* BUF0001 */ 152 { 0xd880d041, "Novell NE2100" }, /* PNP80D8 */ 153 { 0x0082d041, "Cabletron E2100 Series DNI" }, /* PNP8200 */ 154 { 0x3182d041, "AMD AM1500T/AM2100" }, /* PNP8231 */ 155 { 0x8c82d041, "AMD PCnet-ISA" }, /* PNP828C */ 156 { 0x8d82d041, "AMD PCnet-32" }, /* PNP828D */ 157 { 0xcefaedfe, "Racal InterLan EtherBlaster" }, /* _WMFACE */ 158 { 0, NULL } 159 }; 160 161 static void le_isa_wrcsr(struct lance_softc *, uint16_t, uint16_t); 162 static uint16_t le_isa_rdcsr(struct lance_softc *, uint16_t); 163 static bus_dmamap_callback_t le_isa_dma_callback; 164 static int le_isa_probe_legacy(device_t, const struct le_isa_param *); 165 166 static void 167 le_isa_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 168 { 169 struct le_isa_softc *lesc = (struct le_isa_softc *)sc; 170 171 bus_write_2(lesc->sc_rres, lesc->sc_rap, port); 172 bus_barrier(lesc->sc_rres, lesc->sc_rap, 2, BUS_SPACE_BARRIER_WRITE); 173 bus_write_2(lesc->sc_rres, lesc->sc_rdp, val); 174 } 175 176 static uint16_t 177 le_isa_rdcsr(struct lance_softc *sc, uint16_t port) 178 { 179 struct le_isa_softc *lesc = (struct le_isa_softc *)sc; 180 181 bus_write_2(lesc->sc_rres, lesc->sc_rap, port); 182 bus_barrier(lesc->sc_rres, lesc->sc_rap, 2, BUS_SPACE_BARRIER_WRITE); 183 return (bus_read_2(lesc->sc_rres, lesc->sc_rdp)); 184 } 185 186 static void 187 le_isa_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) 188 { 189 struct lance_softc *sc = (struct lance_softc *)xsc; 190 191 if (error != 0) 192 return; 193 KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__)); 194 sc->sc_addr = segs[0].ds_addr; 195 } 196 197 static int 198 le_isa_probe_legacy(device_t dev, const struct le_isa_param *leip) 199 { 200 struct le_isa_softc *lesc; 201 struct lance_softc *sc; 202 int error, i; 203 204 lesc = device_get_softc(dev); 205 sc = &lesc->sc_am7990.lsc; 206 207 i = 0; 208 lesc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &i, 209 leip->iosize, RF_ACTIVE); 210 if (lesc->sc_rres == NULL) 211 return (ENXIO); 212 lesc->sc_rap = leip->rap; 213 lesc->sc_rdp = leip->rdp; 214 215 /* Stop the chip and put it in a known state. */ 216 le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP); 217 DELAY(100); 218 if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP) { 219 error = ENXIO; 220 goto fail; 221 } 222 le_isa_wrcsr(sc, LE_CSR3, 0); 223 error = 0; 224 225 fail: 226 bus_release_resource(dev, SYS_RES_IOPORT, 227 rman_get_rid(lesc->sc_rres), lesc->sc_rres); 228 return (error); 229 } 230 231 static int 232 le_isa_probe(device_t dev) 233 { 234 int i; 235 236 switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) { 237 case 0: 238 return (BUS_PROBE_DEFAULT); 239 case ENOENT: 240 for (i = 0; i < nitems(le_isa_params); i++) { 241 if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) { 242 device_set_desc(dev, le_isa_params[i].name); 243 return (BUS_PROBE_DEFAULT); 244 } 245 } 246 /* FALLTHROUGH */ 247 case ENXIO: 248 default: 249 return (ENXIO); 250 } 251 } 252 253 static int 254 le_isa_attach(device_t dev) 255 { 256 struct le_isa_softc *lesc; 257 struct lance_softc *sc; 258 bus_size_t macstart, rap, rdp; 259 int error, i, j, macstride; 260 261 lesc = device_get_softc(dev); 262 sc = &lesc->sc_am7990.lsc; 263 264 LE_LOCK_INIT(sc, device_get_nameunit(dev)); 265 266 j = 0; 267 switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) { 268 case 0: 269 lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 270 &j, RF_ACTIVE); 271 rap = PCNET_RAP; 272 rdp = PCNET_RDP; 273 macstart = 0; 274 macstride = 1; 275 break; 276 case ENOENT: 277 for (i = 0; i < nitems(le_isa_params); i++) { 278 if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) { 279 lesc->sc_rres = bus_alloc_resource_anywhere(dev, 280 SYS_RES_IOPORT, &j, 281 le_isa_params[i].iosize, RF_ACTIVE); 282 rap = le_isa_params[i].rap; 283 rdp = le_isa_params[i].rdp; 284 macstart = le_isa_params[i].macstart; 285 macstride = le_isa_params[i].macstride; 286 goto found; 287 } 288 } 289 /* FALLTHROUGH */ 290 case ENXIO: 291 default: 292 device_printf(dev, "cannot determine chip\n"); 293 error = ENXIO; 294 goto fail_mtx; 295 } 296 297 found: 298 if (lesc->sc_rres == NULL) { 299 device_printf(dev, "cannot allocate registers\n"); 300 error = ENXIO; 301 goto fail_mtx; 302 } 303 lesc->sc_rap = rap; 304 lesc->sc_rdp = rdp; 305 306 i = 0; 307 if ((lesc->sc_dres = bus_alloc_resource_any(dev, SYS_RES_DRQ, 308 &i, RF_ACTIVE)) == NULL) { 309 device_printf(dev, "cannot allocate DMA channel\n"); 310 error = ENXIO; 311 goto fail_rres; 312 } 313 314 i = 0; 315 if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 316 &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 317 device_printf(dev, "cannot allocate interrupt\n"); 318 error = ENXIO; 319 goto fail_dres; 320 } 321 322 error = bus_dma_tag_create( 323 bus_get_dma_tag(dev), /* parent */ 324 1, 0, /* alignment, boundary */ 325 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */ 326 BUS_SPACE_MAXADDR, /* highaddr */ 327 NULL, NULL, /* filter, filterarg */ 328 BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 329 0, /* nsegments */ 330 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 331 0, /* flags */ 332 NULL, NULL, /* lockfunc, lockarg */ 333 &lesc->sc_pdmat); 334 if (error != 0) { 335 device_printf(dev, "cannot allocate parent DMA tag\n"); 336 goto fail_ires; 337 } 338 339 sc->sc_memsize = LE_ISA_MEMSIZE; 340 /* 341 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte 342 * aligned and the ring descriptors must be 8-byte aligned. 343 */ 344 error = bus_dma_tag_create( 345 lesc->sc_pdmat, /* parent */ 346 8, 0, /* alignment, boundary */ 347 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */ 348 BUS_SPACE_MAXADDR, /* highaddr */ 349 NULL, NULL, /* filter, filterarg */ 350 sc->sc_memsize, /* maxsize */ 351 1, /* nsegments */ 352 sc->sc_memsize, /* maxsegsize */ 353 0, /* flags */ 354 NULL, NULL, /* lockfunc, lockarg */ 355 &lesc->sc_dmat); 356 if (error != 0) { 357 device_printf(dev, "cannot allocate buffer DMA tag\n"); 358 goto fail_pdtag; 359 } 360 361 error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem, 362 BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam); 363 if (error != 0) { 364 device_printf(dev, "cannot allocate DMA buffer memory\n"); 365 goto fail_dtag; 366 } 367 368 sc->sc_addr = 0; 369 error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem, 370 sc->sc_memsize, le_isa_dma_callback, sc, 0); 371 if (error != 0 || sc->sc_addr == 0) { 372 device_printf(dev, "cannot load DMA buffer map\n"); 373 goto fail_dmem; 374 } 375 376 isa_dmacascade(rman_get_start(lesc->sc_dres)); 377 378 sc->sc_flags = 0; 379 sc->sc_conf3 = 0; 380 381 /* 382 * Extract the physical MAC address from the ROM. 383 */ 384 for (i = 0; i < sizeof(sc->sc_enaddr); i++) 385 sc->sc_enaddr[i] = bus_read_1(lesc->sc_rres, 386 macstart + i * macstride); 387 388 sc->sc_copytodesc = lance_copytobuf_contig; 389 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 390 sc->sc_copytobuf = lance_copytobuf_contig; 391 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 392 sc->sc_zerobuf = lance_zerobuf_contig; 393 394 sc->sc_rdcsr = le_isa_rdcsr; 395 sc->sc_wrcsr = le_isa_wrcsr; 396 sc->sc_hwreset = NULL; 397 sc->sc_hwinit = NULL; 398 sc->sc_hwintr = NULL; 399 sc->sc_nocarrier = NULL; 400 sc->sc_mediachange = NULL; 401 sc->sc_mediastatus = NULL; 402 sc->sc_supmedia = NULL; 403 404 error = am7990_config(&lesc->sc_am7990, device_get_name(dev), 405 device_get_unit(dev)); 406 if (error != 0) { 407 device_printf(dev, "cannot attach Am7990\n"); 408 goto fail_dmap; 409 } 410 411 error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, 412 NULL, am7990_intr, sc, &lesc->sc_ih); 413 if (error != 0) { 414 device_printf(dev, "cannot set up interrupt\n"); 415 goto fail_am7990; 416 } 417 418 return (0); 419 420 fail_am7990: 421 am7990_detach(&lesc->sc_am7990); 422 fail_dmap: 423 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 424 fail_dmem: 425 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 426 fail_dtag: 427 bus_dma_tag_destroy(lesc->sc_dmat); 428 fail_pdtag: 429 bus_dma_tag_destroy(lesc->sc_pdmat); 430 fail_ires: 431 bus_release_resource(dev, SYS_RES_IRQ, 432 rman_get_rid(lesc->sc_ires), lesc->sc_ires); 433 fail_dres: 434 bus_release_resource(dev, SYS_RES_DRQ, 435 rman_get_rid(lesc->sc_dres), lesc->sc_dres); 436 fail_rres: 437 bus_release_resource(dev, SYS_RES_IOPORT, 438 rman_get_rid(lesc->sc_rres), lesc->sc_rres); 439 fail_mtx: 440 LE_LOCK_DESTROY(sc); 441 return (error); 442 } 443 444 static int 445 le_isa_detach(device_t dev) 446 { 447 struct le_isa_softc *lesc; 448 struct lance_softc *sc; 449 450 lesc = device_get_softc(dev); 451 sc = &lesc->sc_am7990.lsc; 452 453 bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); 454 am7990_detach(&lesc->sc_am7990); 455 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 456 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 457 bus_dma_tag_destroy(lesc->sc_dmat); 458 bus_dma_tag_destroy(lesc->sc_pdmat); 459 bus_release_resource(dev, SYS_RES_IRQ, 460 rman_get_rid(lesc->sc_ires), lesc->sc_ires); 461 bus_release_resource(dev, SYS_RES_DRQ, 462 rman_get_rid(lesc->sc_dres), lesc->sc_dres); 463 bus_release_resource(dev, SYS_RES_IOPORT, 464 rman_get_rid(lesc->sc_rres), lesc->sc_rres); 465 LE_LOCK_DESTROY(sc); 466 467 return (0); 468 } 469 470 static int 471 le_isa_suspend(device_t dev) 472 { 473 struct le_isa_softc *lesc; 474 475 lesc = device_get_softc(dev); 476 477 lance_suspend(&lesc->sc_am7990.lsc); 478 479 return (0); 480 } 481 482 static int 483 le_isa_resume(device_t dev) 484 { 485 struct le_isa_softc *lesc; 486 487 lesc = device_get_softc(dev); 488 489 lance_resume(&lesc->sc_am7990.lsc); 490 491 return (0); 492 } 493 494 DEFINE_CLASS_0(le, le_isa_driver, le_isa_methods, sizeof(struct le_isa_softc)); 495 DRIVER_MODULE(le, isa, le_isa_driver, 0, 0); 496 MODULE_DEPEND(le, ether, 1, 1, 1); 497 ISA_PNP_INFO(le_isa_ids); 498