if_fea.c revision 21826
1/*- 2 * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. The name of the author may not be used to endorse or promote products 11 * derived from this software withough specific prior written permission 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * $Id: if_fea.c,v 1.7 1996/07/31 21:38:44 thomas Exp $ 25 */ 26 27/* 28 * DEC PDQ FDDI Controller 29 * 30 * This module support the DEFEA EISA FDDI Controller. 31 */ 32 33 34#include <sys/param.h> 35#include <sys/kernel.h> 36#include <sys/mbuf.h> 37#include <sys/protosw.h> 38#include <sys/socket.h> 39#include <sys/ioctl.h> 40#include <sys/errno.h> 41#include <sys/malloc.h> 42#if defined(__FreeBSD__) 43#include <sys/devconf.h> 44#elif defined(__bsdi__) || defined(__NetBSD__) 45#include <sys/device.h> 46#endif 47 48#include <net/if.h> 49#include <net/if_types.h> 50#include <net/if_dl.h> 51#include <net/route.h> 52 53#include "bpfilter.h" 54#if NBPFILTER > 0 55#include <net/bpf.h> 56#include <net/bpfdesc.h> 57#endif 58 59#ifdef INET 60#include <netinet/in.h> 61#include <netinet/in_systm.h> 62#include <netinet/in_var.h> 63#include <netinet/ip.h> 64#include <netinet/if_ether.h> 65#endif 66 67#if defined(__FreeBSD__) 68#include <netinet/if_fddi.h> 69#else 70#include <net/if_fddi.h> 71#endif 72 73#include <vm/vm.h> 74#include <vm/vm_kern.h> 75#include <vm/vm_param.h> 76 77#if defined(__FreeBSD__) 78#include <i386/eisa/eisaconf.h> 79#include <i386/isa/icu.h> 80#include <dev/pdq/pdqvar.h> 81#include <dev/pdq/pdqreg.h> 82#elif defined(__bsdi__) 83#include <i386/isa/isa.h> 84#include <i386/isa/icu.h> 85#include <i386/isa/dma.h> 86#include <i386/isa/isavar.h> 87#include <i386/eisa/eisa.h> 88#include <dev/pdq/pdqvar.h> 89#include <dev/pdq/pdqreg.h> 90#elif defined(__NetBSD__) 91#include <machine/cpu.h> 92#include <machine/bus.h> 93 94#include <dev/ic/pdqvar.h> 95#include <dev/ic/pdqreg.h> 96 97#include <dev/eisa/eisareg.h> 98#include <dev/eisa/eisavar.h> 99#include <dev/eisa/eisadevs.h> 100#endif 101 102/* 103 * 104 */ 105 106#define DEFEA_IRQS 0x0000FBA9U 107 108#if defined(__FreeBSD__) 109static pdq_softc_t *pdqs_eisa[16]; 110#define PDQ_EISA_UNIT_TO_SOFTC(unit) (pdqs_eisa[unit]) 111#define DEFEA_INTRENABLE 0x8 /* level interrupt */ 112#define pdq_eisa_ifwatchdog NULL 113#define DEFEA_DECODE_IRQ(n) ((DEFEA_IRQS >> ((n) << 2)) & 0x0f) 114 115#elif defined(__bsdi__) 116extern struct cfdriver feacd; 117#define PDQ_EISA_UNIT_TO_SOFTC(unit) ((pdq_softc_t *)feacd.cd_devs[unit]) 118#define DEFEA_INTRENABLE 0x28 /* edge interrupt */ 119static const int pdq_eisa_irqs[4] = { IRQ9, IRQ10, IRQ11, IRQ15 }; 120#define DEFEA_DECODE_IRQ(n) (pdq_eisa_irqs[(n)]) 121 122#elif defined(__NetBSD__) 123#define DEFEA_INTRENABLE 0x8 /* level interrupt */ 124#define pdq_eisa_ifwatchdog NULL 125#define DEFEA_DECODE_IRQ(n) ((DEFEA_IRQS >> ((n) << 2)) & 0x0f) 126 127#else 128#error unknown system 129#endif 130 131#ifndef pdq_eisa_ifwatchdog 132static ifnet_ret_t 133pdq_eisa_ifwatchdog( 134 int unit) 135{ 136 pdq_ifwatchdog(&PDQ_EISA_UNIT_TO_SOFTC(unit)->sc_if); 137} 138#endif 139 140static void 141pdq_eisa_subprobe( 142 pdq_bus_t bc, 143 pdq_bus_ioport_t iobase, 144 pdq_uint32_t *maddr, 145 pdq_uint32_t *msize, 146 pdq_uint32_t *irq) 147{ 148 if (irq != NULL) 149 *irq = DEFEA_DECODE_IRQ(PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_IO_CONFIG_STAT_0) & 3); 150 *maddr = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_0) << 8) 151 | (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_1) << 16); 152 *msize = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_MASK_0) + 4) << 8; 153} 154 155static void 156pdq_eisa_devinit( 157 pdq_softc_t *sc) 158{ 159 pdq_uint8_t data; 160 161 /* 162 * Do the standard initialization for the DEFEA registers. 163 */ 164 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_FUNCTION_CTRL, 0x23); 165 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CMP_1_1, (sc->sc_iobase >> 8) & 0xF0); 166 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CMP_0_1, (sc->sc_iobase >> 8) & 0xF0); 167 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_SLOT_CTRL, 0x01); 168 data = PDQ_OS_IORD_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF); 169#if defined(PDQ_IOMAPPED) 170 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF, data & ~1); 171#else 172 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF, data | 1); 173#endif 174 data = PDQ_OS_IORD_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CONFIG_STAT_0); 175 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CONFIG_STAT_0, data | DEFEA_INTRENABLE); 176} 177 178#if defined(__FreeBSD__) 179static int pdq_eisa_shutdown(struct kern_devconf *kdc, int force); 180static int pdq_eisa_probe(void); 181static int pdq_eisa_attach(struct eisa_device *ed); 182 183static unsigned long pdq_eisa_unit; 184 185static struct eisa_driver pdq_eisa_driver = { 186 "fea", pdq_eisa_probe, pdq_eisa_attach, NULL, &pdq_eisa_unit 187}; 188 189DATA_SET(eisadriver_set, pdq_eisa_driver); 190 191static struct kern_devconf kdc_pdq_eisa = { 192 0, 0, 0, /* filled in by dev_attach */ 193 "fea", 0, { MDDT_EISA, 0, "net" }, 194 eisa_generic_externalize, 0, pdq_eisa_shutdown, EISA_EXTERNALLEN, 195 &kdc_eisa0, /* parent */ 196 0, /* parentdata */ 197 DC_BUSY, /* host adapters are always ``in use'' */ 198 "DEC DEFEA EISA FDDI Controller", 199 DC_CLS_NETIF 200}; 201 202static const char * 203pdq_eisa_match( 204 eisa_id_t type) 205{ 206 if ((type >> 8) == 0x10a330) 207 return kdc_pdq_eisa.kdc_description; 208 return NULL; 209} 210 211static int 212pdq_eisa_probe( 213 void) 214{ 215 struct eisa_device *ed = NULL; 216 int count; 217 218 for (count = 0; (ed = eisa_match_dev(ed, pdq_eisa_match)) != NULL; count++) { 219 pdq_bus_ioport_t iobase = ed->ioconf.slot * EISA_SLOT_SIZE; 220 pdq_uint32_t irq, maddr, msize; 221 222 eisa_add_iospace(ed, iobase, 0x200, RESVADDR_NONE); 223 pdq_eisa_subprobe(PDQ_BUS_EISA, iobase, &maddr, &msize, &irq); 224 eisa_add_mspace(ed, maddr, msize, RESVADDR_NONE); 225 eisa_add_intr(ed, irq); 226 eisa_registerdev(ed, &pdq_eisa_driver, &kdc_pdq_eisa); 227 } 228 return count; 229} 230 231static void 232pdq_eisa_interrupt( 233 void *arg) 234{ 235 pdq_softc_t * const sc = (pdq_softc_t *) arg; 236 (void) pdq_interrupt(sc->sc_pdq); 237} 238 239static int 240pdq_eisa_attach( 241 struct eisa_device *ed) 242{ 243 pdq_softc_t *sc; 244 resvaddr_t *iospace; 245 resvaddr_t *mspace; 246 int irq = ffs(ed->ioconf.irq) - 1; 247 248 sc = (pdq_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_WAITOK); 249 if (sc == NULL) { 250 printf("fea%d: malloc failed!\n", sc->sc_if.if_unit); 251 return -1; 252 } 253 pdqs_eisa[ed->unit] = sc; 254 255 bzero(sc, sizeof(pdq_softc_t)); /* Zero out the softc*/ 256 sc->sc_if.if_name = "fea"; 257 sc->sc_if.if_unit = ed->unit; 258 259 if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) { 260 printf("fea%d: no iospace??\n", sc->sc_if.if_unit); 261 return -1; 262 } 263 if ((mspace = ed->ioconf.maddrs.lh_first) == NULL) { 264 printf("fea%d: no memory space??\n", sc->sc_if.if_unit); 265 return -1; 266 } 267 268 sc->sc_iobase = (pdq_bus_ioport_t) iospace->addr; 269 sc->sc_membase = (pdq_bus_memaddr_t) pmap_mapdev(mspace->addr, mspace->size); 270 if (sc->sc_membase == NULL) { 271 printf("fea%d: failed to map memory 0x%x-0x%x!\n", 272 sc->sc_if.if_unit, mspace->addr, mspace->addr + mspace->size - 1); 273 return -1; 274 } 275 276 eisa_reg_start(ed); 277 if (eisa_reg_iospace(ed, iospace)) { 278 printf("fea%d: failed to register iospace 0x%x-0x%x!\n", 279 sc->sc_if.if_unit, iospace->addr, iospace->addr + iospace->size - 1); 280 return -1; 281 } 282 if (eisa_reg_mspace(ed, mspace)) { 283 printf("fea%d: failed to register memory 0x%x-0x%x!\n", 284 sc->sc_if.if_unit, mspace->addr, mspace->addr + mspace->size - 1); 285 return -1; 286 } 287 288 if (eisa_reg_intr(ed, irq, pdq_eisa_interrupt, sc, &net_imask, 1)) { 289 printf("fea%d: interrupt registration failed\n", sc->sc_if.if_unit); 290 return -1; 291 } 292 293 eisa_reg_end(ed); 294 295 pdq_eisa_devinit(sc); 296 sc->sc_pdq = pdq_initialize(PDQ_BUS_EISA, sc->sc_membase, 297 sc->sc_if.if_name, sc->sc_if.if_unit, 298 (void *) sc, PDQ_DEFEA); 299 if (sc->sc_pdq == NULL) { 300 printf("fea%d: initialization failed\n", sc->sc_if.if_unit); 301 return -1; 302 } 303 304 if (eisa_enable_intr(ed, irq)) { 305 printf("fea%d: failed to enable interrupt\n", sc->sc_if.if_unit); 306 return -1; 307 } 308 309 bcopy((caddr_t) sc->sc_pdq->pdq_hwaddr.lanaddr_bytes, sc->sc_ac.ac_enaddr, 6); 310 pdq_ifattach(sc, pdq_eisa_ifwatchdog); 311 312 ed->kdc->kdc_state = DC_BUSY; /* host adapters always busy */ 313 314 return 0; 315} 316 317static int 318pdq_eisa_shutdown( 319 struct kern_devconf *kdc, 320 int force) 321{ 322 pdq_hwreset(PDQ_EISA_UNIT_TO_SOFTC(kdc->kdc_unit)->sc_pdq); 323 (void) dev_detach(kdc); 324 return 0; 325} 326#endif /* __FreeBSD__ */ 327 328#if defined(__bsdi__) 329static int 330pdq_eisa_probe( 331 struct device *parent, 332 struct cfdata *cf, 333 void *aux) 334{ 335 struct isa_attach_args *ia = (struct isa_attach_args *) aux; 336 int slot; 337 pdq_uint32_t irq, maddr, msize; 338 339 if (isa_bustype != BUS_EISA) 340 return 0; 341 342 if ((slot = eisa_match(cf, ia)) == 0) 343 return 0; 344 ia->ia_iobase = slot << 12; 345 ia->ia_iosize = EISA_NPORT; 346 eisa_slotalloc(slot); 347 348 pdq_eisa_subprobe(PDQ_BUS_EISA, ia->ia_iobase, &maddr, &msize, &irq); 349 if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) { 350 printf("fea%d: error: desired IRQ of %d does not match device's actual IRQ (%d),\n", 351 cf->cf_unit, 352 ffs(ia->ia_irq) - 1, ffs(irq) - 1); 353 return 0; 354 } 355 if (ia->ia_irq == IRQUNK) { 356 if ((ia->ia_irq = isa_irqalloc(irq)) == 0) { 357 if ((ia->ia_irq = isa_irqalloc(IRQ9|IRQ10|IRQ11|IRQ15)) == 0) { 358 printf("fea%d: error: IRQ %d is already in use\n", cf->cf_unit, 359 ffs(irq) - 1); 360 return 0; 361 } 362 irq = PDQ_OS_IORD_8(PDQ_BUS_EISA, ia->ia_iobase, PDQ_EISA_IO_CONFIG_STAT_0) & ~3; 363 switch (ia->ia_irq) { 364 case IRQ9: irq |= 0; 365 case IRQ10: irq |= 1; 366 case IRQ11: irq |= 2; 367 case IRQ15: irq |= 3; 368 } 369 PDQ_OS_IOWR_8(PDQ_BUS_EISA, ia->ia_iobase, PDQ_EISA_IO_CONFIG_STAT_0, irq); 370 } 371 } 372 if (maddr == 0) { 373 printf("fea%d: error: memory not enabled! ECU reconfiguration required\n", 374 cf->cf_unit); 375 return 0; 376 } 377 378 /* EISA bus masters don't use host DMA channels */ 379 ia->ia_drq = DRQNONE; 380 381 ia->ia_maddr = (caddr_t) maddr; 382 ia->ia_msize = msize; 383 return 1; 384} 385 386static void 387pdq_eisa_attach( 388 struct device *parent, 389 struct device *self, 390 void *aux) 391{ 392 pdq_softc_t *sc = (pdq_softc_t *) self; 393 register struct isa_attach_args *ia = (struct isa_attach_args *) aux; 394 register struct ifnet *ifp = &sc->sc_if; 395 396 sc->sc_if.if_unit = sc->sc_dev.dv_unit; 397 sc->sc_if.if_name = "fea"; 398 sc->sc_if.if_flags = 0; 399 400 sc->sc_iobase = ia->ia_iobase; 401 402 pdq_eisa_devinit(sc); 403 sc->sc_pdq = pdq_initialize(PDQ_BUS_EISA, 404 (pdq_bus_memaddr_t) ISA_HOLE_VADDR(ia->ia_maddr), 405 sc->sc_if.if_name, sc->sc_if.if_unit, 406 (void *) sc, PDQ_DEFEA); 407 if (sc->sc_pdq == NULL) { 408 printf("fea%d: initialization failed\n", sc->sc_if.if_unit); 409 return; 410 } 411 412 bcopy((caddr_t) sc->sc_pdq->pdq_hwaddr.lanaddr_bytes, sc->sc_ac.ac_enaddr, 6); 413 414 pdq_ifattach(sc, pdq_eisa_ifwatchdog); 415 416 isa_establish(&sc->sc_id, &sc->sc_dev); 417 418 sc->sc_ih.ih_fun = pdq_interrupt; 419 sc->sc_ih.ih_arg = (void *) sc->sc_pdq; 420 intr_establish(ia->ia_irq, &sc->sc_ih, DV_NET); 421 422 sc->sc_ats.func = (void (*)(void *)) pdq_hwreset; 423 sc->sc_ats.arg = (void *) sc->sc_pdq; 424 atshutdown(&sc->sc_ats, ATSH_ADD); 425} 426 427static char *pdq_eisa_ids[] = { 428 "DEC3001", /* 0x0130A310 */ 429 "DEC3002", /* 0x0230A310 */ 430 "DEC3003", /* 0x0330A310 */ 431 "DEC3004", /* 0x0430A310 */ 432}; 433 434struct cfdriver feacd = { 435 0, "fea", pdq_eisa_probe, pdq_eisa_attach, DV_IFNET, sizeof(pdq_softc_t), 436 pdq_eisa_ids 437}; 438#endif /* __bsdi__ */ 439 440#if defined(__NetBSD__) 441static int 442pdq_eisa_match( 443 struct device *parent, 444 void *match, 445 void *aux) 446{ 447 const struct eisa_attach_args * const ea = (struct eisa_attach_args *) aux; 448 449 if (strncmp(ea->ea_idstring, "DEC300", 6) == 0) 450 return 1; 451 452 return 0; 453} 454 455static void 456pdq_eisa_attach( 457 struct device *parent, 458 struct device *self, 459 void *aux) 460{ 461 pdq_softc_t * const sc = (pdq_softc_t *) self; 462 struct eisa_attach_args * const ea = (struct eisa_attach_args *) aux; 463 pdq_uint32_t irq, maddr, msize; 464 eisa_intr_handle_t ih; 465 const char *intrstr; 466 467 sc->sc_bc = ea->ea_bc; 468 bcopy(sc->sc_dev.dv_xname, sc->sc_if.if_xname, IFNAMSIZ); 469 sc->sc_if.if_flags = 0; 470 sc->sc_if.if_softc = sc; 471 472 if (bus_io_map(sc->sc_bc, EISA_SLOT_ADDR(ea->ea_slot), EISA_SLOT_SIZE, &sc->sc_iobase)) { 473 printf("\n%s: failed to map I/O!\n", sc->sc_dev.dv_xname); 474 return; 475 } 476 477 pdq_eisa_subprobe(sc->sc_bc, sc->sc_iobase, &maddr, &msize, &irq); 478 479#if !defined(PDQ_IOMAPPED) 480 if (maddr == 0 || msize == 0) { 481 printf("\n%s: error: memory not enabled! ECU reconfiguration required\n", 482 sc->sc_dev.dv_xname); 483 return; 484 } 485 486 if (bus_mem_map(sc->sc_bc, maddr, msize, 0, &sc->sc_membase)) { 487 bus_io_unmap(sc->sc_bc, sc->sc_iobase, EISA_SLOT_SIZE); 488 printf("\n%s: failed to map memory (0x%x-0x%x)!\n", 489 sc->sc_dev.dv_xname, maddr, maddr + msize - 1); 490 return; 491 } 492#endif 493 pdq_eisa_devinit(sc); 494 sc->sc_pdq = pdq_initialize(sc->sc_bc, sc->sc_membase, 495 sc->sc_if.if_xname, 0, 496 (void *) sc, PDQ_DEFEA); 497 if (sc->sc_pdq == NULL) { 498 printf("%s: initialization failed\n", sc->sc_dev.dv_xname); 499 return; 500 } 501 502 bcopy((caddr_t) sc->sc_pdq->pdq_hwaddr.lanaddr_bytes, sc->sc_ac.ac_enaddr, 6); 503 504 pdq_ifattach(sc, pdq_eisa_ifwatchdog); 505 506 if (eisa_intr_map(ea->ea_ec, irq, &ih)) { 507 printf("%s: couldn't map interrupt (%d)\n", sc->sc_dev.dv_xname, irq); 508 return; 509 } 510 intrstr = eisa_intr_string(ea->ea_ec, ih); 511 sc->sc_ih = eisa_intr_establish(ea->ea_ec, ih, IST_LEVEL, IPL_NET, 512 (int (*)(void *)) pdq_interrupt, sc->sc_pdq); 513 if (sc->sc_ih == NULL) { 514 printf("%s: couldn't establish interrupt", sc->sc_dev.dv_xname); 515 if (intrstr != NULL) 516 printf(" at %s", intrstr); 517 printf("\n"); 518 return; 519 } 520 sc->sc_ats = shutdownhook_establish((void (*)(void *)) pdq_hwreset, sc->sc_pdq); 521 if (sc->sc_ats == NULL) 522 printf("%s: warning: couldn't establish shutdown hook\n", self->dv_xname); 523#if !defined(PDQ_IOMAPPED) 524 printf("%s: using iomem 0x%x-0x%x\n", sc->sc_dev.dv_xname, maddr, maddr + msize - 1); 525#endif 526 if (intrstr != NULL) 527 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 528} 529 530struct cfattach fea_ca = { 531 sizeof(pdq_softc_t), pdq_eisa_match, pdq_eisa_attach 532}; 533 534struct cfdriver fea_cd = { 535 0, "fea", DV_IFNET 536}; 537#endif 538