if_le_cbus.c revision 158829
1/*- 2 * Copyright (c) 1994-2000 3 * Paul Richards. All rights reserved. 4 * 5 * PC-98 port by Chiharu Shibata & FreeBSD(98) porting team. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * verbatim and that no modifications are made prior to this 13 * point in the file. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name Paul Richards may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL PAUL RICHARDS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * from: FreeBSD: src/sys/dev/lnc/if_lnc_cbus.c,v 1.12 2005/11/12 19:14:21 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/dev/le/if_le_cbus.c 158829 2006-05-22 13:43:36Z nyan $"); 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/bus.h> 41#include <sys/endian.h> 42#include <sys/kernel.h> 43#include <sys/lock.h> 44#include <sys/module.h> 45#include <sys/mutex.h> 46#include <sys/resource.h> 47#include <sys/rman.h> 48#include <sys/socket.h> 49 50#include <net/ethernet.h> 51#include <net/if.h> 52#include <net/if_media.h> 53 54#include <machine/bus.h> 55#include <machine/resource.h> 56 57#include <isa/isavar.h> 58 59#include <dev/le/lancereg.h> 60#include <dev/le/lancevar.h> 61#include <dev/le/am7990var.h> 62 63#define LE_CBUS_MEMSIZE (16*1024) 64#define CNET98S_IOSIZE 32 65#define CNET98S_RDP 0x10 66#define CNET98S_RAP 0x12 67#define CNET98S_RESET 0x14 68#define CNET98S_BDP 0x16 69 70struct le_cbus_softc { 71 struct am7990_softc sc_am7990; /* glue to MI code */ 72 73 int sc_rrid; 74 struct resource *sc_rres; 75 bus_space_tag_t sc_regt; 76 bus_space_handle_t sc_regh; 77 78 int sc_irid; 79 struct resource *sc_ires; 80 void *sc_ih; 81 82 bus_dma_tag_t sc_pdmat; 83 bus_dma_tag_t sc_dmat; 84 bus_dmamap_t sc_dmam; 85}; 86 87static device_probe_t le_cbus_probe; 88static device_attach_t le_cbus_attach; 89static device_detach_t le_cbus_detach; 90static device_resume_t le_cbus_resume; 91static device_suspend_t le_cbus_suspend; 92 93static device_method_t le_cbus_methods[] = { 94 /* Device interface */ 95 DEVMETHOD(device_probe, le_cbus_probe), 96 DEVMETHOD(device_attach, le_cbus_attach), 97 DEVMETHOD(device_detach, le_cbus_detach), 98 /* We can just use the suspend method here. */ 99 DEVMETHOD(device_shutdown, le_cbus_suspend), 100 DEVMETHOD(device_suspend, le_cbus_suspend), 101 DEVMETHOD(device_resume, le_cbus_resume), 102 103 { 0, 0 } 104}; 105 106DEFINE_CLASS_0(le, le_cbus_driver, le_cbus_methods, sizeof(struct le_cbus_softc)); 107DRIVER_MODULE(le, isa, le_cbus_driver, le_devclass, 0, 0); 108MODULE_DEPEND(le, ether, 1, 1, 1); 109 110static bus_addr_t le_ioaddr_cnet98s[CNET98S_IOSIZE] = { 111 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 112 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, 113 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 114 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f, 115}; 116 117static void le_cbus_wrbcr(struct lance_softc *, uint16_t, uint16_t); 118#ifdef LEDEBUG 119static uint16_t le_cbus_rdbcr(struct lance_softc *, uint16_t); 120#endif 121static void le_cbus_wrcsr(struct lance_softc *, uint16_t, uint16_t); 122static uint16_t le_cbus_rdcsr(struct lance_softc *, uint16_t); 123static void le_cbus_hwreset(struct lance_softc *); 124static bus_dmamap_callback_t le_cbus_dma_callback; 125 126static void 127le_cbus_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val) 128{ 129 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc; 130 131 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port); 132 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2, 133 BUS_SPACE_BARRIER_WRITE); 134 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP, val); 135} 136 137#ifdef LEDEBUG 138static uint16_t 139le_cbus_rdbcr(struct lance_softc *sc, uint16_t port) 140{ 141 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc; 142 143 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port); 144 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2, 145 BUS_SPACE_BARRIER_WRITE); 146 return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP)); 147} 148#endif 149 150static void 151le_cbus_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 152{ 153 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc; 154 155 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port); 156 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2, 157 BUS_SPACE_BARRIER_WRITE); 158 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP, val); 159} 160 161static uint16_t 162le_cbus_rdcsr(struct lance_softc *sc, uint16_t port) 163{ 164 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc; 165 166 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port); 167 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2, 168 BUS_SPACE_BARRIER_WRITE); 169 return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP)); 170} 171 172static void 173le_cbus_hwreset(struct lance_softc *sc) 174{ 175 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc; 176 177 /* 178 * NB: These are Contec C-NET(98)S only. 179 */ 180 181 /* Reset the chip. */ 182 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET, 183 bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET)); 184 DELAY(500); 185 186 /* ISA bus configuration */ 187 /* ISACSR0 - set Master Mode Read Active time to 300ns. */ 188 le_cbus_wrbcr(sc, LE_BCR0, 0x0006); 189 /* ISACSR1 - set Master Mode Write Active time to 300ns. */ 190 le_cbus_wrbcr(sc, LE_BCR1, 0x0006); 191#ifdef LEDEBUG 192 device_printf(dev, "ISACSR2=0x%x\n", le_cbus_rdbcr(sc, LE_BCR2)); 193#endif 194 /* ISACSR5 - LED1 */ 195 le_cbus_wrbcr(sc, LE_BCR5, LE_B4_PSE | LE_B4_XMTE); 196 /* ISACSR6 - LED2 */ 197 le_cbus_wrbcr(sc, LE_BCR6, LE_B4_PSE | LE_B4_RCVE); 198 /* ISACSR7 - LED3 */ 199 le_cbus_wrbcr(sc, LE_BCR7, LE_B4_PSE | LE_B4_COLE); 200} 201 202static void 203le_cbus_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) 204{ 205 struct lance_softc *sc = (struct lance_softc *)xsc; 206 207 if (error != 0) 208 return; 209 KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__)); 210 sc->sc_addr = segs[0].ds_addr; 211} 212 213static int 214le_cbus_probe(device_t dev) 215{ 216 struct le_cbus_softc *lesc; 217 struct lance_softc *sc; 218 int error; 219 220 /* 221 * Skip PnP devices as some wedge when trying to probe them as 222 * C-NET(98)S. 223 */ 224 if (isa_get_vendorid(dev)) 225 return (ENXIO); 226 227 lesc = device_get_softc(dev); 228 sc = &lesc->sc_am7990.lsc; 229 230 lesc->sc_rrid = 0; 231 lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid, 232 le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE); 233 if (lesc->sc_rres == NULL) 234 return (ENXIO); 235 isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE); 236 lesc->sc_regt = rman_get_bustag(lesc->sc_rres); 237 lesc->sc_regh = rman_get_bushandle(lesc->sc_rres); 238 239 /* Reset the chip. */ 240 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET, 241 bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET)); 242 DELAY(500); 243 244 /* Stop the chip and put it in a known state. */ 245 le_cbus_wrcsr(sc, LE_CSR0, LE_C0_STOP); 246 DELAY(100); 247 if (le_cbus_rdcsr(sc, LE_CSR0) != LE_C0_STOP) { 248 error = ENXIO; 249 goto fail; 250 } 251 le_cbus_wrcsr(sc, LE_CSR3, 0); 252 device_set_desc(dev, "C-NET(98)S"); 253 error = BUS_PROBE_DEFAULT; 254 255 fail: 256 bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres); 257 return (error); 258} 259 260static int 261le_cbus_attach(device_t dev) 262{ 263 struct le_cbus_softc *lesc; 264 struct lance_softc *sc; 265 int error, i; 266 267 lesc = device_get_softc(dev); 268 sc = &lesc->sc_am7990.lsc; 269 270 LE_LOCK_INIT(sc, device_get_nameunit(dev)); 271 272 lesc->sc_rrid = 0; 273 lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid, 274 le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE); 275 if (lesc->sc_rres == NULL) { 276 device_printf(dev, "cannot allocate registers\n"); 277 error = ENXIO; 278 goto fail_mtx; 279 } 280 isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE); 281 lesc->sc_regt = rman_get_bustag(lesc->sc_rres); 282 lesc->sc_regh = rman_get_bushandle(lesc->sc_rres); 283 284 lesc->sc_irid = 0; 285 if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 286 &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 287 device_printf(dev, "cannot allocate interrupt\n"); 288 error = ENXIO; 289 goto fail_rres; 290 } 291 292 error = bus_dma_tag_create( 293 NULL, /* parent */ 294 1, 0, /* alignment, boundary */ 295 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */ 296 BUS_SPACE_MAXADDR, /* highaddr */ 297 NULL, NULL, /* filter, filterarg */ 298 BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 299 0, /* nsegments */ 300 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 301 BUS_DMA_WAITOK, /* flags */ 302 NULL, NULL, /* lockfunc, lockarg */ 303 &lesc->sc_pdmat); 304 if (error != 0) { 305 device_printf(dev, "cannot allocate parent DMA tag\n"); 306 goto fail_ires; 307 } 308 309 sc->sc_memsize = LE_CBUS_MEMSIZE; 310 /* 311 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte 312 * aligned and the ring descriptors must be 8-byte aligned. 313 */ 314 error = bus_dma_tag_create( 315 lesc->sc_pdmat, /* parent */ 316 8, 0, /* alignment, boundary */ 317 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */ 318 BUS_SPACE_MAXADDR, /* highaddr */ 319 NULL, NULL, /* filter, filterarg */ 320 sc->sc_memsize, /* maxsize */ 321 1, /* nsegments */ 322 sc->sc_memsize, /* maxsegsize */ 323 BUS_DMA_WAITOK, /* flags */ 324 NULL, NULL, /* lockfunc, lockarg */ 325 &lesc->sc_dmat); 326 if (error != 0) { 327 device_printf(dev, "cannot allocate buffer DMA tag\n"); 328 goto fail_pdtag; 329 } 330 331 error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem, 332 BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam); 333 if (error != 0) { 334 device_printf(dev, "cannot allocate DMA buffer memory\n"); 335 goto fail_dtag; 336 } 337 338 sc->sc_addr = 0; 339 error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem, 340 sc->sc_memsize, le_cbus_dma_callback, sc, 0); 341 if (error != 0 || sc->sc_addr == 0) { 342 device_printf(dev, "cannot load DMA buffer map\n"); 343 goto fail_dmem; 344 } 345 346 sc->sc_flags = 0; 347 sc->sc_conf3 = 0; 348 349 /* 350 * Extract the physical MAC address from the ROM. 351 */ 352 for (i = 0; i < sizeof(sc->sc_enaddr); i++) 353 sc->sc_enaddr[i] = bus_space_read_1(lesc->sc_regt, 354 lesc->sc_regh, i * 2); 355 356 sc->sc_copytodesc = lance_copytobuf_contig; 357 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 358 sc->sc_copytobuf = lance_copytobuf_contig; 359 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 360 sc->sc_zerobuf = lance_zerobuf_contig; 361 362 sc->sc_rdcsr = le_cbus_rdcsr; 363 sc->sc_wrcsr = le_cbus_wrcsr; 364 sc->sc_hwreset = le_cbus_hwreset; 365 sc->sc_hwinit = NULL; 366 sc->sc_hwintr = NULL; 367 sc->sc_nocarrier = NULL; 368 sc->sc_mediachange = NULL; 369 sc->sc_mediastatus = NULL; 370 sc->sc_supmedia = NULL; 371 372 error = am7990_config(&lesc->sc_am7990, device_get_name(dev), 373 device_get_unit(dev)); 374 if (error != 0) { 375 device_printf(dev, "cannot attach Am7990\n"); 376 goto fail_dmap; 377 } 378 379 error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, 380 am7990_intr, sc, &lesc->sc_ih); 381 if (error != 0) { 382 device_printf(dev, "cannot set up interrupt\n"); 383 goto fail_am7990; 384 } 385 386 return (0); 387 388 fail_am7990: 389 am7990_detach(&lesc->sc_am7990); 390 fail_dmap: 391 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 392 fail_dmem: 393 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 394 fail_dtag: 395 bus_dma_tag_destroy(lesc->sc_dmat); 396 fail_pdtag: 397 bus_dma_tag_destroy(lesc->sc_pdmat); 398 fail_ires: 399 bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); 400 fail_rres: 401 bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres); 402 fail_mtx: 403 LE_LOCK_DESTROY(sc); 404 return (error); 405} 406 407static int 408le_cbus_detach(device_t dev) 409{ 410 struct le_cbus_softc *lesc; 411 struct lance_softc *sc; 412 413 lesc = device_get_softc(dev); 414 sc = &lesc->sc_am7990.lsc; 415 416 bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); 417 am7990_detach(&lesc->sc_am7990); 418 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 419 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 420 bus_dma_tag_destroy(lesc->sc_dmat); 421 bus_dma_tag_destroy(lesc->sc_pdmat); 422 bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); 423 bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres); 424 LE_LOCK_DESTROY(sc); 425 426 return (0); 427} 428 429static int 430le_cbus_suspend(device_t dev) 431{ 432 struct le_cbus_softc *lesc; 433 434 lesc = device_get_softc(dev); 435 436 lance_suspend(&lesc->sc_am7990.lsc); 437 438 return (0); 439} 440 441static int 442le_cbus_resume(device_t dev) 443{ 444 struct le_cbus_softc *lesc; 445 446 lesc = device_get_softc(dev); 447 448 lance_resume(&lesc->sc_am7990.lsc); 449 450 return (0); 451} 452