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