diff options
author | Henric Jungheim <henric@cvs.openbsd.org> | 2003-05-16 06:59:13 +0000 |
---|---|---|
committer | Henric Jungheim <henric@cvs.openbsd.org> | 2003-05-16 06:59:13 +0000 |
commit | cf599f158458425ae996473b91afe4d3ee83f2be (patch) | |
tree | 19aaec28d5c71cd038595bbeb031d75cfd9ffe47 /sys/arch/sparc64/dev/psycho.c | |
parent | e150ffcc509a8e9b5e856394113e2afc39791dd5 (diff) |
The sparc64 proms do not map all interrupt vectors. Instead of
trying to use the interrupt pin (or is it that the PCI
function?) as the interrupt vector, this computes the vector
from the PCI bus, slot, and pin. This will only change mappings
on psycho-based machines (*not* sabre, i.e., IIi/e) and only for
those vectors reported as nonsense INRs (INO 0-3).
This should fix the mapping of non-bridge expansion cards on U60
and E450, and other psycho boxen. U30 seems to do its own
thing.
Diffstat (limited to 'sys/arch/sparc64/dev/psycho.c')
-rw-r--r-- | sys/arch/sparc64/dev/psycho.c | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/sys/arch/sparc64/dev/psycho.c b/sys/arch/sparc64/dev/psycho.c index 41fc0647006..b879cba10cf 100644 --- a/sys/arch/sparc64/dev/psycho.c +++ b/sys/arch/sparc64/dev/psycho.c @@ -1,4 +1,4 @@ -/* $OpenBSD: psycho.c,v 1.30 2003/03/25 22:10:19 jason Exp $ */ +/* $OpenBSD: psycho.c,v 1.31 2003/05/16 06:59:12 henric Exp $ */ /* $NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp $ */ /* @@ -44,6 +44,8 @@ #include <sys/time.h> #include <sys/reboot.h> +#include <uvm/uvm_extern.h> + #define _SPARC_BUS_DMA_PRIVATE #include <machine/bus.h> #include <machine/autoconf.h> @@ -119,6 +121,9 @@ int psycho_dmamem_map(bus_dma_tag_t, bus_dma_tag_t, bus_dma_segment_t *, int, si void psycho_dmamem_unmap(bus_dma_tag_t, bus_dma_tag_t, caddr_t, size_t); void psycho_map_psycho(struct psycho_softc *, int, bus_addr_t, bus_size_t, bus_addr_t, bus_size_t); +int psycho_intr_map(struct pci_attach_args *, pci_intr_handle_t *); +void psycho_identify_pbm(struct psycho_softc *sc, struct psycho_pbm *pp, + struct pcibus_attach_args *pa); /* base pci_chipset */ extern struct sparc_pci_chipset _sparc_pci_chipset; @@ -306,7 +311,7 @@ psycho_attach(struct device *parent, struct device *self, void *aux) } csr = psycho_psychoreg_read(sc, psy_csr); - sc->sc_ign = 0x7c0; /* APB IGN is always 0x7c */ + sc->sc_ign = INTMAP_IGN; /* APB IGN is always 0x1f << 6 = 0x7c */ if (sc->sc_mode == PSYCHO_MODE_PSYCHO) sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6; @@ -534,11 +539,39 @@ psycho_attach(struct device *parent, struct device *self, void *aux) pba.pba_memt = sc->sc_psycho_this->pp_memt; pba.pba_pc->bustag = sc->sc_configtag; pba.pba_pc->bushandle = sc->sc_configaddr; + pba.pba_pc->intr_map = psycho_intr_map; + + if (sc->sc_mode == PSYCHO_MODE_PSYCHO) + psycho_identify_pbm(sc, pp, &pba); + else + pp->pp_id = PSYCHO_PBM_UNKNOWN; config_found(self, &pba, psycho_print); } void +psycho_identify_pbm(struct psycho_softc *sc, struct psycho_pbm *pp, + struct pcibus_attach_args *pa) +{ + vaddr_t pci_va = (vaddr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_pcictl); + paddr_t pci_pa; + + if (pmap_extract(pmap_kernel(), pci_va, &pci_pa) == 0) + pp->pp_id = PSYCHO_PBM_UNKNOWN; + else switch(pci_pa & 0xffff) { + case 0x2000: + pp->pp_id = PSYCHO_PBM_A; + break; + case 0x4000: + pp->pp_id = PSYCHO_PBM_B; + break; + default: + pp->pp_id = PSYCHO_PBM_UNKNOWN; + break; + } +} + +void psycho_map_psycho(struct psycho_softc* sc, int do_map, bus_addr_t reg_addr, bus_size_t reg_size, bus_addr_t pci_addr, bus_size_t pci_size) { @@ -986,6 +1019,41 @@ psycho_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr, } /* + * Bus-specific interrupt mapping + */ +int +psycho_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + struct psycho_pbm *pp = pa->pa_pc->cookie; + struct psycho_softc *sc = pp->pp_sc; + u_int ino; + + ino = *ihp; + + if ((ino & ~INTMAP_PCIINT) == 0) { + if (ino == 0 || ino > 4) { + u_int32_t intreg; + + intreg = pci_conf_read(pa->pa_pc, pa->pa_tag, + PCI_INTERRUPT_REG); + + ino = PCI_INTERRUPT_PIN(intreg) - 1; + } else + ino -= 1; + + ino &= INTMAP_PCIINT; + + ino |= sc->sc_ign; + ino |= ((pp->pp_id == PSYCHO_PBM_B) ? INTMAP_PCIBUS : 0); + ino |= ((pa->pa_device - 1) << 2) & INTMAP_PCISLOT; + + *ihp = ino; + } + + return (0); +} + +/* * install an interrupt handler for a PCI device */ void * |