diff options
author | gibbs <gibbs@FreeBSD.org> | 1996-01-29 03:13:23 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1996-01-29 03:13:23 +0000 |
commit | 0b627d75b7d924f59d3cc0c0ca10e754ba53854f (patch) | |
tree | 1b6101f6ee35060aacfbf2e0aae2d6e0d2e72010 | |
parent | e94d9bd8af1b0fd9544212c02ae1125ec377a6c3 (diff) | |
download | FreeBSD-src-0b627d75b7d924f59d3cc0c0ca10e754ba53854f.zip FreeBSD-src-0b627d75b7d924f59d3cc0c0ca10e754ba53854f.tar.gz |
Another pass through eisaconf. Ioaddrs and Maddrs are link lists now.
The Bt driver is the only one that actually registers multiple addresses.
Probe output is formatted to 80 columns.
-rw-r--r-- | sys/dev/eisa/eisaconf.c | 342 | ||||
-rw-r--r-- | sys/dev/eisa/eisaconf.h | 37 | ||||
-rw-r--r-- | sys/i386/eisa/aha1742.c | 29 | ||||
-rw-r--r-- | sys/i386/eisa/aic7770.c | 31 | ||||
-rw-r--r-- | sys/i386/eisa/bt74x.c | 280 | ||||
-rw-r--r-- | sys/i386/eisa/eisaconf.c | 342 | ||||
-rw-r--r-- | sys/i386/eisa/eisaconf.h | 37 |
7 files changed, 846 insertions, 252 deletions
diff --git a/sys/dev/eisa/eisaconf.c b/sys/dev/eisa/eisaconf.c index 288c66b..2c583aa 100644 --- a/sys/dev/eisa/eisaconf.c +++ b/sys/dev/eisa/eisaconf.c @@ -1,7 +1,7 @@ /* * EISA bus probe and attach routines * - * Copyright (c) 1995 Justin T. Gibbs. + * Copyright (c) 1995, 1996 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -18,15 +18,15 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: eisaconf.c,v 1.11 1995/12/10 13:33:49 phk Exp $ + * $Id: eisaconf.c,v 1.12 1996/01/03 06:28:01 gibbs Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/devconf.h> #include <sys/kernel.h> #include <sys/sysctl.h> -#include <sys/conf.h> +#include <sys/conf.h> /* For kdc_isa */ #include <sys/malloc.h> -#include <sys/devconf.h> #include <i386/eisa/eisaconf.h> @@ -77,6 +77,30 @@ static struct eisa_driver mainboard_drv = { DATA_SET (eisadriver_set, mainboard_drv); /* + * Local function declarations and static variables + */ +void eisa_reg_print __P((struct eisa_device *e_dev, char *string, + char *separator)); +static int eisa_add_resvaddr __P((struct resvlist *head, u_long base, + u_long size, int flags)); +static int eisa_reg_resvaddr __P((struct eisa_device *e_dev, + struct resvlist *head, resvaddr_t *resvaddr, + int *reg_count)); + +/* + * Keep some state about what we've printed so far + * to make probe output pretty. + */ +static struct { + int in_registration;/* reg_start has been called */ + int num_interrupts; + int num_ioaddrs; + int num_maddrs; + int column; /* How much we have output so far. */ +#define MAX_COL 80 +} reg_state; + +/* ** probe for EISA devices */ void @@ -112,6 +136,7 @@ eisa_configure() } bzero(dev_node, sizeof(*dev_node)); e_dev = &(dev_node->dev); + e_dev->id = eisa_id; /* * Add an EISA ID based descriptive name incase we don't @@ -131,9 +156,13 @@ eisa_configure() EISA_MFCTR_CHAR2(e_dev->id), EISA_PRODUCT_ID(e_dev->id), EISA_REVISION_ID(e_dev->id)); + e_dev->ioconf.slot = slot; - /* Is iobase defined in any EISA specs? */ - e_dev->ioconf.iobase = eisaBase & 0xff00; + + /* Initialize our lists of reserved addresses */ + LIST_INIT(&(e_dev->ioconf.ioaddrs)); + LIST_INIT(&(e_dev->ioconf.maddrs)); + *eisa_dev_list_tail = dev_node; eisa_dev_list_tail = &dev_node->next; } @@ -199,6 +228,7 @@ eisa_configure() for (; dev_node; dev_node=dev_node->next) { e_dev = &dev_node->dev; e_drv = e_dev->driver; + if (e_drv) { /* * Determine the proper unit number for this device. @@ -213,20 +243,25 @@ eisa_configure() */ e_dev->unit = (*e_drv->unit)++; if ((*e_drv->attach)(e_dev) < 0) { - printf("%s0:%d <%s> attach failed\n", + /* Ensure registration has ended */ + reg_state.in_registration = 0; + printf("\n%s0:%d <%s> attach failed\n", mainboard_drv.name, e_dev->ioconf.slot, e_dev->full_name); continue; } + /* Ensure registration has ended */ + reg_state.in_registration = 0; e_dev->kdc->kdc_unit = e_dev->unit; } else { /* Announce unattached device */ - printf("%s0:%d <%s> unknown device\n", + printf("%s0:%d <%s=0x%x> unknown device\n", mainboard_drv.name, e_dev->ioconf.slot, - e_dev->full_name); + e_dev->full_name, + e_dev->id); } } } @@ -267,10 +302,57 @@ eisa_reg_start(e_dev) /* * Announce the device. */ - printf("%s%ld: <%s>", - e_dev->driver->name, - e_dev->unit, - e_dev->full_name); + char *string; + + reg_state.in_registration = 1; + reg_state.num_interrupts = 0; + reg_state.num_ioaddrs = 0; + reg_state.num_maddrs = 0; + reg_state.column = 0; + + string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1, + M_TEMP, M_NOWAIT); + if(!string) { + printf("eisa0: cannot malloc device description string\n"); + return; + } + sprintf(string, " <%s>", e_dev->full_name); + eisa_reg_print(e_dev, string, /*separator=*/NULL); + free(string, M_TEMP); +} + +/* + * Output registration information mindfull of screen wrap. + * Output an optional character separator before the string + * if the line does not wrap. + */ +void +eisa_reg_print(e_dev, string, separator) + struct eisa_device *e_dev; + char *string; + char *separator; +{ + int len = strlen(string); + + if( separator ) + len++; + + if(reg_state.column + len > MAX_COL) { + printf("\n"); + reg_state.column = 0; + } + else if( separator ) { + printf("%c", *separator); + reg_state.column++; + } + + if(reg_state.column == 0) + reg_state.column += printf("%s%ld:%s", + e_dev->driver->name, + e_dev->unit, + string); + else + reg_state.column += printf("%s", string); } /* Interrupt and I/O space registration facitlities */ @@ -278,19 +360,30 @@ void eisa_reg_end(e_dev) struct eisa_device *e_dev; { - /* - * The device should have called eisa_registerdev() - * during its probe. So hopefully we can use the kdc - * to weed out ISA/VL devices that use EISA id registers. - */ - if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) { - printf(" on isa\n"); - } - else { - printf(" on %s0 slot %d\n", - mainboard_drv.name, - e_dev->ioconf.slot); + if( reg_state.in_registration ) + { + /* + * The device should have called eisa_registerdev() + * during its probe. So hopefully we can use the kdc + * to weed out ISA/VL devices that use EISA id registers. + */ + char string[25]; + + if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) { + sprintf(string, " on isa"); + } + else { + sprintf(string, " on %s0 slot %d", + mainboard_drv.name, + e_dev->ioconf.slot); + } + eisa_reg_print(e_dev, string, NULL); + printf("\n"); + reg_state.in_registration = 0; } + else + printf("eisa_reg_end called outside of a " + "registration session\n"); } int @@ -313,6 +406,8 @@ eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) { int result; int s; + char string[25]; + char separator = ','; #if NOT_YET /* @@ -324,28 +419,35 @@ eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) if (haveseen_dev(dev, checkthese)) return 1; #endif - s = splhigh(); - /* - * This should really go to a routine that can optionally - * handle shared interrupts. - */ - result = register_intr(irq, /* isa irq */ - 0, /* deviced?? */ - 0, /* flags? */ - (inthand2_t*) func, /* handler */ - maskptr, /* mask pointer */ - (int)arg); /* handler arg */ - - if (result) { - printf ("eisa_reg_int: result=%d\n", result); + if (reg_state.in_registration) { + s = splhigh(); + /* + * This should really go to a routine that can optionally + * handle shared interrupts. + */ + result = register_intr(irq, /* isa irq */ + 0, /* deviced?? */ + 0, /* flags? */ + (inthand2_t*) func, /* handler */ + maskptr, /* mask pointer */ + (int)arg); /* handler arg */ + + if (result) { + printf ("\neisa_reg_int: result=%d\n", result); + splx(s); + return (result); + }; + update_intr_masks(); splx(s); - return (result); - }; - update_intr_masks(); - splx(s); + } + else + return EPERM; e_dev->ioconf.irq |= 1ul << irq; - printf(" irq %d", irq); + sprintf(string, " irq %d", irq); + eisa_reg_print(e_dev, string, reg_state.num_interrupts ? + &separator : NULL); + reg_state.num_interrupts++; return (0); } @@ -398,31 +500,146 @@ eisa_enable_intr(e_dev, irq) return 0; } +static int +eisa_add_resvaddr(head, base, size, flags) + struct resvlist *head; + u_long base; + u_long size; + int flags; +{ + resvaddr_t *reservation; + + reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t), + M_DEVBUF, M_NOWAIT); + if(!reservation) + return (ENOMEM); + + reservation->addr = base; + reservation->size = size; + reservation->flags = flags; + + if (!head->lh_first) { + LIST_INSERT_HEAD(head, reservation, links); + } + else { + resvaddr_t *node; + for(node = head->lh_first; node; node = node->links.le_next) { + if (node->addr > reservation->addr) { + /* + * List is sorted in increasing + * address order. + */ + LIST_INSERT_BEFORE(node, reservation, links); + break; + } + + if (node->addr == reservation->addr) { + /* + * If the entry we want to add + * matches any already in here, + * fail. + */ + free(reservation, M_DEVBUF); + return (EEXIST); + } + + if (!node->links.le_next) { + LIST_INSERT_AFTER(node, reservation, links); + break; + } + } + } + return (0); +} + int -eisa_add_iospace(e_dev, iobase, iosize) +eisa_add_mspace(e_dev, mbase, msize, flags) struct eisa_device *e_dev; - u_long iobase; - int iosize; + u_long mbase; + u_long msize; + int flags; { - /* - * We should develop a scheme for storing the results of - * multiple calls to this function. - */ - e_dev->ioconf.iobase = iobase; - e_dev->ioconf.iosize = iosize; - return 0; + return eisa_add_resvaddr(&(e_dev->ioconf.maddrs), mbase, msize, flags); } int -eisa_reg_iospace(e_dev, iobase, iosize) +eisa_add_iospace(e_dev, iobase, iosize, flags) struct eisa_device *e_dev; u_long iobase; - int iosize; + u_long iosize; + int flags; { - /* - * We should develop a scheme for storing the results of - * multiple calls to this function. + return eisa_add_resvaddr(&(e_dev->ioconf.ioaddrs), iobase, iosize, + flags); +} + +static int +eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count) + struct eisa_device *e_dev; + struct resvlist *head; + resvaddr_t *resvaddr; + int *reg_count; +{ + if (reg_state.in_registration) { + resvaddr_t *node; + /* + * Ensure that this resvaddr is actually in the devices' + * reservation list. + */ + for(node = head->lh_first; node; + node = node->links.le_next) { + if (node == resvaddr) { + char buf[35]; + char separator = ','; + char *string = buf; + + if (*reg_count == 0) { + /* First time */ + string += sprintf(string, " at"); + } + + if (node->size == 1 + || (node->flags & RESVADDR_BITMASK)) + sprintf(string, " 0x%lx", node->addr); + else + sprintf(string, " 0x%lx-0x%lx", + node->addr, + node->addr + node->size - 1); + eisa_reg_print(e_dev, buf, + *reg_count ? &separator : NULL); + (*reg_count)++; + return (0); + } + } + return (ENOENT); + } + return EPERM; +} + +int +eisa_reg_mspace(e_dev, resvaddr) + struct eisa_device *e_dev; + resvaddr_t *resvaddr; +{ +#ifdef NOT_YET + /* + * Punt on conflict detection for the moment. + * I want to develop a generic routine to do + * this for all device types. */ + int checkthese = CC_MADDR; + if (haveseen_dev(dev, checkthese)) + return -1; +#endif + return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr, + &(reg_state.num_maddrs))); +} + +int +eisa_reg_iospace(e_dev, resvaddr) + struct eisa_device *e_dev; + resvaddr_t *resvaddr; +{ #ifdef NOT_YET /* * Punt on conflict detection for the moment. @@ -433,11 +650,8 @@ eisa_reg_iospace(e_dev, iobase, iosize) if (haveseen_dev(dev, checkthese)) return -1; #endif - e_dev->ioconf.iobase = iobase; - e_dev->ioconf.iosize = iosize; - - printf(" at 0x%lx-0x%lx", iobase, iobase + iosize - 1); - return (0); + return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr, + &(reg_state.num_ioaddrs))); } int diff --git a/sys/dev/eisa/eisaconf.h b/sys/dev/eisa/eisaconf.h index 93cecf3..181c768 100644 --- a/sys/dev/eisa/eisaconf.h +++ b/sys/dev/eisa/eisaconf.h @@ -18,13 +18,16 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: eisaconf.h,v 1.5 1995/11/20 12:41:13 phk Exp $ + * $Id: eisaconf.h,v 1.6 1995/11/21 12:52:49 bde Exp $ */ #ifndef _I386_EISA_EISACONF_H_ #define _I386_EISA_EISACONF_H_ 1 +#include <sys/queue.h> + #define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */ +#define EISA_SLOT_SIZE 0x1000 #define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ #define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@') /* Bits 21-25 */ @@ -35,15 +38,27 @@ extern struct linker_set eisadriver_set; -typedef u_long eisa_id_t; /* Should use u_int32? */ +typedef u_int32_t eisa_id_t; + +typedef struct resvaddr { + u_long addr; /* start address */ + u_long size; /* size of reserved area */ + int flags; +#define RESVADDR_NONE 0x00 +#define RESVADDR_BITMASK 0x01 /* size is a mask of reserved + * bits at addr + */ +#define RESVADDR_RELOCATABLE 0x02 + LIST_ENTRY(resvaddr) links; /* List links */ +} resvaddr_t; + +LIST_HEAD(resvlist, resvaddr); struct eisa_ioconf { - int slot; - u_long iobase; /* base i/o address */ - int iosize; /* size of i/o space */ - u_short irq; /* interrupt request */ - caddr_t maddr; /* physical i/o memory address on bus (if any)*/ - int msize; /* size of i/o memory */ + int slot; + struct resvlist ioaddrs; /* list of reserved I/O ranges */ + struct resvlist maddrs; /* list of reserved memory ranges */ + u_short irq; /* bitmask of interrupt */ }; struct kern_devconf; @@ -81,8 +96,10 @@ int eisa_add_intr __P((struct eisa_device *, int)); int eisa_reg_intr __P((struct eisa_device *, int, void (*)(void *), void *, u_int *, int)); int eisa_release_intr __P((struct eisa_device *, int, void (*)(void *))); int eisa_enable_intr __P((struct eisa_device *, int)); -int eisa_add_iospace __P((struct eisa_device *, u_long, int)); -int eisa_reg_iospace __P((struct eisa_device *, u_long, int)); +int eisa_add_iospace __P((struct eisa_device *, u_long, u_long, int)); +int eisa_reg_iospace __P((struct eisa_device *, resvaddr_t *)); +int eisa_add_mspace __P((struct eisa_device *, u_long, u_long, int)); +int eisa_reg_mspace __P((struct eisa_device *, resvaddr_t *)); int eisa_registerdev __P((struct eisa_device *, struct eisa_driver *, struct kern_devconf *)); diff --git a/sys/i386/eisa/aha1742.c b/sys/i386/eisa/aha1742.c index 3344762..f9a5f40 100644 --- a/sys/i386/eisa/aha1742.c +++ b/sys/i386/eisa/aha1742.c @@ -14,7 +14,7 @@ * * commenced: Sun Sep 27 18:14:01 PDT 1992 * - * $Id: aha1742.c,v 1.47 1996/01/07 19:20:59 gibbs Exp $ + * $Id: aha1742.c,v 1.48 1996/01/14 02:19:42 gibbs Exp $ */ #include <sys/types.h> @@ -26,12 +26,14 @@ #include <sys/kernel.h> #include <sys/sysctl.h> #include <sys/systm.h> -#include <sys/errno.h> -#include <sys/ioctl.h> +#include <sys/devconf.h> #include <sys/malloc.h> #include <sys/buf.h> #include <sys/proc.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + #include <machine/clock.h> #include <vm/vm.h> @@ -41,9 +43,6 @@ #else #define NAHB 1 #endif /*KERNEL */ -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> -#include <sys/devconf.h> /* */ @@ -72,6 +71,7 @@ typedef unsigned long int physaddr; #define EISA_DEVICE_ID_ADAPTEC_1740 0x04900000 #define AHB_EISA_IOSIZE 0x100 +#define AHB_EISA_SLOT_OFFSET 0xc00 /* AHA1740 EISA board control registers (Offset from slot base) */ #define EBCTRL 0x084 @@ -473,9 +473,10 @@ ahbprobe(void) count = 0; while ((e_dev = eisa_match_dev(e_dev, ahbmatch))) { - iobase = e_dev->ioconf.iobase; + iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE) + + AHB_EISA_SLOT_OFFSET; - eisa_add_iospace(e_dev, iobase, AHB_EISA_IOSIZE); + eisa_add_iospace(e_dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE); intdef = inb(INTDEF + iobase); switch (intdef & 0x7) { case INT9: @@ -594,18 +595,24 @@ ahb_attach(e_dev) */ int unit = e_dev->unit; struct ahb_data *ahb; + resvaddr_t *iospace; int irq = ffs(e_dev->ioconf.irq) - 1; - if(!(ahb_reset(e_dev->ioconf.iobase))) + iospace = e_dev->ioconf.ioaddrs.lh_first; + + if(!iospace) + return -1; + + if(!(ahb_reset(iospace->addr))) return -1; eisa_reg_start(e_dev); - if(eisa_reg_iospace(e_dev, e_dev->ioconf.iobase, AHB_EISA_IOSIZE)) { + if(eisa_reg_iospace(e_dev, iospace)) { eisa_reg_end(e_dev); return -1; } - if(!(ahb = ahb_alloc(unit, e_dev->ioconf.iobase, irq))) { + if(!(ahb = ahb_alloc(unit, iospace->addr, irq))) { ahb_free(ahb); eisa_reg_end(e_dev); return -1; diff --git a/sys/i386/eisa/aic7770.c b/sys/i386/eisa/aic7770.c index b7da311..2e215b0 100644 --- a/sys/i386/eisa/aic7770.c +++ b/sys/i386/eisa/aic7770.c @@ -2,7 +2,7 @@ * Product specific probe and attach routines for: * 27/284X and aic7770 motherboard SCSI controllers * - * Copyright (c) 1995 Justin T. Gibbs + * Copyright (c) 1995, 1996 Justin T. Gibbs * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -19,7 +19,7 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: aic7770.c,v 1.21 1996/01/03 06:28:00 gibbs Exp $ + * $Id: aic7770.c,v 1.22 1996/01/23 21:48:28 se Exp $ */ #include "eisa.h" @@ -44,8 +44,9 @@ #define EISA_DEVICE_ID_ADAPTEC_284xB 0x04907756 /* BIOS enabled */ #define EISA_DEVICE_ID_ADAPTEC_284x 0x04907757 /* BIOS disabled*/ -#define AHC_EISA_IOSIZE 0x100 -#define INTDEF 0x5cul /* Interrupt Definition Register */ +#define AHC_EISA_SLOT_OFFSET 0xc00 +#define AHC_EISA_IOSIZE 0x100 +#define INTDEF 0x5cul /* Interrupt Definition Register */ static int aic7770probe __P((void)); static int aic7770_attach __P((struct eisa_device *e_dev)); @@ -106,10 +107,11 @@ aic7770probe(void) count = 0; while ((e_dev = eisa_match_dev(e_dev, aic7770_match))) { - iobase = e_dev->ioconf.iobase; + iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE) + + AHC_EISA_SLOT_OFFSET; ahc_reset(iobase); - eisa_add_iospace(e_dev, iobase, AHC_EISA_IOSIZE); + eisa_add_iospace(e_dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE); intdef = inb(INTDEF + iobase); switch (intdef & 0xf) { case 9: @@ -154,10 +156,18 @@ aic7770_attach(e_dev) { ahc_type type; struct ahc_data *ahc; + resvaddr_t *iospace; u_long iobase; int unit = e_dev->unit; int irq = ffs(e_dev->ioconf.irq) - 1; + iospace = e_dev->ioconf.ioaddrs.lh_first; + + if(!iospace) + return -1; + + iobase = iospace->addr; + switch(e_dev->id) { case EISA_DEVICE_ID_ADAPTEC_AIC7770: type = AHC_AIC7770; @@ -175,11 +185,11 @@ aic7770_attach(e_dev) break; } - if(!(ahc = ahc_alloc(unit, e_dev->ioconf.iobase, type, AHC_FNONE))) + if(!(ahc = ahc_alloc(unit, iospace->addr, type, AHC_FNONE))) return -1; eisa_reg_start(e_dev); - if(eisa_reg_iospace(e_dev, e_dev->ioconf.iobase, AHC_EISA_IOSIZE)) { + if(eisa_reg_iospace(e_dev, iospace)) { ahc_free(ahc); return -1; } @@ -211,10 +221,7 @@ aic7770_attach(e_dev) /* * Now that we know we own the resources we need, do the * card initialization. - */ - iobase = ahc->baseport; - - /* + * * First, the aic7770 card specific setup. */ switch( ahc->type ) { diff --git a/sys/i386/eisa/bt74x.c b/sys/i386/eisa/bt74x.c index 5d52b07..6cc4dab 100644 --- a/sys/i386/eisa/bt74x.c +++ b/sys/i386/eisa/bt74x.c @@ -19,7 +19,7 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: bt74x.c,v 1.1 1995/12/12 08:47:11 gibbs Exp $ + * $Id: bt74x.c,v 1.2 1995/12/14 14:19:13 peter Exp $ */ #include "eisa.h" @@ -37,9 +37,11 @@ #define EISA_DEVICE_ID_BUSLOGIC_74X_B 0x0ab34201 #define EISA_DEVICE_ID_BUSLOGIC_74X_C 0x0ab34202 +#define EISA_DEVICE_ID_AMI_4801 0x05a94801 -#define BT_IOSIZE 0x04 /* Move to central header */ -#define BT_EISA_IOSIZE 0x100 +#define BT_IOSIZE 0x04 /* Move to central header */ +#define BT_EISA_IOSIZE 0x100 +#define BT_EISA_SLOT_OFFSET 0xc00 #define EISA_IOCONF 0x08C #define PORTADDR 0x07 @@ -60,6 +62,33 @@ #define EISA_IRQ_TYPE 0x08D #define LEVEL 0x40 +/* Definitions for the AMI Series 48 controler */ +#define AMI_EISA_IOSIZE 0x500 /* Two separate ranges?? */ +#define AMI_EISA_SLOT_OFFSET 0x800 +#define AMI_EISA_IOCONF 0x000 +#define AMI_DMA_CHANNEL 0x03 +#define AMI_IRQ_CHANNEL 0x1c +#define AMI_INT_15 0x14 +#define AMI_INT_14 0x10 +#define AMI_INT_12 0x0c +#define AMI_INT_11 0x00 +#define AMI_INT_10 0x08 +#define AMI_INT_9 0x04 +#define AMI_BIOS_ADDR 0xe0 + +#define AMI_EISA_IOCONF1 0x001 +#define AMI_PORTADDR 0x0e +#define AMI_PORT_334 0x08 +#define AMI_PORT_330 0x00 +#define AMI_PORT_234 0x0c +#define AMI_PORT_230 0x04 +#define AMI_PORT_134 0x0a +#define AMI_PORT_130 0x02 +#define AMI_IRQ_LEVEL 0x01 + + +#define AMI_MISC2_OPTIONS 0x49E +#define AMI_ENABLE_ISA_DMA 0x08 static int bt_eisa_probe __P((void)); static int bt_eisa_attach __P((struct eisa_device *e_dev)); @@ -98,6 +127,9 @@ bt_match(type) case EISA_DEVICE_ID_BUSLOGIC_74X_C: return ("Buslogic 74xC SCSI host adapter"); break; + case EISA_DEVICE_ID_AMI_4801: + return ("AMI Series 48 SCSI host adapter"); + break; default: break; } @@ -118,74 +150,146 @@ bt_eisa_probe(void) u_char ioconf; u_long port; int irq; - iobase = e_dev->ioconf.iobase; - -#ifdef MULTIPLE_IOSPACES - eisa_add_iospace(e_dev, iobase, BT_EISA_IOSIZE); -#endif - - ioconf = inb(iobase + EISA_IOCONF); - /* Determine "ISA" I/O port */ - switch (ioconf & PORTADDR) { - case PORT_330: - port = 0x330; - break; - case PORT_334: - port = 0x334; - break; - case PORT_230: - port = 0x230; - break; - case PORT_234: - port = 0x234; - break; - case PORT_130: - port = 0x130; - break; - case PORT_134: - port = 0x134; - break; - default: - /* Disabled */ - printf("bt: Buslogic EISA Adapter at slot %d " - "has a disabled I/O port. Cannot " - "attach.\n", e_dev->ioconf.slot); - continue; - } + iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE); + if(e_dev->id == EISA_DEVICE_ID_AMI_4801) { + u_char ioconf1; + iobase += AMI_EISA_SLOT_OFFSET; + + eisa_add_iospace(e_dev, iobase, AMI_EISA_IOSIZE, + RESVADDR_NONE); + + ioconf = inb(iobase + AMI_EISA_IOCONF); + ioconf1 = inb(iobase + AMI_EISA_IOCONF1); + /* Determine "ISA" I/O port */ + switch (ioconf1 & AMI_PORTADDR) { + case AMI_PORT_330: + port = 0x330; + break; + case AMI_PORT_334: + port = 0x334; + break; + case AMI_PORT_230: + port = 0x230; + break; + case AMI_PORT_234: + port = 0x234; + break; + case AMI_PORT_134: + port = 0x134; + break; + case AMI_PORT_130: + port = 0x130; + break; + default: + /* Disabled */ + printf("bt: AMI EISA Adapter at " + "slot %d has a disabled I/O " + "port. Cannot attach.\n", + e_dev->ioconf.slot); + continue; + } - eisa_add_iospace(e_dev, port, BT_IOSIZE); - - /* Determine our IRQ */ - switch (ioconf & IRQ_CHANNEL) { - case INT_11: - irq = 11; - break; - case INT_10: - irq = 10; - break; - case INT_15: - irq = 15; - break; - case INT_12: - irq = 12; - break; - case INT_14: - irq = 14; - break; - case INT_9: - irq = 9; - break; - default: - /* Disabled */ - printf("bt: Buslogic EISA Adapter at slot %d " - "has its IRQ disabled. Cannot " - "attach.\n", e_dev->ioconf.slot); - continue; + eisa_add_iospace(e_dev, port, BT_IOSIZE, RESVADDR_NONE); + + /* Determine our IRQ */ + switch (ioconf & AMI_IRQ_CHANNEL) { + case AMI_INT_11: + irq = 11; + break; + case AMI_INT_10: + irq = 10; + break; + case AMI_INT_15: + irq = 15; + break; + case AMI_INT_12: + irq = 12; + break; + case AMI_INT_14: + irq = 14; + break; + case AMI_INT_9: + irq = 9; + break; + default: + /* Disabled */ + printf("bt: AMI EISA Adapter at " + "slot %d has its IRQ disabled. " + "Cannot attach.\n", + e_dev->ioconf.slot); + continue; + } } + else { + iobase += BT_EISA_SLOT_OFFSET; - eisa_add_intr(e_dev, irq); + eisa_add_iospace(e_dev, iobase, BT_EISA_IOSIZE, + RESVADDR_NONE); + + ioconf = inb(iobase + EISA_IOCONF); + /* Determine "ISA" I/O port */ + switch (ioconf & PORTADDR) { + case PORT_330: + port = 0x330; + break; + case PORT_334: + port = 0x334; + break; + case PORT_230: + port = 0x230; + break; + case PORT_234: + port = 0x234; + break; + case PORT_130: + port = 0x130; + break; + case PORT_134: + port = 0x134; + break; + default: + /* Disabled */ + printf("bt: Buslogic EISA Adapter at " + "slot %d has a disabled I/O " + "port. Cannot attach.\n", + e_dev->ioconf.slot); + continue; + } + eisa_add_iospace(e_dev, port, BT_IOSIZE, RESVADDR_NONE); + /* Determine our IRQ */ + switch (ioconf & IRQ_CHANNEL) { + case INT_11: + irq = 11; + break; + case INT_10: + irq = 10; + break; + case INT_15: + irq = 15; + break; + case INT_12: + irq = 12; + break; + case INT_14: + irq = 14; + break; + case INT_9: + irq = 9; + break; + default: + /* Disabled */ + printf("bt: Buslogic EISA Adapter at " + "slot %d has its IRQ disabled. " + "Cannot attach.\n", + e_dev->ioconf.slot); + continue; + } + + } + eisa_add_intr(e_dev, irq); eisa_registerdev(e_dev, &bt_eisa_driver, &kdc_eisa_bt); + count++; } return count; @@ -198,27 +302,41 @@ bt_eisa_attach(e_dev) struct bt_data *bt; int unit = e_dev->unit; int irq = ffs(e_dev->ioconf.irq) - 1; -#ifdef MULTIPLE_IOADDR - u_char level_intr = inb((e_dev->ioconf.iobase[1]) + EISA_IRQ_TYPE) - & LEVEL; -#else - u_char level_intr = inb((e_dev->ioconf.slot * 0x1c00) + EISA_IRQ_TYPE) - & LEVEL; -#endif + resvaddr_t *ioport; + resvaddr_t *eisa_ioport; + u_char level_intr; + + /* + * The addresses are sorted in increasing order + * so we know the port to pass to the core bt + * driver comes first. + */ + ioport = e_dev->ioconf.ioaddrs.lh_first; + + if(!ioport) + return -1; + + eisa_ioport = ioport->links.le_next; + + if(!eisa_ioport) + return -1; + + if(e_dev->id == EISA_DEVICE_ID_AMI_4801) + level_intr = inb(eisa_ioport->addr + AMI_EISA_IOCONF1) + & AMI_IRQ_LEVEL; + else + level_intr = inb(eisa_ioport->addr + EISA_IRQ_TYPE) + & LEVEL; eisa_reg_start(e_dev); - if(eisa_reg_iospace(e_dev, e_dev->ioconf.iobase, BT_IOSIZE)) { + if(eisa_reg_iospace(e_dev, ioport)) return -1; - } -#ifdef MULTIPLE_IOADDR - /* Almost like this. Will depend on the definition of iobase */ - if(eisa_reg_iospace(e_dev, e_dev->ioconf.iobase[1], BT_EISA_IOSIZE)) { + if(eisa_reg_iospace(e_dev, eisa_ioport)) return -1; -#endif - if(!(bt = bt_alloc(unit, e_dev->ioconf.iobase))) { + + if(!(bt = bt_alloc(unit, ioport->addr))) return -1; - } if(eisa_reg_intr(e_dev, irq, bt_intr, (void *)bt, &bio_imask, /*shared ==*/level_intr)) { diff --git a/sys/i386/eisa/eisaconf.c b/sys/i386/eisa/eisaconf.c index 288c66b..2c583aa 100644 --- a/sys/i386/eisa/eisaconf.c +++ b/sys/i386/eisa/eisaconf.c @@ -1,7 +1,7 @@ /* * EISA bus probe and attach routines * - * Copyright (c) 1995 Justin T. Gibbs. + * Copyright (c) 1995, 1996 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -18,15 +18,15 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: eisaconf.c,v 1.11 1995/12/10 13:33:49 phk Exp $ + * $Id: eisaconf.c,v 1.12 1996/01/03 06:28:01 gibbs Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/devconf.h> #include <sys/kernel.h> #include <sys/sysctl.h> -#include <sys/conf.h> +#include <sys/conf.h> /* For kdc_isa */ #include <sys/malloc.h> -#include <sys/devconf.h> #include <i386/eisa/eisaconf.h> @@ -77,6 +77,30 @@ static struct eisa_driver mainboard_drv = { DATA_SET (eisadriver_set, mainboard_drv); /* + * Local function declarations and static variables + */ +void eisa_reg_print __P((struct eisa_device *e_dev, char *string, + char *separator)); +static int eisa_add_resvaddr __P((struct resvlist *head, u_long base, + u_long size, int flags)); +static int eisa_reg_resvaddr __P((struct eisa_device *e_dev, + struct resvlist *head, resvaddr_t *resvaddr, + int *reg_count)); + +/* + * Keep some state about what we've printed so far + * to make probe output pretty. + */ +static struct { + int in_registration;/* reg_start has been called */ + int num_interrupts; + int num_ioaddrs; + int num_maddrs; + int column; /* How much we have output so far. */ +#define MAX_COL 80 +} reg_state; + +/* ** probe for EISA devices */ void @@ -112,6 +136,7 @@ eisa_configure() } bzero(dev_node, sizeof(*dev_node)); e_dev = &(dev_node->dev); + e_dev->id = eisa_id; /* * Add an EISA ID based descriptive name incase we don't @@ -131,9 +156,13 @@ eisa_configure() EISA_MFCTR_CHAR2(e_dev->id), EISA_PRODUCT_ID(e_dev->id), EISA_REVISION_ID(e_dev->id)); + e_dev->ioconf.slot = slot; - /* Is iobase defined in any EISA specs? */ - e_dev->ioconf.iobase = eisaBase & 0xff00; + + /* Initialize our lists of reserved addresses */ + LIST_INIT(&(e_dev->ioconf.ioaddrs)); + LIST_INIT(&(e_dev->ioconf.maddrs)); + *eisa_dev_list_tail = dev_node; eisa_dev_list_tail = &dev_node->next; } @@ -199,6 +228,7 @@ eisa_configure() for (; dev_node; dev_node=dev_node->next) { e_dev = &dev_node->dev; e_drv = e_dev->driver; + if (e_drv) { /* * Determine the proper unit number for this device. @@ -213,20 +243,25 @@ eisa_configure() */ e_dev->unit = (*e_drv->unit)++; if ((*e_drv->attach)(e_dev) < 0) { - printf("%s0:%d <%s> attach failed\n", + /* Ensure registration has ended */ + reg_state.in_registration = 0; + printf("\n%s0:%d <%s> attach failed\n", mainboard_drv.name, e_dev->ioconf.slot, e_dev->full_name); continue; } + /* Ensure registration has ended */ + reg_state.in_registration = 0; e_dev->kdc->kdc_unit = e_dev->unit; } else { /* Announce unattached device */ - printf("%s0:%d <%s> unknown device\n", + printf("%s0:%d <%s=0x%x> unknown device\n", mainboard_drv.name, e_dev->ioconf.slot, - e_dev->full_name); + e_dev->full_name, + e_dev->id); } } } @@ -267,10 +302,57 @@ eisa_reg_start(e_dev) /* * Announce the device. */ - printf("%s%ld: <%s>", - e_dev->driver->name, - e_dev->unit, - e_dev->full_name); + char *string; + + reg_state.in_registration = 1; + reg_state.num_interrupts = 0; + reg_state.num_ioaddrs = 0; + reg_state.num_maddrs = 0; + reg_state.column = 0; + + string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1, + M_TEMP, M_NOWAIT); + if(!string) { + printf("eisa0: cannot malloc device description string\n"); + return; + } + sprintf(string, " <%s>", e_dev->full_name); + eisa_reg_print(e_dev, string, /*separator=*/NULL); + free(string, M_TEMP); +} + +/* + * Output registration information mindfull of screen wrap. + * Output an optional character separator before the string + * if the line does not wrap. + */ +void +eisa_reg_print(e_dev, string, separator) + struct eisa_device *e_dev; + char *string; + char *separator; +{ + int len = strlen(string); + + if( separator ) + len++; + + if(reg_state.column + len > MAX_COL) { + printf("\n"); + reg_state.column = 0; + } + else if( separator ) { + printf("%c", *separator); + reg_state.column++; + } + + if(reg_state.column == 0) + reg_state.column += printf("%s%ld:%s", + e_dev->driver->name, + e_dev->unit, + string); + else + reg_state.column += printf("%s", string); } /* Interrupt and I/O space registration facitlities */ @@ -278,19 +360,30 @@ void eisa_reg_end(e_dev) struct eisa_device *e_dev; { - /* - * The device should have called eisa_registerdev() - * during its probe. So hopefully we can use the kdc - * to weed out ISA/VL devices that use EISA id registers. - */ - if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) { - printf(" on isa\n"); - } - else { - printf(" on %s0 slot %d\n", - mainboard_drv.name, - e_dev->ioconf.slot); + if( reg_state.in_registration ) + { + /* + * The device should have called eisa_registerdev() + * during its probe. So hopefully we can use the kdc + * to weed out ISA/VL devices that use EISA id registers. + */ + char string[25]; + + if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) { + sprintf(string, " on isa"); + } + else { + sprintf(string, " on %s0 slot %d", + mainboard_drv.name, + e_dev->ioconf.slot); + } + eisa_reg_print(e_dev, string, NULL); + printf("\n"); + reg_state.in_registration = 0; } + else + printf("eisa_reg_end called outside of a " + "registration session\n"); } int @@ -313,6 +406,8 @@ eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) { int result; int s; + char string[25]; + char separator = ','; #if NOT_YET /* @@ -324,28 +419,35 @@ eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) if (haveseen_dev(dev, checkthese)) return 1; #endif - s = splhigh(); - /* - * This should really go to a routine that can optionally - * handle shared interrupts. - */ - result = register_intr(irq, /* isa irq */ - 0, /* deviced?? */ - 0, /* flags? */ - (inthand2_t*) func, /* handler */ - maskptr, /* mask pointer */ - (int)arg); /* handler arg */ - - if (result) { - printf ("eisa_reg_int: result=%d\n", result); + if (reg_state.in_registration) { + s = splhigh(); + /* + * This should really go to a routine that can optionally + * handle shared interrupts. + */ + result = register_intr(irq, /* isa irq */ + 0, /* deviced?? */ + 0, /* flags? */ + (inthand2_t*) func, /* handler */ + maskptr, /* mask pointer */ + (int)arg); /* handler arg */ + + if (result) { + printf ("\neisa_reg_int: result=%d\n", result); + splx(s); + return (result); + }; + update_intr_masks(); splx(s); - return (result); - }; - update_intr_masks(); - splx(s); + } + else + return EPERM; e_dev->ioconf.irq |= 1ul << irq; - printf(" irq %d", irq); + sprintf(string, " irq %d", irq); + eisa_reg_print(e_dev, string, reg_state.num_interrupts ? + &separator : NULL); + reg_state.num_interrupts++; return (0); } @@ -398,31 +500,146 @@ eisa_enable_intr(e_dev, irq) return 0; } +static int +eisa_add_resvaddr(head, base, size, flags) + struct resvlist *head; + u_long base; + u_long size; + int flags; +{ + resvaddr_t *reservation; + + reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t), + M_DEVBUF, M_NOWAIT); + if(!reservation) + return (ENOMEM); + + reservation->addr = base; + reservation->size = size; + reservation->flags = flags; + + if (!head->lh_first) { + LIST_INSERT_HEAD(head, reservation, links); + } + else { + resvaddr_t *node; + for(node = head->lh_first; node; node = node->links.le_next) { + if (node->addr > reservation->addr) { + /* + * List is sorted in increasing + * address order. + */ + LIST_INSERT_BEFORE(node, reservation, links); + break; + } + + if (node->addr == reservation->addr) { + /* + * If the entry we want to add + * matches any already in here, + * fail. + */ + free(reservation, M_DEVBUF); + return (EEXIST); + } + + if (!node->links.le_next) { + LIST_INSERT_AFTER(node, reservation, links); + break; + } + } + } + return (0); +} + int -eisa_add_iospace(e_dev, iobase, iosize) +eisa_add_mspace(e_dev, mbase, msize, flags) struct eisa_device *e_dev; - u_long iobase; - int iosize; + u_long mbase; + u_long msize; + int flags; { - /* - * We should develop a scheme for storing the results of - * multiple calls to this function. - */ - e_dev->ioconf.iobase = iobase; - e_dev->ioconf.iosize = iosize; - return 0; + return eisa_add_resvaddr(&(e_dev->ioconf.maddrs), mbase, msize, flags); } int -eisa_reg_iospace(e_dev, iobase, iosize) +eisa_add_iospace(e_dev, iobase, iosize, flags) struct eisa_device *e_dev; u_long iobase; - int iosize; + u_long iosize; + int flags; { - /* - * We should develop a scheme for storing the results of - * multiple calls to this function. + return eisa_add_resvaddr(&(e_dev->ioconf.ioaddrs), iobase, iosize, + flags); +} + +static int +eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count) + struct eisa_device *e_dev; + struct resvlist *head; + resvaddr_t *resvaddr; + int *reg_count; +{ + if (reg_state.in_registration) { + resvaddr_t *node; + /* + * Ensure that this resvaddr is actually in the devices' + * reservation list. + */ + for(node = head->lh_first; node; + node = node->links.le_next) { + if (node == resvaddr) { + char buf[35]; + char separator = ','; + char *string = buf; + + if (*reg_count == 0) { + /* First time */ + string += sprintf(string, " at"); + } + + if (node->size == 1 + || (node->flags & RESVADDR_BITMASK)) + sprintf(string, " 0x%lx", node->addr); + else + sprintf(string, " 0x%lx-0x%lx", + node->addr, + node->addr + node->size - 1); + eisa_reg_print(e_dev, buf, + *reg_count ? &separator : NULL); + (*reg_count)++; + return (0); + } + } + return (ENOENT); + } + return EPERM; +} + +int +eisa_reg_mspace(e_dev, resvaddr) + struct eisa_device *e_dev; + resvaddr_t *resvaddr; +{ +#ifdef NOT_YET + /* + * Punt on conflict detection for the moment. + * I want to develop a generic routine to do + * this for all device types. */ + int checkthese = CC_MADDR; + if (haveseen_dev(dev, checkthese)) + return -1; +#endif + return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr, + &(reg_state.num_maddrs))); +} + +int +eisa_reg_iospace(e_dev, resvaddr) + struct eisa_device *e_dev; + resvaddr_t *resvaddr; +{ #ifdef NOT_YET /* * Punt on conflict detection for the moment. @@ -433,11 +650,8 @@ eisa_reg_iospace(e_dev, iobase, iosize) if (haveseen_dev(dev, checkthese)) return -1; #endif - e_dev->ioconf.iobase = iobase; - e_dev->ioconf.iosize = iosize; - - printf(" at 0x%lx-0x%lx", iobase, iobase + iosize - 1); - return (0); + return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr, + &(reg_state.num_ioaddrs))); } int diff --git a/sys/i386/eisa/eisaconf.h b/sys/i386/eisa/eisaconf.h index 93cecf3..181c768 100644 --- a/sys/i386/eisa/eisaconf.h +++ b/sys/i386/eisa/eisaconf.h @@ -18,13 +18,16 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: eisaconf.h,v 1.5 1995/11/20 12:41:13 phk Exp $ + * $Id: eisaconf.h,v 1.6 1995/11/21 12:52:49 bde Exp $ */ #ifndef _I386_EISA_EISACONF_H_ #define _I386_EISA_EISACONF_H_ 1 +#include <sys/queue.h> + #define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */ +#define EISA_SLOT_SIZE 0x1000 #define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ #define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@') /* Bits 21-25 */ @@ -35,15 +38,27 @@ extern struct linker_set eisadriver_set; -typedef u_long eisa_id_t; /* Should use u_int32? */ +typedef u_int32_t eisa_id_t; + +typedef struct resvaddr { + u_long addr; /* start address */ + u_long size; /* size of reserved area */ + int flags; +#define RESVADDR_NONE 0x00 +#define RESVADDR_BITMASK 0x01 /* size is a mask of reserved + * bits at addr + */ +#define RESVADDR_RELOCATABLE 0x02 + LIST_ENTRY(resvaddr) links; /* List links */ +} resvaddr_t; + +LIST_HEAD(resvlist, resvaddr); struct eisa_ioconf { - int slot; - u_long iobase; /* base i/o address */ - int iosize; /* size of i/o space */ - u_short irq; /* interrupt request */ - caddr_t maddr; /* physical i/o memory address on bus (if any)*/ - int msize; /* size of i/o memory */ + int slot; + struct resvlist ioaddrs; /* list of reserved I/O ranges */ + struct resvlist maddrs; /* list of reserved memory ranges */ + u_short irq; /* bitmask of interrupt */ }; struct kern_devconf; @@ -81,8 +96,10 @@ int eisa_add_intr __P((struct eisa_device *, int)); int eisa_reg_intr __P((struct eisa_device *, int, void (*)(void *), void *, u_int *, int)); int eisa_release_intr __P((struct eisa_device *, int, void (*)(void *))); int eisa_enable_intr __P((struct eisa_device *, int)); -int eisa_add_iospace __P((struct eisa_device *, u_long, int)); -int eisa_reg_iospace __P((struct eisa_device *, u_long, int)); +int eisa_add_iospace __P((struct eisa_device *, u_long, u_long, int)); +int eisa_reg_iospace __P((struct eisa_device *, resvaddr_t *)); +int eisa_add_mspace __P((struct eisa_device *, u_long, u_long, int)); +int eisa_reg_mspace __P((struct eisa_device *, resvaddr_t *)); int eisa_registerdev __P((struct eisa_device *, struct eisa_driver *, struct kern_devconf *)); |