diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-10-26 18:00:07 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-10-26 18:00:07 +0000 |
commit | e43558c65c4e1ada177750e34935adadeb7a8adb (patch) | |
tree | a180b0730c2681e08af26162c0f8b3b9506024c6 /sys/arch/sgi/localbus | |
parent | 4c271da1cc0acb1a0ec7015f8388d67085299d0d (diff) |
Better crime/mace interrupt handling; interrupt information is no longer
specified in the kernel configuration file, but is provided by macebus(4)
as part of the child device attachment args, and provide both crime and
mace interrupt bitmasks; this allows us to only really enable interrupt
sources we care about, and to avoid invoking interrupt handler we don't need
to for the few mace interrupts multiplexed at the crime level.
Diffstat (limited to 'sys/arch/sgi/localbus')
-rw-r--r-- | sys/arch/sgi/localbus/com_lbus.c | 28 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/macebus.c | 199 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/macebus.h | 22 |
3 files changed, 151 insertions, 98 deletions
diff --git a/sys/arch/sgi/localbus/com_lbus.c b/sys/arch/sgi/localbus/com_lbus.c index 20d1ef6050c..835e05bcba0 100644 --- a/sys/arch/sgi/localbus/com_lbus.c +++ b/sys/arch/sgi/localbus/com_lbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: com_lbus.c,v 1.10 2009/10/16 14:38:13 miod Exp $ */ +/* $OpenBSD: com_lbus.c,v 1.11 2009/10/26 18:00:06 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -41,7 +41,7 @@ #include <mips64/archtype.h> -#include <sgi/localbus/macebus.h> +#include <sgi/localbus/macebusvar.h> int com_macebus_probe(struct device *, void *, void *); void com_macebus_attach(struct device *, struct device *, void *); @@ -53,19 +53,19 @@ struct cfattach com_macebus_ca = { int com_macebus_probe(struct device *parent, void *match, void *aux) { - struct confargs *ca = aux; + struct macebus_attach_args *maa = aux; bus_space_handle_t ioh; int rv; /* If it's in use as the console, then it's there. */ - if (ca->ca_baseaddr == comconsaddr && !comconsattached) + if (maa->maa_baseaddr == comconsaddr && !comconsattached) return (1); - if (bus_space_map(ca->ca_iot, ca->ca_baseaddr, COM_NPORTS, 0, &ioh)) + if (bus_space_map(maa->maa_iot, maa->maa_baseaddr, COM_NPORTS, 0, &ioh)) return (0); - rv = comprobe1(ca->ca_iot, ioh); - bus_space_unmap(ca->ca_iot, ioh, COM_NPORTS); + rv = comprobe1(maa->maa_iot, ioh); + bus_space_unmap(maa->maa_iot, ioh, COM_NPORTS); return rv; } @@ -74,22 +74,22 @@ void com_macebus_attach(struct device *parent, struct device *self, void *aux) { struct com_softc *sc = (void *)self; - struct confargs *ca = aux; + struct macebus_attach_args *maa = aux; - sc->sc_iot = ca->ca_iot; + sc->sc_iot = maa->maa_iot; sc->sc_hwflags = 0; sc->sc_swflags = 0; - sc->sc_iobase = ca->ca_baseaddr; + sc->sc_iobase = maa->maa_baseaddr; sc->sc_frequency = 1843200; /* If it's in use as the console, then it's there. */ - if (ca->ca_baseaddr == comconsaddr && !comconsattached) { + if (maa->maa_baseaddr == comconsaddr && !comconsattached) { if (comcnattach(sc->sc_iot, sc->sc_iobase, comconsrate, sc->sc_frequency, (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8)) panic("failed to setup serial console!"); sc->sc_ioh = comconsioh; } else { - if (bus_space_map(sc->sc_iot, ca->ca_baseaddr, COM_NPORTS, 0, + if (bus_space_map(sc->sc_iot, maa->maa_baseaddr, COM_NPORTS, 0, &sc->sc_ioh)) { printf(": can't map i/o space\n"); return; @@ -98,6 +98,6 @@ com_macebus_attach(struct device *parent, struct device *self, void *aux) com_attach_subr(sc); - macebus_intr_establish(NULL, ca->ca_intr, IST_EDGE, IPL_TTY, comintr, - (void *)sc, sc->sc_dev.dv_xname); + macebus_intr_establish(maa->maa_intr, maa->maa_mace_intr, + IST_EDGE, IPL_TTY, comintr, (void *)sc, sc->sc_dev.dv_xname); } diff --git a/sys/arch/sgi/localbus/macebus.c b/sys/arch/sgi/localbus/macebus.c index 98e91dbddcd..1ffba232f99 100644 --- a/sys/arch/sgi/localbus/macebus.c +++ b/sys/arch/sgi/localbus/macebus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macebus.c,v 1.51 2009/10/22 22:08:54 miod Exp $ */ +/* $OpenBSD: macebus.c,v 1.52 2009/10/26 18:00:06 miod Exp $ */ /* * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se) @@ -47,17 +47,19 @@ #include <sgi/localbus/crimebus.h> #include <sgi/localbus/macebus.h> +#include <sgi/localbus/macebusvar.h> int macebusmatch(struct device *, void *, void *); void macebusattach(struct device *, struct device *, void *); int macebusprint(void *, const char *); -int macebussearch(struct device *, void *, void *); +int macebussubmatch(struct device *, void *, void *); void macebus_intr_makemasks(void); void macebus_splx(int); uint32_t macebus_iointr(uint32_t, struct trap_frame *); uint32_t macebus_aux(uint32_t, struct trap_frame *); -void mace_setintrmask(int); +int macebus_iointr_skip(struct intrhand *); +void crime_setintrmask(int); u_int8_t mace_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); u_int16_t mace_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t); @@ -159,17 +161,44 @@ struct machine_bus_dma_tag mace_bus_dma_tag = { /* * CRIME/MACE interrupt handling declarations: 32 CRIME sources, 32 MACE - * sources (unmanaged); 1 level. + * sources (multiplexed by CRIME); 1 level. * We define another level for periodic tasks as well. */ -struct intrhand *mace_intrhand[CRIME_NINTS]; +struct crime_intrhand { + struct intrhand ih; + uint32_t mace_irqmask; +}; +struct crime_intrhand *crime_intrhand[CRIME_NINTS]; #define INTPRI_MACEIO (INTPRI_CLOCK + 1) #define INTPRI_MACEAUX (INTPRI_MACEIO + 1) -uint64_t mace_intem; -uint64_t mace_imask[NIPLS]; +uint64_t crime_intem, mace_intem; +uint64_t crime_imask[NIPLS]; + +/* + * List of macebus child devices. + */ + +#define MACEBUSDEV(name, addr, i, i2) \ + { name, &macebus_tag, &macebus_tag, &mace_bus_dma_tag, addr, i, i2 } +struct macebus_attach_args macebus_children[] = { + MACEBUSDEV("com", MACE_ISA_SER1_OFFS, 4, MACE_ISA_INT_SERIAL_1), + MACEBUSDEV("com", MACE_ISA_SER2_OFFS, 4, MACE_ISA_INT_SERIAL_2), + MACEBUSDEV("dsrtc", MACE_ISA_RTC_OFFS, -1, 0), +#if 0 + MACEBUSDEV("lpt", MACE_ISA_EPP_OFFS, 4, MACE_ISA_INT_PARALLEL), +#endif + MACEBUSDEV("macepcibr", MACE_PCI_OFFS, 7, 0), + MACEBUSDEV("mavb", MACE_IO_AUDIO_OFFS, 6, MACE_ISA_INT_AUDIO), + MACEBUSDEV("mec", MACE_ETHERNET_OFFS, 3, 0), + MACEBUSDEV("mkbc", MACE_IO_KBC_OFFS, 5, + MACE_ISA_INT_KBD | MACE_ISA_INT_KBD_POLL | + MACE_ISA_INT_MOUSE | MACE_ISA_INT_MOUSE_POLL), + MACEBUSDEV("power", 0, 5, MACE_ISA_INT_RTC) +}; +#undef MACEBUSDEV /* * Match bus only to targets which have this bus. @@ -185,49 +214,39 @@ macebusmatch(struct device *parent, void *match, void *aux) int macebusprint(void *aux, const char *macebus) { - struct confargs *ca = aux; + struct macebus_attach_args *maa = aux; if (macebus != NULL) - printf("%s at %s", ca->ca_name, macebus); + printf("%s at %s", maa->maa_name, macebus); - if (ca->ca_baseaddr != 0) - printf(" base 0x%08x", ca->ca_baseaddr); - if (ca->ca_intr != 0) - printf(" irq %d", ca->ca_intr); + if (maa->maa_baseaddr != 0) + printf(" base 0x%08x", maa->maa_baseaddr); + if (maa->maa_intr >= 0) + printf(" irq %d", maa->maa_intr); return (UNCONF); } int -macebussearch(struct device *parent, void *child, void *args) +macebussubmatch(struct device *parent, void *vcf, void *args) { - struct cfdata *cf = child; - struct confargs ca; - - ca.ca_name = cf->cf_driver->cd_name; - ca.ca_iot = &macebus_tag; - ca.ca_memt = &macebus_tag; - ca.ca_dmat = &mace_bus_dma_tag; - if (cf->cf_loc[0] == -1) - ca.ca_baseaddr = 0; - else - ca.ca_baseaddr = cf->cf_loc[0]; - if (cf->cf_loc[1] == -1) - ca.ca_intr = 0; - else - ca.ca_intr = cf->cf_loc[1]; - - if ((*cf->cf_attach->ca_match)(parent, cf, &ca) == 0) - return (0); - - config_attach(parent, cf, &ca, macebusprint); - return (1); + struct cfdata *cf = vcf; + struct macebus_attach_args *maa = args; + + if (strcmp(cf->cf_driver->cd_name, maa->maa_name) != 0) + return 0; + + if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != (int)maa->maa_baseaddr) + return 0; + + return (*cf->cf_attach->ca_match)(parent, cf, maa); } void macebusattach(struct device *parent, struct device *self, void *aux) { u_int32_t creg; + uint i; /* * Map and setup CRIME control registers. @@ -257,9 +276,7 @@ macebusattach(struct device *parent, struct device *self, void *aux) return; } - /* Turn on all MACE interrupts except for MACE compare/timer. */ - bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK, - 0xffffffff & ~MACE_ISA_INT_TIMER); + bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK, 0); bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_STAT, 0); /* @@ -272,7 +289,12 @@ macebusattach(struct device *parent, struct device *self, void *aux) /* Set up a handler called when clock interrupts go off. */ set_intr(INTPRI_MACEAUX, CR_INT_5, macebus_aux); - config_search(macebussearch, self, aux); + /* + * Attach subdevices. + */ + for (i = 0; i < nitems(macebus_children); i++) + config_found_sm(self, macebus_children + i, + macebusprint, macebussubmatch); } /* @@ -455,29 +477,28 @@ macebus_device_to_pa(bus_addr_t addr) * XXX in kernel configuration files... */ void * -macebus_intr_establish(void *icp, u_long irq, int type, int level, +macebus_intr_establish(int irq, uint32_t mace_irqmask, int type, int level, int (*ih_fun)(void *), void *ih_arg, const char *ih_what) { - struct intrhand **p, *q, *ih; + struct crime_intrhand **p, *q, *ih; int s; #ifdef DIAGNOSTIC - if (irq > CRIME_NINTS || irq < 1) + if (irq >= CRIME_NINTS || irq < 0) panic("intr_establish: illegal irq %d", irq); #endif - irq -= 1; /* Adjust for 1 being first (0 is no int) */ - ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT); if (ih == NULL) return NULL; - ih->ih_next = NULL; - ih->ih_fun = ih_fun; - ih->ih_arg = ih_arg; - ih->ih_level = level; - ih->ih_irq = irq + 1; - evcount_attach(&ih->ih_count, ih_what, (void *)&ih->ih_irq, + ih->ih.ih_next = NULL; + ih->ih.ih_fun = ih_fun; + ih->ih.ih_arg = ih_arg; + ih->ih.ih_level = level; + ih->ih.ih_irq = irq; + ih->mace_irqmask = mace_irqmask; + evcount_attach(&ih->ih.ih_count, ih_what, (void *)&ih->ih.ih_irq, &evcount_intr); s = splhigh(); @@ -487,13 +508,21 @@ macebus_intr_establish(void *icp, u_long irq, int type, int level, * This is O(N^2), but we want to preserve the order, and N is * generally small. */ - for (p = &mace_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) + for (p = &crime_intrhand[irq]; (q = *p) != NULL; + p = (struct crime_intrhand **)&q->ih.ih_next) ; *p = ih; - mace_intem |= 1UL << irq; + crime_intem |= 1UL << irq; macebus_intr_makemasks(); + /* enable further MACE sources if necessary */ + if (mace_irqmask != 0) { + mace_intem |= mace_irqmask; + bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK, + mace_intem); + } + splx(s); /* causes hw mask update */ return (ih); @@ -519,7 +548,8 @@ macebus_intr_makemasks(void) /* First, figure out which levels each IRQ uses. */ for (irq = 0; irq < CRIME_NINTS; irq++) { uint levels = 0; - for (q = mace_intrhand[irq]; q; q = q->ih_next) + for (q = (struct intrhand *)crime_intrhand[irq]; + q != NULL; q = q->ih_next) levels |= 1 << q->ih_level; intrlevel[irq] = levels; } @@ -530,7 +560,7 @@ macebus_intr_makemasks(void) for (irq = 0; irq < CRIME_NINTS; irq++) if (intrlevel[irq] & (1 << level)) irqs |= 1UL << irq; - mace_imask[level] = irqs; + crime_imask[level] = irqs; } /* @@ -540,16 +570,16 @@ macebus_intr_makemasks(void) * Enforce a hierarchy that gives slow devices a better chance at not * dropping data. */ - mace_imask[IPL_NET] |= mace_imask[IPL_BIO]; - mace_imask[IPL_TTY] |= mace_imask[IPL_NET]; - mace_imask[IPL_VM] |= mace_imask[IPL_TTY]; - mace_imask[IPL_CLOCK] |= mace_imask[IPL_VM]; + crime_imask[IPL_NET] |= crime_imask[IPL_BIO]; + crime_imask[IPL_TTY] |= crime_imask[IPL_NET]; + crime_imask[IPL_VM] |= crime_imask[IPL_TTY]; + crime_imask[IPL_CLOCK] |= crime_imask[IPL_VM]; /* * These are pseudo-levels. */ - mace_imask[IPL_NONE] = 0; - mace_imask[IPL_HIGH] = -1UL; + crime_imask[IPL_NONE] = 0; + crime_imask[IPL_HIGH] = -1UL; } void @@ -561,7 +591,7 @@ macebus_splx(int newipl) __asm__ (".set noreorder\n"); ci->ci_ipl = newipl; __asm__ ("sync\n\t.set reorder\n"); - mace_setintrmask(newipl); + crime_setintrmask(newipl); /* If we still have softints pending trigger processing. */ if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT) setsoftintr0(); @@ -581,19 +611,50 @@ do { \ } while (0) #define INTR_MASKPENDING \ bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_MASK, imr & ~isr) -#define INTR_IMASK(ipl) mace_imask[ipl] -#define INTR_HANDLER(bit) mace_intrhand[bit] +#define INTR_IMASK(ipl) crime_imask[ipl] +#define INTR_HANDLER(bit) (struct intrhand *)crime_intrhand[bit] #define INTR_SPURIOUS(bit) \ do { \ - /* XXX +1 because of -1 in intr_establish() */ \ - if (bit != 4) \ - printf("spurious crime interrupt %d\n", bit + 1); \ + uint64_t mace_isr, mace_imr; \ + mace_isr = bus_space_read_8(&macebus_tag, mace_h, MACE_ISA_INT_STAT); \ + mace_imr = bus_space_read_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK); \ + /* serial console processing may clear interrupt condition \ + before it fires */ \ + if (bit != 4 || (mace_isr & mace_imr) != 0) \ + printf("spurious crime interrupt %d mace isr %p imr %p\n", \ + bit, mace_isr, mace_imr); \ } while (0) #define INTR_MASKRESTORE \ bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_MASK, imr) +#define INTR_HANDLER_SKIP(ih) macebus_iointr_skip((void *)ih) + #include <sgi/sgi/intr_template.c> +int +macebus_iointr_skip(struct intrhand *ih) +{ + struct crime_intrhand *mih = (struct crime_intrhand *)ih; + uint64_t mace_isr, mace_imr; + + /* do not skip pure CRIME interrupts */ + if (mih->mace_irqmask == 0) + return 0; + + /* + * Several CRIME interrupts (such as superio and miscellaneous) are + * shared by multiple devices, so narrow the selection with the + * MACE interrupt status. + */ + + mace_isr = bus_space_read_8(&macebus_tag, mace_h, MACE_ISA_INT_STAT); + mace_imr = bus_space_read_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK); + if ((mace_isr & mace_imr & mih->mace_irqmask) != 0) + return 0; + + return 1; +} + /* * Macebus auxilary functions run each clock interrupt. */ @@ -612,7 +673,7 @@ macebus_aux(uint32_t hwpend, struct trap_frame *cf) mask &= ~MACE_ISA_MISC_RLED_OFF; } else if (curproc == NULL || curproc == curcpu()->ci_schedstate.spc_idleproc) { - mask &= ~MACE_ISA_MISC_GLED_OFF; + mask &= ~MACE_ISA_MISC_GLED_OFF; } else { mask &= ~(MACE_ISA_MISC_RLED_OFF | MACE_ISA_MISC_GLED_OFF); } @@ -622,8 +683,8 @@ macebus_aux(uint32_t hwpend, struct trap_frame *cf) } void -mace_setintrmask(int level) +crime_setintrmask(int level) { *(volatile uint64_t *)(PHYS_TO_XKPHYS(CRIMEBUS_BASE, CCA_NC) + - CRIME_INT_MASK) = mace_intem & ~mace_imask[level]; + CRIME_INT_MASK) = crime_intem & ~crime_imask[level]; } diff --git a/sys/arch/sgi/localbus/macebus.h b/sys/arch/sgi/localbus/macebus.h index 63ca7f0ffd0..78c35bfe4c2 100644 --- a/sys/arch/sgi/localbus/macebus.h +++ b/sys/arch/sgi/localbus/macebus.h @@ -1,4 +1,4 @@ -/* $OpenBSD: macebus.h,v 1.14 2009/10/22 20:51:08 miod Exp $ */ +/* $OpenBSD: macebus.h,v 1.15 2009/10/26 18:00:06 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.com). @@ -26,11 +26,6 @@ * */ -#ifndef _MACEBUS_H_ -#define _MACEBUS_H_ 1 - -#include <machine/bus.h> - /* * Physical address of MACEBUS. */ @@ -43,6 +38,7 @@ #define MACE_VIN1_OFFS 0x00100000 #define MACE_VIN2_OFFS 0x00180000 #define MACE_VOUT_OFFS 0x00200000 +#define MACE_ETHERNET_OFFS 0x00280000 #define MACE_IO_OFFS 0x00300000 #define MACE_IO_SIZE 0x00050000 #define MACE_ISAX_OFFS 0x00380000 @@ -79,6 +75,11 @@ #define PERR_DATA_PARITY_ADDR_VALID 0x00020000 #define PERR_RETRY_ADDR_VALID 0x00010000 +/* + * MACE IO definitions. + */ +#define MACE_IO_AUDIO_OFFS (MACE_IO_OFFS+0x00000000) +#define MACE_IO_KBC_OFFS (MACE_IO_OFFS+0x00020000) /* * MACE ISA definitions. @@ -118,12 +119,3 @@ #define MACE_ISA_SER2_OFFS (MACE_ISAX_OFFS+0x00018000) #define MACE_ISA_RTC_OFFS (MACE_ISAX_OFFS+0x00020000) #define MACE_ISA_GAME_OFFS (MACE_ISAX_OFFS+0x00030000) - -extern bus_space_t macebus_tag; -extern struct machine_bus_dma_tag mace_bus_dma_tag; - -void *macebus_intr_establish(void *, u_long, int, int, int (*)(void *), - void *, const char *); -void macebus_intr_disestablish(void *); - -#endif /* _MACEBUS_H_ */ |