diff options
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 * |