summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsing <jsing@openbsd.org>2011-04-07 14:22:26 +0000
committerjsing <jsing@openbsd.org>2011-04-07 14:22:26 +0000
commit63e18f3ab43828218345072ebb760b4a70a47833 (patch)
treee8762276397440405a055d3d29a76661a8c3a86d
parentMake sure the eeprom pointer is correctly initialized in (diff)
downloadwireguard-openbsd-63e18f3ab43828218345072ebb760b4a70a47833.tar.xz
wireguard-openbsd-63e18f3ab43828218345072ebb760b4a70a47833.zip
Sync apic code from hppa.
ok kettenis@
-rw-r--r--sys/arch/hppa64/dev/apic.c298
1 files changed, 261 insertions, 37 deletions
diff --git a/sys/arch/hppa64/dev/apic.c b/sys/arch/hppa64/dev/apic.c
index 68ed3a57d9d..5b37a2c9ec9 100644
--- a/sys/arch/hppa64/dev/apic.c
+++ b/sys/arch/hppa64/dev/apic.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: apic.c,v 1.5 2010/07/01 04:33:23 jsing Exp $ */
+/* $OpenBSD: apic.c,v 1.6 2011/04/07 14:22:26 jsing Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
+ * Copyright (c) 2007 Mark Kettenis
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
@@ -17,11 +18,14 @@
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define APIC_DEBUG
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/malloc.h>
+
+#include <machine/autoconf.h>
+#include <machine/pdc.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
@@ -30,14 +34,61 @@
#include <hppa64/dev/elroyreg.h>
#include <hppa64/dev/elroyvar.h>
-void apic_write(volatile struct elroy_regs *, u_int32_t, u_int32_t);
-u_int32_t apic_read(volatile struct elroy_regs *, u_int32_t);
+#define APIC_INT_LINE_MASK 0x0000ff00
+#define APIC_INT_LINE_SHIFT 8
+#define APIC_INT_IRQ_MASK 0x0000001f
+
+#define APIC_INT_LINE(x) (((x) & APIC_INT_LINE_MASK) >> APIC_INT_LINE_SHIFT)
+#define APIC_INT_IRQ(x) ((x) & APIC_INT_IRQ_MASK)
+
+/*
+ * Interrupt types match the Intel MP Specification.
+ */
+
+#define MPS_INTPO_DEF 0
+#define MPS_INTPO_ACTHI 1
+#define MPS_INTPO_ACTLO 3
+#define MPS_INTPO_SHIFT 0
+#define MPS_INTPO_MASK 3
+
+#define MPS_INTTR_DEF 0
+#define MPS_INTTR_EDGE 1
+#define MPS_INTTR_LEVEL 3
+#define MPS_INTTR_SHIFT 2
+#define MPS_INTTR_MASK 3
+
+#define MPS_INT(p,t) \
+ ((((p) & MPS_INTPO_MASK) << MPS_INTPO_SHIFT) | \
+ (((t) & MPS_INTTR_MASK) << MPS_INTTR_SHIFT))
+
+struct apic_iv {
+ struct elroy_softc *sc;
+ pci_intr_handle_t ih;
+ int (*handler)(void *);
+ void *arg;
+ struct apic_iv *next;
+ struct evcount *cnt;
+};
+
+struct apic_iv *apic_intr_list[CPU_NINTS];
+
+void apic_get_int_tbl(struct elroy_softc *);
+u_int32_t apic_get_int_ent0(struct elroy_softc *, int);
+
+void apic_write(volatile struct elroy_regs *r, u_int32_t reg,
+ u_int32_t val);
+u_int32_t apic_read(volatile struct elroy_regs *r, u_int32_t reg);
+
+#ifdef DEBUG
+void apic_dump(struct elroy_softc *);
+#endif
void
apic_write(volatile struct elroy_regs *r, u_int32_t reg, u_int32_t val)
{
elroy_write32(&r->apic_addr, htole32(reg));
elroy_write32(&r->apic_data, htole32(val));
+ elroy_read32(&r->apic_data);
}
u_int32_t
@@ -47,10 +98,6 @@ apic_read(volatile struct elroy_regs *r, u_int32_t reg)
return letoh32(elroy_read32(&r->apic_data));
}
-void apic_write(volatile struct elroy_regs *r, u_int32_t reg,
- u_int32_t val);
-u_int32_t apic_read(volatile struct elroy_regs *r, u_int32_t reg);
-
void
apic_attach(struct elroy_softc *sc)
{
@@ -61,25 +108,38 @@ apic_attach(struct elroy_softc *sc)
sc->sc_nints = (data & APIC_VERSION_NENT) >> APIC_VERSION_NENT_SHIFT;
printf(" APIC ver %x, %d pins",
data & APIC_VERSION_MASK, sc->sc_nints);
+
+ sc->sc_irq = malloc(sc->sc_nints * sizeof(int), M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (sc->sc_irq == NULL)
+ panic("apic_attach: cannot allocate irq table");
+
+ apic_get_int_tbl(sc);
+
+#ifdef DEBUG
+ apic_dump(sc);
+#endif
}
int
apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
+ struct elroy_softc *sc = pa->pa_pc->_cookie;
pci_chipset_tag_t pc = pa->pa_pc;
- struct elroy_softc *sc = pc->_cookie;
pcitag_t tag = pa->pa_tag;
- hppa_hpa_t hpa = cpu_gethpa(0);
pcireg_t reg;
+ int line;
reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
-printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg), PCI_INTERRUPT_LINE(reg));
- apic_write(sc->sc_regs, APIC_ENT0(PCI_INTERRUPT_PIN(reg)),
+#ifdef DEBUG
+ printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg),
PCI_INTERRUPT_LINE(reg));
- apic_write(sc->sc_regs, APIC_ENT1(PCI_INTERRUPT_PIN(reg)),
- ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12));
- *ihp = PCI_INTERRUPT_LINE(reg) + 1;
- return (*ihp == 0);
+#endif
+ line = PCI_INTERRUPT_LINE(reg);
+ if (sc->sc_irq[line] == 0)
+ sc->sc_irq[line] = cpu_intr_findirq();
+ *ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line];
+ return (APIC_INT_IRQ(*ihp) == 0);
}
const char *
@@ -87,7 +147,8 @@ apic_intr_string(void *v, pci_intr_handle_t ih)
{
static char buf[32];
- snprintf(buf, 32, "irq %ld", ih);
+ snprintf(buf, 32, "line %ld irq %ld",
+ APIC_INT_LINE(ih), APIC_INT_IRQ(ih));
return (buf);
}
@@ -96,23 +157,68 @@ void *
apic_intr_establish(void *v, pci_intr_handle_t ih,
int pri, int (*handler)(void *), void *arg, const char *name)
{
- /* struct elroy_softc *sc = v; */
- /* volatile struct elroy_regs *r = sc->sc_regs; */
- /* void *iv = NULL; */
+ struct elroy_softc *sc = v;
+ volatile struct elroy_regs *r = sc->sc_regs;
+ hppa_hpa_t hpa = cpu_gethpa(0);
+ struct evcount *cnt;
+ struct apic_iv *aiv, *biv;
+ void *iv;
+ int irq = APIC_INT_IRQ(ih);
+ int line = APIC_INT_LINE(ih);
+ u_int32_t ent0;
/* no mapping or bogus */
- if (ih <= 0 || ih > 63)
+ if (irq <= 0 || irq > 63)
return (NULL);
-#if 0
-TODO
- if ((iv = cpu_intr_map(sc->sc_ih, pri, ih - 1, handler, arg, name))) {
- if (cold)
- sc->sc_imr |= (1 << (ih - 1));
- else
- /* r->imr = sc->sc_imr |= (1 << (ih - 1)) */;
+ aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT);
+ if (aiv == NULL) {
+ free(cnt, M_DEVBUF);
+ return NULL;
+ }
+
+ aiv->sc = sc;
+ aiv->ih = ih;
+ aiv->handler = handler;
+ aiv->arg = arg;
+ aiv->next = NULL;
+ aiv->cnt = NULL;
+ if (apic_intr_list[irq]) {
+ cnt = malloc(sizeof(struct evcount), M_DEVBUF, M_NOWAIT);
+ if (!cnt) {
+ free(aiv, M_DEVBUF);
+ return (NULL);
+ }
+
+ evcount_attach(cnt, name, NULL);
+ biv = apic_intr_list[irq];
+ while (biv->next)
+ biv = biv->next;
+ biv->next = aiv;
+ aiv->cnt = cnt;
+ return (arg);
}
+
+ if ((iv = cpu_intr_establish(pri, irq, apic_intr, aiv, name))) {
+ ent0 = (63 - irq) & APIC_ENT0_VEC;
+ ent0 |= apic_get_int_ent0(sc, line);
+#if 0
+ if (cold) {
+ sc->sc_imr |= (1 << irq);
+ ent0 |= APIC_ENT0_MASK;
+ }
#endif
+ apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK);
+ apic_write(sc->sc_regs, APIC_ENT1(line),
+ ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12));
+ apic_write(sc->sc_regs, APIC_ENT0(line), ent0);
+
+ /* Signal EOI. */
+ elroy_write32(&r->apic_eoi,
+ htole32((63 - irq) & APIC_ENT0_VEC));
+
+ apic_intr_list[irq] = aiv;
+ }
return (arg);
}
@@ -120,19 +226,137 @@ TODO
void
apic_intr_disestablish(void *v, void *cookie)
{
-#if 0
- struct elroy_softc *sc = v;
+}
+
+int
+apic_intr(void *v)
+{
+ struct apic_iv *iv = v;
+ struct elroy_softc *sc = iv->sc;
volatile struct elroy_regs *r = sc->sc_regs;
+ pci_intr_handle_t ih = iv->ih;
+ int claimed = 0;
- r->imr &= ~(1 << (ih - 1));
+ while (iv) {
+ if (iv->handler(iv->arg)) {
+ if (iv->cnt)
+ iv->cnt->ec_count++;
+ else
+ claimed = 1;
+ }
+ iv = iv->next;
+ }
- TODO cpu_intr_unmap(sc->sc_ih, cookie);
-#endif
+ /* Signal EOI. */
+ elroy_write32(&r->apic_eoi,
+ htole32((63 - APIC_INT_IRQ(ih)) & APIC_ENT0_VEC));
+
+ return (claimed);
}
-int
-apic_intr(void *v)
+/* Maximum number of supported interrupt routing entries. */
+#define MAX_INT_TBL_SZ 16
+
+void
+apic_get_int_tbl(struct elroy_softc *sc)
+{
+ struct pdc_pat_io_num int_tbl_sz PDC_ALIGNMENT;
+ struct pdc_pat_pci_rt int_tbl[MAX_INT_TBL_SZ] PDC_ALIGNMENT;
+ size_t size;
+
+ /*
+ * XXX int_tbl should not be allocated on the stack, but we need a
+ * 1:1 mapping, and malloc doesn't provide that.
+ */
+
+ if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SZ,
+ &int_tbl_sz, 0, 0, 0, 0, 0))
+ return;
+
+ if (int_tbl_sz.num > MAX_INT_TBL_SZ)
+ panic("interrupt routing table too big (%d entries)",
+ int_tbl_sz.num);
+
+ size = int_tbl_sz.num * sizeof(struct pdc_pat_pci_rt);
+ sc->sc_int_tbl_sz = int_tbl_sz.num;
+ sc->sc_int_tbl = malloc(size, M_DEVBUF, M_NOWAIT);
+ if (sc->sc_int_tbl == NULL)
+ return;
+
+ if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
+ &int_tbl_sz, 0, &int_tbl, 0, 0, 0))
+ return;
+
+ memcpy(sc->sc_int_tbl, int_tbl, size);
+}
+
+u_int32_t
+apic_get_int_ent0(struct elroy_softc *sc, int line)
+{
+ volatile struct elroy_regs *r = sc->sc_regs;
+ int trigger = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF);
+ u_int32_t ent0 = APIC_ENT0_LOW | APIC_ENT0_LEV;
+ int bus, mpspo, mpstr;
+ int i;
+
+ bus = letoh32(elroy_read32(&r->busnum)) & 0xff;
+ for (i = 0; i < sc->sc_int_tbl_sz; i++) {
+ if (bus == sc->sc_int_tbl[i].bus &&
+ line == sc->sc_int_tbl[i].line)
+ trigger = sc->sc_int_tbl[i].trigger;
+ }
+
+ mpspo = (trigger >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
+ mpstr = (trigger >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
+
+ switch (mpspo) {
+ case MPS_INTPO_DEF:
+ break;
+ case MPS_INTPO_ACTHI:
+ ent0 &= ~APIC_ENT0_LOW;
+ break;
+ case MPS_INTPO_ACTLO:
+ ent0 |= APIC_ENT0_LOW;
+ break;
+ default:
+ panic("unknown MPS interrupt polarity %d", mpspo);
+ }
+
+ switch(mpstr) {
+ case MPS_INTTR_DEF:
+ break;
+ case MPS_INTTR_LEVEL:
+ ent0 |= APIC_ENT0_LEV;
+ break;
+ case MPS_INTTR_EDGE:
+ ent0 &= ~APIC_ENT0_LEV;
+ break;
+ default:
+ panic("unknown MPS interrupt trigger %d", mpstr);
+ }
+
+ return ent0;
+}
+
+#ifdef DEBUG
+void
+apic_dump(struct elroy_softc *sc)
{
+ int i;
+
+ for (i = 0; i < sc->sc_nints; i++)
+ printf("0x%04x 0x%04x\n", apic_read(sc->sc_regs, APIC_ENT0(i)),
+ apic_read(sc->sc_regs, APIC_ENT1(i)));
- return (0);
+ for (i = 0; i < sc->sc_int_tbl_sz; i++) {
+ printf("type=%x ", sc->sc_int_tbl[i].type);
+ printf("len=%d ", sc->sc_int_tbl[i].len);
+ printf("itype=%d ", sc->sc_int_tbl[i].itype);
+ printf("trigger=%x ", sc->sc_int_tbl[i].trigger);
+ printf("pin=%x ", sc->sc_int_tbl[i].pin);
+ printf("bus=%d ", sc->sc_int_tbl[i].bus);
+ printf("line=%d ", sc->sc_int_tbl[i].line);
+ printf("addr=%x\n", sc->sc_int_tbl[i].addr);
+ }
}
+#endif