summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64/dev/psycho.c
diff options
context:
space:
mode:
authorHenric Jungheim <henric@cvs.openbsd.org>2003-05-16 06:59:13 +0000
committerHenric Jungheim <henric@cvs.openbsd.org>2003-05-16 06:59:13 +0000
commitcf599f158458425ae996473b91afe4d3ee83f2be (patch)
tree19aaec28d5c71cd038595bbeb031d75cfd9ffe47 /sys/arch/sparc64/dev/psycho.c
parente150ffcc509a8e9b5e856394113e2afc39791dd5 (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.c72
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 *