diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/macppc/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/macppc/conf/files.macppc | 9 | ||||
-rw-r--r-- | sys/arch/macppc/dev/openpic.c | 178 | ||||
-rw-r--r-- | sys/arch/macppc/pci/hpb.c | 248 |
4 files changed, 398 insertions, 41 deletions
diff --git a/sys/arch/macppc/conf/GENERIC b/sys/arch/macppc/conf/GENERIC index b5cb4f3a3f2..dbfab3c4d36 100644 --- a/sys/arch/macppc/conf/GENERIC +++ b/sys/arch/macppc/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.250 2015/05/30 18:14:08 jsg Exp $g +# $OpenBSD: GENERIC,v 1.251 2015/06/02 13:53:43 mpi Exp $g # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -46,7 +46,9 @@ smu* at mainbus0 pci* at mpcpcibr? pci* at ht? ppb* at pci? # PCI-PCI bridges +hpb* at pci? pci* at ppb? +pci* at hpb? siop* at pci? fxp* at pci? diff --git a/sys/arch/macppc/conf/files.macppc b/sys/arch/macppc/conf/files.macppc index 28c6cd7d6ec..9aa971eebc1 100644 --- a/sys/arch/macppc/conf/files.macppc +++ b/sys/arch/macppc/conf/files.macppc @@ -1,4 +1,4 @@ -# $OpenBSD: files.macppc,v 1.81 2015/05/11 06:46:21 ratchov Exp $ +# $OpenBSD: files.macppc,v 1.82 2015/06/02 13:53:43 mpi Exp $ # # macppc-specific configuration info @@ -86,7 +86,12 @@ include "dev/wscons/files.wscons" #file arch/macppc/pci/bandit.c pci -#PCI-Host bridge chipsets +# HT bridge +device hpb {} : pcibus +attach hpb at pci +file arch/macppc/pci/hpb.c hpb needs-flag + +# PCI-Host bridge chipsets device pchb: agpbus attach pchb at pci file arch/macppc/pci/pchb.c pchb diff --git a/sys/arch/macppc/dev/openpic.c b/sys/arch/macppc/dev/openpic.c index 32eec128de7..9ddac5f32cb 100644 --- a/sys/arch/macppc/dev/openpic.c +++ b/sys/arch/macppc/dev/openpic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: openpic.c,v 1.79 2015/04/02 11:22:48 mpi Exp $ */ +/* $OpenBSD: openpic.c,v 1.80 2015/06/02 13:53:43 mpi Exp $ */ /*- * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org> @@ -37,13 +37,15 @@ * @(#)isa.c 7.2 (Berkeley) 5/12/91 */ +#include "hpb.h" + #include <sys/param.h> #include <sys/device.h> #include <sys/systm.h> #include <sys/malloc.h> +#include <sys/atomic.h> #include <uvm/uvm_extern.h> -#include <ddb/db_var.h> #include <machine/autoconf.h> #include <machine/intr.h> @@ -85,16 +87,41 @@ void openpic_splx(int); u_int openpic_read(int reg); void openpic_write(int reg, u_int val); -void openpic_enable_irq(int, int); -void openpic_disable_irq(int); + +void openpic_acknowledge_irq(int, int); +void openpic_enable_irq(int, int, int); +void openpic_disable_irq(int, int); + void openpic_calc_mask(void); void openpic_set_priority(int, int); void *openpic_intr_establish(void *, int, int, int, int (*)(void *), void *, const char *); -void openpic_intr_disestablish( void *lcp, void *arg); +void openpic_intr_disestablish(void *, void *); void openpic_collect_preconf_intr(void); void openpic_ext_intr(void); +/* Generic IRQ management routines. */ +void openpic_gen_acknowledge_irq(int, int); +void openpic_gen_enable_irq(int, int, int); +void openpic_gen_disable_irq(int, int); + +#if NHPB > 0 +/* CPC945 IRQ management routines. */ +void openpic_cpc945_acknowledge_irq(int, int); +void openpic_cpc945_enable_irq(int, int, int); +void openpic_cpc945_disable_irq(int, int); +#endif /* NHPB */ + +struct openpic_ops { + void (*acknowledge_irq)(int, int); + void (*enable_irq)(int, int, int); + void (*disable_irq)(int, int); +} openpic_ops = { + openpic_gen_acknowledge_irq, + openpic_gen_enable_irq, + openpic_gen_disable_irq +}; + #ifdef MULTIPROCESSOR void openpic_ipi_ddb(void); @@ -124,7 +151,7 @@ openpic_read(int reg) { char *addr = (void *)(openpic_base + reg); - asm volatile("eieio"::: "memory"); + membar_sync(); if (openpic_big_endian) return in32(addr); else @@ -140,7 +167,7 @@ openpic_write(int reg, u_int val) out32(addr, val); else out32rb(addr, val); - asm volatile("eieio"::: "memory"); + membar_sync(); } static inline int @@ -183,7 +210,7 @@ openpic_match(struct device *parent, void *cf, void *aux) } void -openpic_attach(struct device *parent, struct device *self, void *aux) +openpic_attach(struct device *parent, struct device *self, void *aux) { struct cpu_info *ci = curcpu(); struct confargs *ca = aux; @@ -198,6 +225,13 @@ openpic_attach(struct device *parent, struct device *self, void *aux) openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr + ca->ca_reg[0], 0x40000); + /* Reset the PIC */ + x = openpic_read(OPENPIC_CONFIG) | OPENPIC_CONFIG_RESET; + openpic_write(OPENPIC_CONFIG, x); + + while (openpic_read(OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) + delay(100); + /* openpic may support more than 128 interupts but driver doesn't */ openpic_numirq = ((openpic_read(OPENPIC_FEATURE) >> 16) & 0x7f)+1; @@ -270,12 +304,21 @@ openpic_attach(struct device *parent, struct device *self, void *aux) openpic_write(OPENPIC_SPURIOUS_VECTOR, 255); #endif +#if NHPB > 0 + /* Only U4 systems have a big-endian MPIC. */ + if (openpic_big_endian) { + openpic_ops.acknowledge_irq = openpic_cpc945_acknowledge_irq; + openpic_ops.enable_irq = openpic_cpc945_enable_irq; + openpic_ops.disable_irq = openpic_cpc945_disable_irq; + } +#endif + install_extint(openpic_ext_intr); openpic_set_priority(ci->ci_cpuid, 0); intr_establish_func = openpic_intr_establish; - intr_disestablish_func = openpic_intr_disestablish; + intr_disestablish_func = openpic_intr_disestablish; #ifdef MULTIPROCESSOR intr_send_ipi_func = openpic_send_ipi; #endif @@ -498,12 +541,12 @@ openpic_calc_mask() if (maxipl == IPL_NONE) { minipl = IPL_NONE; /* Interrupt not enabled */ - openpic_disable_irq(irq); + openpic_disable_irq(irq, iq->iq_ist); } else { for (i = minipl; i <= maxipl; i++) { openpic_pri_share[i] = maxipl; } - openpic_enable_irq(irq, maxipl); + openpic_enable_irq(irq, iq->iq_ist, maxipl); } iq->iq_ipl = maxipl; @@ -514,13 +557,19 @@ openpic_calc_mask() } void -openpic_enable_irq(int irq, int pri) +openpic_gen_acknowledge_irq(int irq, int cpuid) +{ + openpic_eoi(cpuid); +} + +void +openpic_gen_enable_irq(int irq, int ist, int pri) { u_int x; - struct intrq *iq = &openpic_handler[irq]; x = irq; - if (iq->iq_ist == IST_LEVEL) + + if (ist == IST_LEVEL) x |= OPENPIC_SENSE_LEVEL; else x |= OPENPIC_SENSE_EDGE; @@ -530,7 +579,7 @@ openpic_enable_irq(int irq, int pri) } void -openpic_disable_irq(int irq) +openpic_gen_disable_irq(int irq, int ist) { u_int x; @@ -545,30 +594,11 @@ openpic_set_priority(int cpu, int pri) openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri); } -#ifdef MULTIPROCESSOR -void -openpic_send_ipi(struct cpu_info *ci, int id) -{ - switch (id) { - case PPC_IPI_NOP: - id = 0; - break; - case PPC_IPI_DDB: - id = 1; - break; - default: - panic("invalid ipi send to cpu %d %d", ci->ci_cpuid, id); - } - - openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid); -} - -#endif - int openpic_irqnest[PPC_MAXPROCS]; int openpic_irqloop[PPC_MAXPROCS]; + void -openpic_ext_intr() +openpic_ext_intr(void) { struct cpu_info *ci = curcpu(); int irq, pcpl, ret; @@ -624,7 +654,7 @@ openpic_ext_intr() if (iq->iq_ipl > maxipl) maxipl = iq->iq_ipl; openpic_splraise(iq->iq_ipl); - openpic_eoi(ci->ci_cpuid); + openpic_acknowledge_irq(irq, ci->ci_cpuid); spurious = 1; TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { @@ -656,9 +686,44 @@ openpic_ext_intr() openpic_irqnest[ci->ci_cpuid]--; } +void +openpic_acknowledge_irq(int irq, int cpuid) +{ + (openpic_ops.acknowledge_irq)(irq, cpuid); +} + +void +openpic_enable_irq(int irq, int ist, int pri) +{ + (openpic_ops.enable_irq)(irq, ist, pri); +} + +void +openpic_disable_irq(int irq, int ist) +{ + (openpic_ops.disable_irq)(irq, ist); +} + #ifdef MULTIPROCESSOR void -openpic_ipi_ddb() +openpic_send_ipi(struct cpu_info *ci, int id) +{ + switch (id) { + case PPC_IPI_NOP: + id = 0; + break; + case PPC_IPI_DDB: + id = 1; + break; + default: + panic("invalid ipi send to cpu %d %d", ci->ci_cpuid, id); + } + + openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid); +} + +void +openpic_ipi_ddb(void) { DPRINTF("ipi_ddb() called\n"); #ifdef DDB @@ -666,3 +731,40 @@ openpic_ipi_ddb() #endif } #endif /* MULTIPROCESSOR */ + +#if NHPB > 0 +extern int hpb_enable_irq(int, int); +extern int hpb_disable_irq(int, int); +extern void hpb_eoi(int); + +void +openpic_cpc945_acknowledge_irq(int irq, int cpuid) +{ + hpb_eoi(irq); + openpic_gen_acknowledge_irq(irq, cpuid); +} + +void +openpic_cpc945_enable_irq(int irq, int ist, int pri) +{ + if (hpb_enable_irq(irq, ist)) { + u_int x = irq; + + x |= OPENPIC_SENSE_EDGE; + x |= OPENPIC_POLARITY_POSITIVE; + x |= pri << OPENPIC_PRIORITY_SHIFT; + openpic_write(OPENPIC_SRC_VECTOR(irq), x); + + hpb_eoi(irq); + } else + openpic_gen_enable_irq(irq, ist, pri); +} + +void +openpic_cpc945_disable_irq(int irq, int ist) +{ + hpb_disable_irq(irq, ist); + openpic_gen_disable_irq(irq, ist); +} +#endif /* NHPB */ + diff --git a/sys/arch/macppc/pci/hpb.c b/sys/arch/macppc/pci/hpb.c new file mode 100644 index 00000000000..7633847a947 --- /dev/null +++ b/sys/arch/macppc/pci/hpb.c @@ -0,0 +1,248 @@ +/* $OpenBSD: hpb.c,v 1.1 2015/06/02 13:53:43 mpi Exp $ */ + +/* + * Copyright (c) 2015 Martin Pieuchot + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/intr.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> +#include <dev/pci/ppbreg.h> + +/* + * Section 7.6.2 Interrupt Message Definition Register + */ +#define PCI_HT_LAST_ISMG (0x01 << 16) +#define PCI_HT_IMSG_LO(idx) (((2 * (idx)) + 0x10) << 16) +#define HT_MASK (1 << 0) +#define HT_ACTIVELOW (1 << 1) +#define HT_EOI (1 << 5) + +#define PCI_HT_IMSG_HI(idx) (PCI_HT_IMSG_LO(idx) + 1) +#define HT_PASSPW (1U << 30) +#define HT_WAITEOI (1U << 31) /* Waiting for EOI */ + + +/* Apple hardware is special... */ +#define HT_APPL_EOIOFF(idx) (0x60 + (((idx) >> 3) & ~3)) +#define HT_APPL_WEOI(idx) (1 << ((idx) & 0x1f)) + +struct ht_intr_msg { + unsigned int him_idx; /* Index */ + int him_ist; /* Share type */ + pcireg_t him_weoi; /* Cached wait for interrupt data */ +}; + +#define hpb_MAX_IMSG 128 + +struct hpb_softc { + struct device sc_dev; + pci_chipset_tag_t sc_pc; + pcitag_t sc_tag; + pcireg_t sc_id; /* Needed for Apple hardware */ + unsigned int sc_off; /* Interrupt cap. offset */ + unsigned int sc_nirq; + struct ht_intr_msg sc_imap[hpb_MAX_IMSG]; +}; + +int hpb_match(struct device *, void *, void *); +void hpb_attach(struct device *, struct device *, void *); + +int hpb_print(void *, const char *); + +void hpb_eoi(int); +int hpb_enable_irq(int, int); +int hpb_disable_irq(int, int); + +const struct cfattach hpb_ca = { + sizeof(struct hpb_softc), hpb_match, hpb_attach +}; + +struct cfdriver hpb_cd = { + NULL, "hpb", DV_DULL, +}; + +int +hpb_match(struct device *parent, void *match, void *aux) +{ + struct pci_attach_args *pa = aux; + pci_chipset_tag_t pc = pa->pa_pc; + pcitag_t tag = pa->pa_tag; + + if (PCI_CLASS(pa->pa_class) != PCI_CLASS_BRIDGE || + PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_BRIDGE_PCI) + return (0); + + if (!pci_get_ht_capability(pc, tag, PCI_HT_CAP_INTR, NULL, NULL)) + return (0); + + return (10); +} + +void +hpb_attach(struct device *parent, struct device *self, void *aux) +{ + struct hpb_softc *sc = (struct hpb_softc *)self; + struct pci_attach_args *pa = aux; + struct pcibus_attach_args pba; + pci_chipset_tag_t pc = pa->pa_pc; + pcitag_t tag = pa->pa_tag; + int idx, irq, off; + pcireg_t busdata, reg; + + if (!pci_get_ht_capability(pc, tag, PCI_HT_CAP_INTR, &off, NULL)) + panic("A clown ate your HT capability"); + + /* Interrupt definitions are numbered beginning with 0. */ + pci_conf_write(pc, tag, off, PCI_HT_LAST_ISMG); + reg = pci_conf_read(pc, tag, off + PCI_HT_INTR_DATA); + + sc->sc_pc = pc; + sc->sc_tag = tag; + sc->sc_id = pa->pa_id; + sc->sc_off = off; + sc->sc_nirq = ((reg >> 16) & 0xff); + + if (sc->sc_nirq == 0 || sc->sc_nirq > hpb_MAX_IMSG) + return; + + printf(": %u sources\n", sc->sc_nirq); + + for (idx = 0; idx < sc->sc_nirq; idx++) { + pci_conf_write(pc, tag, off, PCI_HT_IMSG_LO(idx)); + reg = pci_conf_read(pc, tag, off + PCI_HT_INTR_DATA); + + pci_conf_write(pc, tag, off + PCI_HT_INTR_DATA, reg | HT_MASK); + irq = (reg >> 16) & 0xff; + +#ifdef DIAGNOSTIC + if (sc->sc_imap[irq].him_idx != 0) { + printf("%s: multiple definition for irq %d\n", + sc->sc_dev.dv_xname, irq); + continue; + } +#endif + pci_conf_write(pc, tag, off, PCI_HT_IMSG_HI(idx)); + reg = pci_conf_read(pc, tag, off + PCI_HT_INTR_DATA); + + sc->sc_imap[irq].him_idx = idx; + sc->sc_imap[irq].him_weoi = reg | HT_WAITEOI; + } + + busdata = pci_conf_read(pc, pa->pa_tag, PPB_REG_BUSINFO); + + memset(&pba, 0, sizeof(pba)); + pba.pba_busname = "pci"; + pba.pba_iot = pa->pa_iot; + pba.pba_memt = pa->pa_memt; + pba.pba_dmat = pa->pa_dmat; + pba.pba_pc = pc; + pba.pba_domain = pa->pa_domain; + pba.pba_bus = PPB_BUSINFO_SECONDARY(busdata); + pba.pba_bridgetag = &sc->sc_tag; + + config_found(self, &pba, hpb_print); +} + +int +hpb_print(void *aux, const char *pnp) +{ + struct pcibus_attach_args *pba = aux; + + if (pnp) + printf("%s at %s", pba->pba_busname, pnp); + printf(" bus %d", pba->pba_bus); + return (UNCONF); +} + +void +hpb_eoi(int irq) +{ + struct hpb_softc *sc = hpb_cd.cd_devs[0]; + pci_chipset_tag_t pc = sc->sc_pc; + pcitag_t tag = sc->sc_tag; + int idx; + + if (irq >= sc->sc_nirq || sc->sc_imap[irq].him_weoi == 0 || + sc->sc_imap[irq].him_ist != IST_LEVEL) + return; + + idx = sc->sc_imap[irq].him_idx; + + if (PCI_VENDOR(sc->sc_id) == PCI_VENDOR_APPLE) { + pci_conf_write(pc, tag, HT_APPL_EOIOFF(idx), HT_APPL_WEOI(idx)); + } else { + pci_conf_write(pc, tag, sc->sc_off, PCI_HT_IMSG_HI(idx)); + pci_conf_write(pc, tag, sc->sc_off + PCI_HT_INTR_DATA, + sc->sc_imap[irq].him_weoi); + } +} + +int +hpb_enable_irq(int irq, int ist) +{ + struct hpb_softc *sc = hpb_cd.cd_devs[0]; + pci_chipset_tag_t pc = sc->sc_pc; + pcitag_t tag = sc->sc_tag; + pcireg_t reg; + int idx; + + if (irq >= sc->sc_nirq || sc->sc_imap[irq].him_weoi == 0) + return (0); + + idx = sc->sc_imap[irq].him_idx; + sc->sc_imap[irq].him_ist = ist; + + pci_conf_write(pc, tag, sc->sc_off, PCI_HT_IMSG_LO(idx)); + reg = pci_conf_read(pc, tag, sc->sc_off + PCI_HT_INTR_DATA); + + pci_conf_write(pc, tag, sc->sc_off + PCI_HT_INTR_DATA, reg | HT_MASK); + + reg &= ~(HT_ACTIVELOW | HT_EOI | HT_MASK); + if (ist == IST_LEVEL) + reg |= HT_ACTIVELOW | HT_EOI; + + pci_conf_write(pc, tag, sc->sc_off + PCI_HT_INTR_DATA, reg); + + return (1); +} + +int +hpb_disable_irq(int irq, int ist) +{ + struct hpb_softc *sc = hpb_cd.cd_devs[0]; + pci_chipset_tag_t pc = sc->sc_pc; + pcitag_t tag = sc->sc_tag; + pcireg_t reg; + int idx; + + if (irq > sc->sc_nirq || sc->sc_imap[irq].him_weoi == 0) + return (0); + + idx = sc->sc_imap[irq].him_idx; + + pci_conf_write(pc, tag, sc->sc_off, PCI_HT_IMSG_LO(idx)); + reg = pci_conf_read(pc, tag, sc->sc_off + PCI_HT_INTR_DATA); + + pci_conf_write(pc, tag, sc->sc_off + PCI_HT_INTR_DATA, reg | HT_MASK); + + return (1); +} |