if_fea.c revision 32350
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 1997/09/21 21:35:24 gibbs Exp $ 25 */ 26 27/* 28 * DEC PDQ FDDI Controller 29 * 30 * This module support the DEFEA EISA FDDI Controller. 31 */ 32 33#include "opt_inet.h" 34 35#include <sys/param.h> 36#include <sys/kernel.h> 37#include <sys/socket.h> 38#if defined(__bsdi__) || defined(__NetBSD__) 39#include <sys/device.h> 40#endif 41 42#include <net/ethernet.h> 43#include <net/if.h> 44#include <net/if_arp.h> 45 46#ifdef INET 47#include <netinet/in.h> 48#endif 49 50#if defined(__FreeBSD__) 51#include <i386/eisa/eisaconf.h> 52#include <dev/pdq/pdqvar.h> 53#include <dev/pdq/pdqreg.h> 54#elif defined(__bsdi__) 55#include <i386/isa/isa.h> 56#include <i386/isa/icu.h> 57#include <i386/isa/dma.h> 58#include <i386/isa/isavar.h> 59#include <i386/eisa/eisa.h> 60#include <dev/pdq/pdqvar.h> 61#include <dev/pdq/pdqreg.h> 62#elif defined(__NetBSD__) 63#include <machine/cpu.h> 64#include <machine/bus.h> 65 66#include <dev/ic/pdqvar.h> 67#include <dev/ic/pdqreg.h> 68 69#include <dev/eisa/eisareg.h> 70#include <dev/eisa/eisavar.h> 71#include <dev/eisa/eisadevs.h> 72#endif 73 74/* 75 * 76 */ 77 78#define DEFEA_IRQS 0x0000FBA9U 79 80#if defined(__FreeBSD__) 81static pdq_softc_t *pdqs_eisa[16]; 82#define PDQ_EISA_UNIT_TO_SOFTC(unit) (pdqs_eisa[unit]) 83#define DEFEA_INTRENABLE 0x8 /* level interrupt */ 84#define pdq_eisa_ifwatchdog NULL 85#define DEFEA_DECODE_IRQ(n) ((DEFEA_IRQS >> ((n) << 2)) & 0x0f) 86 87#elif defined(__bsdi__) 88extern struct cfdriver feacd; 89#define PDQ_EISA_UNIT_TO_SOFTC(unit) ((pdq_softc_t *)feacd.cd_devs[unit]) 90#define DEFEA_INTRENABLE 0x28 /* edge interrupt */ 91static const int pdq_eisa_irqs[4] = { IRQ9, IRQ10, IRQ11, IRQ15 }; 92#define DEFEA_DECODE_IRQ(n) (pdq_eisa_irqs[(n)]) 93 94#elif defined(__NetBSD__) 95#define DEFEA_INTRENABLE 0x8 /* level interrupt */ 96#define pdq_eisa_ifwatchdog NULL 97#define DEFEA_DECODE_IRQ(n) ((DEFEA_IRQS >> ((n) << 2)) & 0x0f) 98 99#else 100#error unknown system 101#endif 102 103#ifndef pdq_eisa_ifwatchdog 104static ifnet_ret_t 105pdq_eisa_ifwatchdog( 106 int unit) 107{ 108 pdq_ifwatchdog(&PDQ_EISA_UNIT_TO_SOFTC(unit)->sc_if); 109} 110#endif 111 112static void 113pdq_eisa_subprobe( 114 pdq_bus_t bc, 115 pdq_bus_ioport_t iobase, 116 pdq_uint32_t *maddr, 117 pdq_uint32_t *msize, 118 pdq_uint32_t *irq) 119{ 120 if (irq != NULL) 121 *irq = DEFEA_DECODE_IRQ(PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_IO_CONFIG_STAT_0) & 3); 122 *maddr = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_0) << 8) 123 | (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_1) << 16); 124 *msize = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_MASK_0) + 4) << 8; 125} 126 127static void 128pdq_eisa_devinit( 129 pdq_softc_t *sc) 130{ 131 pdq_uint8_t data; 132 133 /* 134 * Do the standard initialization for the DEFEA registers. 135 */ 136 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_FUNCTION_CTRL, 0x23); 137 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CMP_1_1, (sc->sc_iobase >> 8) & 0xF0); 138 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CMP_0_1, (sc->sc_iobase >> 8) & 0xF0); 139 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_SLOT_CTRL, 0x01); 140 data = PDQ_OS_IORD_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF); 141#if defined(PDQ_IOMAPPED) 142 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF, data & ~1); 143#else 144 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF, data | 1); 145#endif 146 data = PDQ_OS_IORD_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CONFIG_STAT_0); 147 PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CONFIG_STAT_0, data | DEFEA_INTRENABLE); 148} 149 150#if defined(__FreeBSD__) 151static void pdq_eisa_shutdown(int howto, void *sc); 152static int pdq_eisa_probe(void); 153static int pdq_eisa_attach(struct eisa_device *ed); 154 155static unsigned long pdq_eisa_unit; 156 157static struct eisa_driver pdq_eisa_driver = { 158 "fea", pdq_eisa_probe, pdq_eisa_attach, NULL, &pdq_eisa_unit 159}; 160 161DATA_SET(eisadriver_set, pdq_eisa_driver); 162 163 164static const char * 165pdq_eisa_match( 166 eisa_id_t type) 167{ 168 if ((type >> 8) == 0x10a330) 169 return ("DEC DEFEA EISA FDDI Controller"); 170 return NULL; 171} 172 173static int 174pdq_eisa_probe( 175 void) 176{ 177 struct eisa_device *ed = NULL; 178 int count; 179 180 for (count = 0; (ed = eisa_match_dev(ed, pdq_eisa_match)) != NULL; count++) { 181 pdq_bus_ioport_t iobase = ed->ioconf.slot * EISA_SLOT_SIZE; 182 pdq_uint32_t irq, maddr, msize; 183 184 eisa_add_iospace(ed, iobase, 0x200, RESVADDR_NONE); 185 pdq_eisa_subprobe(PDQ_BUS_EISA, iobase, &maddr, &msize, &irq); 186 eisa_add_mspace(ed, maddr, msize, RESVADDR_NONE); 187 eisa_add_intr(ed, irq); 188 eisa_registerdev(ed, &pdq_eisa_driver); 189 } 190 return count; 191} 192 193static void 194pdq_eisa_interrupt( 195 void *arg) 196{ 197 pdq_softc_t * const sc = (pdq_softc_t *) arg; 198 (void) pdq_interrupt(sc->sc_pdq); 199} 200 201static int 202pdq_eisa_attach( 203 struct eisa_device *ed) 204{ 205 pdq_softc_t *sc; 206 resvaddr_t *iospace; 207 resvaddr_t *mspace; 208 int irq; 209 210 if (TAILQ_FIRST(&ed->ioconf.irqs) == NULL) 211 return (-1); 212 213 irq = TAILQ_FIRST(&ed->ioconf.irqs)->irq_no; 214 215 sc = (pdq_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_WAITOK); 216 if (sc == NULL) { 217 printf("fea%d: malloc failed!\n", sc->sc_if.if_unit); 218 return -1; 219 } 220 pdqs_eisa[ed->unit] = sc; 221 222 bzero(sc, sizeof(pdq_softc_t)); /* Zero out the softc*/ 223 sc->sc_if.if_name = "fea"; 224 sc->sc_if.if_unit = ed->unit; 225 226 if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) { 227 printf("fea%d: no iospace??\n", sc->sc_if.if_unit); 228 return -1; 229 } 230 if ((mspace = ed->ioconf.maddrs.lh_first) == NULL) { 231 printf("fea%d: no memory space??\n", sc->sc_if.if_unit); 232 return -1; 233 } 234 235 sc->sc_iobase = (pdq_bus_ioport_t) iospace->addr; 236 sc->sc_membase = (pdq_bus_memaddr_t) pmap_mapdev(mspace->addr, mspace->size); 237 if (sc->sc_membase == NULL) { 238 printf("fea%d: failed to map memory 0x%x-0x%x!\n", 239 sc->sc_if.if_unit, mspace->addr, mspace->addr + mspace->size - 1); 240 return -1; 241 } 242 243 eisa_reg_start(ed); 244 if (eisa_reg_iospace(ed, iospace)) { 245 printf("fea%d: failed to register iospace 0x%x-0x%x!\n", 246 sc->sc_if.if_unit, iospace->addr, iospace->addr + iospace->size - 1); 247 return -1; 248 } 249 if (eisa_reg_mspace(ed, mspace)) { 250 printf("fea%d: failed to register memory 0x%x-0x%x!\n", 251 sc->sc_if.if_unit, mspace->addr, mspace->addr + mspace->size - 1); 252 return -1; 253 } 254 255 if (eisa_reg_intr(ed, irq, pdq_eisa_interrupt, sc, &net_imask, 1)) { 256 printf("fea%d: interrupt registration failed\n", sc->sc_if.if_unit); 257 return -1; 258 } 259 260 eisa_reg_end(ed); 261 262 pdq_eisa_devinit(sc); 263 sc->sc_pdq = pdq_initialize(PDQ_BUS_EISA, sc->sc_membase, 264 sc->sc_if.if_name, sc->sc_if.if_unit, 265 (void *) sc, PDQ_DEFEA); 266 if (sc->sc_pdq == NULL) { 267 printf("fea%d: initialization failed\n", sc->sc_if.if_unit); 268 return -1; 269 } 270 271 if (eisa_enable_intr(ed, irq)) { 272 printf("fea%d: failed to enable interrupt\n", sc->sc_if.if_unit); 273 return -1; 274 } 275 276 bcopy((caddr_t) sc->sc_pdq->pdq_hwaddr.lanaddr_bytes, sc->sc_ac.ac_enaddr, 6); 277 pdq_ifattach(sc, pdq_eisa_ifwatchdog); 278 at_shutdown(pdq_eisa_shutdown, (void *) sc, SHUTDOWN_POST_SYNC); 279 280 return 0; 281} 282 283static void 284pdq_eisa_shutdown( 285 int howto, 286 void *sc) 287{ 288 pdq_hwreset(((pdq_softc_t *)sc)->sc_pdq); 289} 290#endif /* __FreeBSD__ */ 291 292#if defined(__bsdi__) 293static int 294pdq_eisa_probe( 295 struct device *parent, 296 struct cfdata *cf, 297 void *aux) 298{ 299 struct isa_attach_args *ia = (struct isa_attach_args *) aux; 300 int slot; 301 pdq_uint32_t irq, maddr, msize; 302 303 if (isa_bustype != BUS_EISA) 304 return 0; 305 306 if ((slot = eisa_match(cf, ia)) == 0) 307 return 0; 308 ia->ia_iobase = slot << 12; 309 ia->ia_iosize = EISA_NPORT; 310 eisa_slotalloc(slot); 311 312 pdq_eisa_subprobe(PDQ_BUS_EISA, ia->ia_iobase, &maddr, &msize, &irq); 313 if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) { 314 printf("fea%d: error: desired IRQ of %d does not match device's actual IRQ (%d),\n", 315 cf->cf_unit, 316 ffs(ia->ia_irq) - 1, ffs(irq) - 1); 317 return 0; 318 } 319 if (ia->ia_irq == IRQUNK) { 320 if ((ia->ia_irq = isa_irqalloc(irq)) == 0) { 321 if ((ia->ia_irq = isa_irqalloc(IRQ9|IRQ10|IRQ11|IRQ15)) == 0) { 322 printf("fea%d: error: IRQ %d is already in use\n", cf->cf_unit, 323 ffs(irq) - 1); 324 return 0; 325 } 326 irq = PDQ_OS_IORD_8(PDQ_BUS_EISA, ia->ia_iobase, PDQ_EISA_IO_CONFIG_STAT_0) & ~3; 327 switch (ia->ia_irq) { 328 case IRQ9: irq |= 0; 329 case IRQ10: irq |= 1; 330 case IRQ11: irq |= 2; 331 case IRQ15: irq |= 3; 332 } 333 PDQ_OS_IOWR_8(PDQ_BUS_EISA, ia->ia_iobase, PDQ_EISA_IO_CONFIG_STAT_0, irq); 334 } 335 } 336 if (maddr == 0) { 337 printf("fea%d: error: memory not enabled! ECU reconfiguration required\n", 338 cf->cf_unit); 339 return 0; 340 } 341 342 /* EISA bus masters don't use host DMA channels */ 343 ia->ia_drq = DRQNONE; 344 345 ia->ia_maddr = (caddr_t) maddr; 346 ia->ia_msize = msize; 347 return 1; 348} 349 350static void 351pdq_eisa_attach( 352 struct device *parent, 353 struct device *self, 354 void *aux) 355{ 356 pdq_softc_t *sc = (pdq_softc_t *) self; 357 register struct isa_attach_args *ia = (struct isa_attach_args *) aux; 358 register struct ifnet *ifp = &sc->sc_if; 359 360 sc->sc_if.if_unit = sc->sc_dev.dv_unit; 361 sc->sc_if.if_name = "fea"; 362 sc->sc_if.if_flags = 0; 363 364 sc->sc_iobase = ia->ia_iobase; 365 366 pdq_eisa_devinit(sc); 367 sc->sc_pdq = pdq_initialize(PDQ_BUS_EISA, 368 (pdq_bus_memaddr_t) ISA_HOLE_VADDR(ia->ia_maddr), 369 sc->sc_if.if_name, sc->sc_if.if_unit, 370 (void *) sc, PDQ_DEFEA); 371 if (sc->sc_pdq == NULL) { 372 printf("fea%d: initialization failed\n", sc->sc_if.if_unit); 373 return; 374 } 375 376 bcopy((caddr_t) sc->sc_pdq->pdq_hwaddr.lanaddr_bytes, sc->sc_ac.ac_enaddr, 6); 377 378 pdq_ifattach(sc, pdq_eisa_ifwatchdog); 379 380 isa_establish(&sc->sc_id, &sc->sc_dev); 381 382 sc->sc_ih.ih_fun = pdq_interrupt; 383 sc->sc_ih.ih_arg = (void *) sc->sc_pdq; 384 intr_establish(ia->ia_irq, &sc->sc_ih, DV_NET); 385 386 sc->sc_ats.func = (void (*)(void *)) pdq_hwreset; 387 sc->sc_ats.arg = (void *) sc->sc_pdq; 388 atshutdown(&sc->sc_ats, ATSH_ADD); 389} 390 391static char *pdq_eisa_ids[] = { 392 "DEC3001", /* 0x0130A310 */ 393 "DEC3002", /* 0x0230A310 */ 394 "DEC3003", /* 0x0330A310 */ 395 "DEC3004", /* 0x0430A310 */ 396}; 397 398struct cfdriver feacd = { 399 0, "fea", pdq_eisa_probe, pdq_eisa_attach, DV_IFNET, sizeof(pdq_softc_t), 400 pdq_eisa_ids 401}; 402#endif /* __bsdi__ */ 403 404#if defined(__NetBSD__) 405static int 406pdq_eisa_match( 407 struct device *parent, 408 void *match, 409 void *aux) 410{ 411 const struct eisa_attach_args * const ea = (struct eisa_attach_args *) aux; 412 413 if (strncmp(ea->ea_idstring, "DEC300", 6) == 0) 414 return 1; 415 416 return 0; 417} 418 419static void 420pdq_eisa_attach( 421 struct device *parent, 422 struct device *self, 423 void *aux) 424{ 425 pdq_softc_t * const sc = (pdq_softc_t *) self; 426 struct eisa_attach_args * const ea = (struct eisa_attach_args *) aux; 427 pdq_uint32_t irq, maddr, msize; 428 eisa_intr_handle_t ih; 429 const char *intrstr; 430 431 sc->sc_bc = ea->ea_bc; 432 bcopy(sc->sc_dev.dv_xname, sc->sc_if.if_xname, IFNAMSIZ); 433 sc->sc_if.if_flags = 0; 434 sc->sc_if.if_softc = sc; 435 436 if (bus_io_map(sc->sc_bc, EISA_SLOT_ADDR(ea->ea_slot), EISA_SLOT_SIZE, &sc->sc_iobase)) { 437 printf("\n%s: failed to map I/O!\n", sc->sc_dev.dv_xname); 438 return; 439 } 440 441 pdq_eisa_subprobe(sc->sc_bc, sc->sc_iobase, &maddr, &msize, &irq); 442 443#if !defined(PDQ_IOMAPPED) 444 if (maddr == 0 || msize == 0) { 445 printf("\n%s: error: memory not enabled! ECU reconfiguration required\n", 446 sc->sc_dev.dv_xname); 447 return; 448 } 449 450 if (bus_mem_map(sc->sc_bc, maddr, msize, 0, &sc->sc_membase)) { 451 bus_io_unmap(sc->sc_bc, sc->sc_iobase, EISA_SLOT_SIZE); 452 printf("\n%s: failed to map memory (0x%x-0x%x)!\n", 453 sc->sc_dev.dv_xname, maddr, maddr + msize - 1); 454 return; 455 } 456#endif 457 pdq_eisa_devinit(sc); 458 sc->sc_pdq = pdq_initialize(sc->sc_bc, sc->sc_membase, 459 sc->sc_if.if_xname, 0, 460 (void *) sc, PDQ_DEFEA); 461 if (sc->sc_pdq == NULL) { 462 printf("%s: initialization failed\n", sc->sc_dev.dv_xname); 463 return; 464 } 465 466 bcopy((caddr_t) sc->sc_pdq->pdq_hwaddr.lanaddr_bytes, sc->sc_ac.ac_enaddr, 6); 467 468 pdq_ifattach(sc, pdq_eisa_ifwatchdog); 469 470 if (eisa_intr_map(ea->ea_ec, irq, &ih)) { 471 printf("%s: couldn't map interrupt (%d)\n", sc->sc_dev.dv_xname, irq); 472 return; 473 } 474 intrstr = eisa_intr_string(ea->ea_ec, ih); 475 sc->sc_ih = eisa_intr_establish(ea->ea_ec, ih, IST_LEVEL, IPL_NET, 476 (int (*)(void *)) pdq_interrupt, sc->sc_pdq); 477 if (sc->sc_ih == NULL) { 478 printf("%s: couldn't establish interrupt", sc->sc_dev.dv_xname); 479 if (intrstr != NULL) 480 printf(" at %s", intrstr); 481 printf("\n"); 482 return; 483 } 484 sc->sc_ats = shutdownhook_establish((void (*)(void *)) pdq_hwreset, sc->sc_pdq); 485 if (sc->sc_ats == NULL) 486 printf("%s: warning: couldn't establish shutdown hook\n", self->dv_xname); 487#if !defined(PDQ_IOMAPPED) 488 printf("%s: using iomem 0x%x-0x%x\n", sc->sc_dev.dv_xname, maddr, maddr + msize - 1); 489#endif 490 if (intrstr != NULL) 491 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 492} 493 494struct cfattach fea_ca = { 495 sizeof(pdq_softc_t), pdq_eisa_match, pdq_eisa_attach 496}; 497 498struct cfdriver fea_cd = { 499 0, "fea", DV_IFNET 500}; 501#endif 502