eisaconf.c revision 139749
1/*- 2 * EISA bus probe and attach routines 3 * 4 * Copyright (c) 1995, 1996 Justin T. Gibbs. 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 immediately at the beginning of the file, without modification, 12 * this list of conditions, and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/sys/dev/eisa/eisaconf.c 139749 2005-01-06 01:43:34Z imp $"); 35 36#include "opt_eisa.h" 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/queue.h> 41#include <sys/limits.h> 42#include <sys/malloc.h> 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/bus.h> 46 47#include <machine/bus.h> 48#include <machine/resource.h> 49#include <sys/rman.h> 50 51#include <dev/eisa/eisaconf.h> 52 53typedef struct resvaddr { 54 u_long addr; /* start address */ 55 u_long size; /* size of reserved area */ 56 int flags; 57 struct resource *res; /* resource manager handle */ 58 LIST_ENTRY(resvaddr) links; /* List links */ 59} resvaddr_t; 60 61LIST_HEAD(resvlist, resvaddr); 62 63struct irq_node { 64 int irq_no; 65 int irq_trigger; 66 void *idesc; 67 TAILQ_ENTRY(irq_node) links; 68}; 69 70TAILQ_HEAD(irqlist, irq_node); 71 72struct eisa_ioconf { 73 int slot; 74 struct resvlist ioaddrs; /* list of reserved I/O ranges */ 75 struct resvlist maddrs; /* list of reserved memory ranges */ 76 struct irqlist irqs; /* list of reserved irqs */ 77}; 78 79/* To be replaced by the "super device" generic device structure... */ 80struct eisa_device { 81 eisa_id_t id; 82 struct eisa_ioconf ioconf; 83}; 84 85 86#define MAX_COL 79 87#ifndef EISA_SLOTS 88#define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */ 89#endif 90int num_eisa_slots = EISA_SLOTS; 91TUNABLE_INT("hw.eisa_slots", &num_eisa_slots); 92 93static devclass_t eisa_devclass; 94 95static int eisa_probe_slot(int slot, eisa_id_t *eisa_id); 96static void eisa_reg_print (device_t, char *, char *, int *); 97static struct irq_node * eisa_find_irq(struct eisa_device *e_dev, int rid); 98static struct resvaddr * eisa_find_maddr(struct eisa_device *e_dev, int rid); 99static struct resvaddr * eisa_find_ioaddr(struct eisa_device *e_dev, int rid); 100 101static int 102mainboard_probe(device_t dev) 103{ 104 char *idstring; 105 eisa_id_t id = eisa_get_id(dev); 106 107 if (eisa_get_slot(dev) != 0) 108 return (ENXIO); 109 110 idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1, 111 M_DEVBUF, M_NOWAIT); 112 if (idstring == NULL) { 113 panic("Eisa probe unable to malloc"); 114 } 115 sprintf(idstring, "%c%c%c%03x%01x (System Board)", 116 EISA_MFCTR_CHAR0(id), 117 EISA_MFCTR_CHAR1(id), 118 EISA_MFCTR_CHAR2(id), 119 EISA_PRODUCT_ID(id), 120 EISA_REVISION_ID(id)); 121 device_set_desc(dev, idstring); 122 123 return (0); 124} 125 126static int 127mainboard_attach(device_t dev) 128{ 129 return (0); 130} 131 132static device_method_t mainboard_methods[] = { 133 /* Device interface */ 134 DEVMETHOD(device_probe, mainboard_probe), 135 DEVMETHOD(device_attach, mainboard_attach), 136 137 { 0, 0 } 138}; 139 140static driver_t mainboard_driver = { 141 "mainboard", 142 mainboard_methods, 143 1, 144}; 145 146static devclass_t mainboard_devclass; 147 148DRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0); 149 150/* 151** probe for EISA devices 152*/ 153static int 154eisa_probe(device_t dev) 155{ 156 int devices_found, slot; 157 struct eisa_device *e_dev; 158 device_t child; 159 eisa_id_t eisa_id; 160 161 device_set_desc(dev, "EISA bus"); 162 163 devices_found = 0; 164 for (slot = 0; slot < num_eisa_slots; slot++) { 165 eisa_id = 0; 166 if (eisa_probe_slot(slot, &eisa_id)) { 167 /* 168 * If there's no card in the first slot (the 169 * mainboard), then the system doesn't have EISA. 170 * We abort the probe early in this case since 171 * continuing on causes a hang on some systems. 172 * Interestingly enough, the inb has been seen to 173 * cause the hang. However, aborting here causes 174 * the Adaptec 2842 probe to fail so that driver 175 * needs to be fixed separately. 176 */ 177 if (slot == 0) 178 break; 179 continue; 180 } 181 182 devices_found++; 183 184 /* Prepare an eisa_device_node for this slot */ 185 e_dev = (struct eisa_device *)malloc(sizeof(*e_dev), 186 M_DEVBUF, M_NOWAIT|M_ZERO); 187 if (!e_dev) { 188 device_printf(dev, "cannot malloc eisa_device"); 189 break; /* Try to attach what we have already */ 190 } 191 192 e_dev->id = eisa_id; 193 e_dev->ioconf.slot = slot; 194 195 /* Initialize our lists of reserved addresses */ 196 LIST_INIT(&(e_dev->ioconf.ioaddrs)); 197 LIST_INIT(&(e_dev->ioconf.maddrs)); 198 TAILQ_INIT(&(e_dev->ioconf.irqs)); 199 200 child = device_add_child(dev, NULL, -1); 201 device_set_ivars(child, e_dev); 202 } 203 204 /* 205 * EISA busses themselves are not easily detectable, the easiest way 206 * to tell if there is an eisa bus is if we found something - there 207 * should be a motherboard "card" there somewhere. 208 */ 209 return devices_found ? 0 : ENXIO; 210} 211 212static int 213eisa_probe_slot(int slot, eisa_id_t *eisa_id) 214{ 215 eisa_id_t probe_id; 216 int base, i, id_size; 217 218 probe_id = 0; 219 id_size = sizeof(probe_id); 220 base = 0x0c80 + (slot * 0x1000); 221 222 for (i = 0; i < id_size; i++) 223 probe_id |= inb(base + i) << ((id_size - i - 1) * CHAR_BIT); 224 225 /* If we found a card, return its EISA id. */ 226 if ((probe_id & 0x80000000) == 0) { 227 *eisa_id = probe_id; 228 return (0); 229 } 230 231 return (ENXIO); 232} 233 234static void 235eisa_probe_nomatch(device_t dev, device_t child) 236{ 237 u_int32_t eisa_id = eisa_get_id(child); 238 u_int8_t slot = eisa_get_slot(child); 239 240 device_printf(dev, "unknown card %c%c%c%03x%01x (0x%08x) at slot %d\n", 241 EISA_MFCTR_CHAR0(eisa_id), 242 EISA_MFCTR_CHAR1(eisa_id), 243 EISA_MFCTR_CHAR2(eisa_id), 244 EISA_PRODUCT_ID(eisa_id), 245 EISA_REVISION_ID(eisa_id), 246 eisa_id, 247 slot); 248 249 return; 250} 251 252static void 253eisa_reg_print (dev, string, separator, column) 254 device_t dev; 255 char * string; 256 char * separator; 257 int * column; 258{ 259 int length = strlen(string); 260 261 length += (separator ? 2 : 1); 262 263 if (((*column) + length) >= MAX_COL) { 264 printf("\n"); 265 (*column) = 0; 266 } else if ((*column) != 0) { 267 if (separator) { 268 printf("%c", *separator); 269 (*column)++; 270 } 271 printf(" "); 272 (*column)++; 273 } 274 275 if ((*column) == 0) { 276 (*column) += device_printf(dev, "%s", string); 277 } else { 278 (*column) += printf("%s", string); 279 } 280 281 return; 282} 283 284static int 285eisa_print_child(device_t dev, device_t child) 286{ 287 char buf[81]; 288 struct eisa_device * e_dev = device_get_ivars(child); 289 int rid; 290 struct irq_node * irq; 291 struct resvaddr * resv; 292 char separator = ','; 293 int column = 0; 294 int retval = 0; 295 296 if (device_get_desc(child)) { 297 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child)); 298 eisa_reg_print(child, buf, NULL, &column); 299 } 300 301 rid = 0; 302 while ((resv = eisa_find_ioaddr(e_dev, rid++))) { 303 if ((resv->size == 1) || 304 (resv->flags & RESVADDR_BITMASK)) { 305 snprintf(buf, sizeof(buf), "%s%lx", 306 ((rid == 1) ? "at 0x" : "0x"), 307 resv->addr); 308 } else { 309 snprintf(buf, sizeof(buf), "%s%lx-0x%lx", 310 ((rid == 1) ? "at 0x" : "0x"), 311 resv->addr, 312 (resv->addr + (resv->size - 1))); 313 } 314 eisa_reg_print(child, buf, 315 ((rid == 2) ? &separator : NULL), &column); 316 } 317 318 rid = 0; 319 while ((resv = eisa_find_maddr(e_dev, rid++))) { 320 if ((resv->size == 1) || 321 (resv->flags & RESVADDR_BITMASK)) { 322 snprintf(buf, sizeof(buf), "%s%lx", 323 ((rid == 1) ? "at 0x" : "0x"), 324 resv->addr); 325 } else { 326 snprintf(buf, sizeof(buf), "%s%lx-0x%lx", 327 ((rid == 1) ? "at 0x" : "0x"), 328 resv->addr, 329 (resv->addr + (resv->size - 1))); 330 } 331 eisa_reg_print(child, buf, 332 ((rid == 2) ? &separator : NULL), &column); 333 } 334 335 rid = 0; 336 while ((irq = eisa_find_irq(e_dev, rid++)) != NULL) { 337 snprintf(buf, sizeof(buf), "irq %d (%s)", irq->irq_no, 338 (irq->irq_trigger ? "level" : "edge")); 339 eisa_reg_print(child, buf, 340 ((rid == 1) ? &separator : NULL), &column); 341 } 342 343 snprintf(buf, sizeof(buf), "on %s slot %d\n", 344 device_get_nameunit(dev), eisa_get_slot(child)); 345 eisa_reg_print(child, buf, NULL, &column); 346 347 return (retval); 348} 349 350static struct irq_node * 351eisa_find_irq(struct eisa_device *e_dev, int rid) 352{ 353 int i; 354 struct irq_node *irq; 355 356 for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs); 357 i < rid && irq; 358 i++, irq = TAILQ_NEXT(irq, links)) 359 ; 360 361 if (irq) 362 return (irq); 363 else 364 return (NULL); 365} 366 367static struct resvaddr * 368eisa_find_maddr(struct eisa_device *e_dev, int rid) 369{ 370 int i; 371 struct resvaddr *resv; 372 373 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs); 374 i < rid && resv; 375 i++, resv = LIST_NEXT(resv, links)) 376 ; 377 378 return resv; 379} 380 381static struct resvaddr * 382eisa_find_ioaddr(struct eisa_device *e_dev, int rid) 383{ 384 int i; 385 struct resvaddr *resv; 386 387 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs); 388 i < rid && resv; 389 i++, resv = LIST_NEXT(resv, links)) 390 ; 391 392 return resv; 393} 394 395static int 396eisa_read_ivar(device_t dev, device_t child, int which, u_long *result) 397{ 398 struct eisa_device *e_dev = device_get_ivars(child); 399 struct irq_node *irq; 400 401 switch (which) { 402 case EISA_IVAR_SLOT: 403 *result = e_dev->ioconf.slot; 404 break; 405 406 case EISA_IVAR_ID: 407 *result = e_dev->id; 408 break; 409 410 case EISA_IVAR_IRQ: 411 /* XXX only first irq */ 412 if ((irq = eisa_find_irq(e_dev, 0)) != NULL) { 413 *result = irq->irq_no; 414 } else { 415 *result = -1; 416 } 417 break; 418 419 default: 420 return (ENOENT); 421 } 422 423 return (0); 424} 425 426static int 427eisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 428{ 429 return (EINVAL); 430} 431 432static struct resource * 433eisa_alloc_resource(device_t dev, device_t child, int type, int *rid, 434 u_long start, u_long end, u_long count, u_int flags) 435{ 436 int isdefault; 437 struct eisa_device *e_dev = device_get_ivars(child); 438 struct resource *rv, **rvp = 0; 439 440 isdefault = (device_get_parent(child) == dev 441 && start == 0UL && end == ~0UL && count == 1); 442 443 switch (type) { 444 case SYS_RES_IRQ: 445 if (isdefault) { 446 struct irq_node * irq = eisa_find_irq(e_dev, *rid); 447 if (irq == NULL) 448 return 0; 449 start = end = irq->irq_no; 450 count = 1; 451 if (irq->irq_trigger == EISA_TRIGGER_LEVEL) { 452 flags |= RF_SHAREABLE; 453 } else { 454 flags &= ~RF_SHAREABLE; 455 } 456 } 457 break; 458 459 case SYS_RES_MEMORY: 460 if (isdefault) { 461 struct resvaddr *resv; 462 463 resv = eisa_find_maddr(e_dev, *rid); 464 if (!resv) 465 return 0; 466 467 start = resv->addr; 468 end = resv->addr + (resv->size - 1); 469 count = resv->size; 470 rvp = &resv->res; 471 } 472 break; 473 474 case SYS_RES_IOPORT: 475 if (isdefault) { 476 struct resvaddr *resv; 477 478 resv = eisa_find_ioaddr(e_dev, *rid); 479 if (!resv) 480 return 0; 481 482 start = resv->addr; 483 end = resv->addr + (resv->size - 1); 484 count = resv->size; 485 rvp = &resv->res; 486 } 487 break; 488 489 default: 490 return 0; 491 } 492 493 rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 494 type, rid, start, end, count, flags); 495 if (rvp) 496 *rvp = rv; 497 498 return rv; 499} 500 501static int 502eisa_release_resource(device_t dev, device_t child, int type, int rid, 503 struct resource *r) 504{ 505 int rv; 506 struct eisa_device *e_dev = device_get_ivars(child); 507 struct resvaddr *resv = 0; 508 509 switch (type) { 510 case SYS_RES_IRQ: 511 if (eisa_find_irq(e_dev, rid) == NULL) 512 return EINVAL; 513 break; 514 515 case SYS_RES_MEMORY: 516 if (device_get_parent(child) == dev) 517 resv = eisa_find_maddr(e_dev, rid); 518 break; 519 520 521 case SYS_RES_IOPORT: 522 if (device_get_parent(child) == dev) 523 resv = eisa_find_ioaddr(e_dev, rid); 524 break; 525 526 default: 527 return (ENOENT); 528 } 529 530 rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); 531 532 if (rv == 0) { 533 if (resv) 534 resv->res = 0; 535 } 536 537 return rv; 538} 539 540static int 541eisa_add_intr_m(device_t eisa, device_t dev, int irq, int trigger) 542{ 543 struct eisa_device *e_dev = device_get_ivars(dev); 544 struct irq_node *irq_info; 545 546 irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF, 547 M_NOWAIT); 548 if (irq_info == NULL) 549 return (1); 550 551 irq_info->irq_no = irq; 552 irq_info->irq_trigger = trigger; 553 irq_info->idesc = NULL; 554 TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links); 555 return 0; 556} 557 558static int 559eisa_add_resvaddr(struct eisa_device *e_dev, struct resvlist *head, u_long base, 560 u_long size, int flags) 561{ 562 resvaddr_t *reservation; 563 564 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t), 565 M_DEVBUF, M_NOWAIT); 566 if(!reservation) 567 return (ENOMEM); 568 569 reservation->addr = base; 570 reservation->size = size; 571 reservation->flags = flags; 572 573 if (!LIST_FIRST(head)) { 574 LIST_INSERT_HEAD(head, reservation, links); 575 } 576 else { 577 resvaddr_t *node; 578 LIST_FOREACH(node, head, links) { 579 if (node->addr > reservation->addr) { 580 /* 581 * List is sorted in increasing 582 * address order. 583 */ 584 LIST_INSERT_BEFORE(node, reservation, links); 585 break; 586 } 587 588 if (node->addr == reservation->addr) { 589 /* 590 * If the entry we want to add 591 * matches any already in here, 592 * fail. 593 */ 594 free(reservation, M_DEVBUF); 595 return (EEXIST); 596 } 597 598 if (!LIST_NEXT(node, links)) { 599 LIST_INSERT_AFTER(node, reservation, links); 600 break; 601 } 602 } 603 } 604 return (0); 605} 606 607static int 608eisa_add_mspace_m(device_t eisa, device_t dev, u_long mbase, u_long msize, 609 int flags) 610{ 611 struct eisa_device *e_dev = device_get_ivars(dev); 612 613 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize, 614 flags); 615} 616 617static int 618eisa_add_iospace_m(device_t eisa, device_t dev, u_long iobase, u_long iosize, 619 int flags) 620{ 621 struct eisa_device *e_dev = device_get_ivars(dev); 622 623 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase, 624 iosize, flags); 625} 626 627static device_method_t eisa_methods[] = { 628 /* Device interface */ 629 DEVMETHOD(device_probe, eisa_probe), 630 DEVMETHOD(device_attach, bus_generic_attach), 631 DEVMETHOD(device_shutdown, bus_generic_shutdown), 632 DEVMETHOD(device_suspend, bus_generic_suspend), 633 DEVMETHOD(device_resume, bus_generic_resume), 634 635 /* Bus interface */ 636 DEVMETHOD(bus_print_child, eisa_print_child), 637 DEVMETHOD(bus_probe_nomatch, eisa_probe_nomatch), 638 DEVMETHOD(bus_read_ivar, eisa_read_ivar), 639 DEVMETHOD(bus_write_ivar, eisa_write_ivar), 640 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 641 DEVMETHOD(bus_alloc_resource, eisa_alloc_resource), 642 DEVMETHOD(bus_release_resource, eisa_release_resource), 643 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 644 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 645 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 646 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 647 648 /* EISA interface */ 649 DEVMETHOD(eisa_add_intr, eisa_add_intr_m), 650 DEVMETHOD(eisa_add_iospace, eisa_add_iospace_m), 651 DEVMETHOD(eisa_add_mspace, eisa_add_mspace_m), 652 653 { 0, 0 } 654}; 655 656static driver_t eisa_driver = { 657 "eisa", 658 eisa_methods, 659 1, /* no softc */ 660}; 661 662DRIVER_MODULE(eisa, eisab, eisa_driver, eisa_devclass, 0, 0); 663DRIVER_MODULE(eisa, legacy, eisa_driver, eisa_devclass, 0, 0); 664