Module Name:    src
Committed By:   skrll
Date:           Thu Apr 30 07:08:39 UTC 2009

Added Files:
        src/sys/arch/hp700/dev: apic.c

Log Message:
Another file missed by me / cvs in the nick-hppapmap merge.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.2 src/sys/arch/hp700/dev/apic.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/sys/arch/hp700/dev/apic.c
diff -u /dev/null src/sys/arch/hp700/dev/apic.c:1.2
--- /dev/null	Thu Apr 30 07:08:39 2009
+++ src/sys/arch/hp700/dev/apic.c	Thu Apr 30 07:08:39 2009
@@ -0,0 +1,362 @@
+/*	$NetBSD: apic.c,v 1.2 2009/04/30 07:08:39 skrll Exp $	*/
+
+/*	$OpenBSD: apic.c,v 1.7 2007/10/06 23:50:54 krw 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
+ * 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 MIND, 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 <sys/malloc.h>
+
+#include <machine/autoconf.h>
+#include <machine/pdc.h>
+#include <machine/intr.h>
+
+#include <hp700/hp700/intr.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <hp700/dev/elroyreg.h>
+#include <hp700/dev/elroyvar.h>
+
+#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 evcnt *cnt;
+};
+
+struct apic_iv *apic_intr_list[CPU_NINTS];
+
+void apic_write(volatile struct elroy_regs *, uint32_t, uint32_t);
+uint32_t apic_read(volatile struct elroy_regs *, uint32_t reg);
+
+void	apic_get_int_tbl(struct elroy_softc *);
+uint32_t apic_get_int_ent0(struct elroy_softc *, int);
+#ifdef DEBUG
+void	apic_dump(struct elroy_softc *);
+#endif
+
+void
+apic_write(volatile struct elroy_regs *r, uint32_t reg, uint32_t val)
+{
+	elroy_write32(&r->apic_addr, htole32(reg));
+	elroy_write32(&r->apic_data, htole32(val));
+	elroy_read32(&r->apic_data);
+}
+
+uint32_t
+apic_read(volatile struct elroy_regs *r, uint32_t reg)
+{
+	elroy_write32(&r->apic_addr, htole32(reg));
+	return le32toh(elroy_read32(&r->apic_data));
+}
+
+void
+apic_attach(struct elroy_softc *sc)
+{
+	volatile struct elroy_regs *r = sc->sc_regs;
+	uint32_t data;
+
+	data = apic_read(r, APIC_VERSION);
+	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\n");
+
+	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;
+	pcitag_t tag = pa->pa_tag;
+	pcireg_t reg;
+	int line;
+
+	reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
+#ifdef DEBUG
+	printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg),
+	    PCI_INTERRUPT_LINE(reg));
+#endif
+	line = PCI_INTERRUPT_LINE(reg);
+	if (sc->sc_irq[line] == 0)
+		sc->sc_irq[line] = hp700_intr_allocate_bit(&int_reg_cpu);;
+	*ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line];
+	return (APIC_INT_IRQ(*ihp) == 0);
+}
+
+const char *
+apic_intr_string(void *v, pci_intr_handle_t ih)
+{
+	static char buf[32];
+
+	snprintf(buf, sizeof(buf), "line %ld irq %ld",
+	    APIC_INT_LINE(ih), APIC_INT_IRQ(ih));
+
+	return (buf);
+}
+
+void *
+apic_intr_establish(void *v, pci_intr_handle_t ih,
+    int pri, int (*handler)(void *), void *arg)
+{
+	struct elroy_softc *sc = v;
+	volatile struct elroy_regs *r = sc->sc_regs;
+	hppa_hpa_t hpa = cpu_gethpa(0);
+	struct evcnt *cnt;
+	struct apic_iv *aiv, *biv;
+	void *iv;
+	int irq = APIC_INT_IRQ(ih);
+	int line = APIC_INT_LINE(ih);
+	uint32_t ent0;
+
+	/* no mapping or bogus */
+	if (irq <= 0 || irq > 31)
+		return (NULL);
+
+	aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT);
+	if (aiv == NULL)
+		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 evcnt), M_DEVBUF, M_NOWAIT);
+		if (cnt == NULL) {
+			free(aiv, M_DEVBUF);
+			return NULL;
+		}
+
+		evcnt_attach_dynamic(cnt, EVCNT_TYPE_INTR, NULL,
+		    sc->sc_dv.dv_xname, "irq" /* XXXNH */);
+		biv = apic_intr_list[irq];
+		while (biv->next)
+			biv = biv->next;
+		biv->next = aiv;
+		aiv->cnt = cnt;
+		return arg;
+	}
+
+	if ((iv = hp700_intr_establish(&sc->sc_dv, pri, apic_intr,
+	     aiv, &int_reg_cpu, irq))) {
+		ent0 = (31 - 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((31 - irq) & APIC_ENT0_VEC));
+
+		apic_intr_list[irq] = aiv;
+	}
+
+	return (arg);
+}
+
+void
+apic_intr_disestablish(void *v, void *cookie)
+{
+}
+
+int
+apic_intr(void *v)
+{
+	struct apic_iv *iv = v;
+	struct elroy_softc *sc = iv->sc;
+	volatile struct elroy_regs *r = sc->sc_regs;
+	int claimed = 0;
+
+	while (iv) {
+		if (iv->handler(iv->arg)) {
+			if (iv->cnt)
+				iv->cnt->ev_count++;
+			else
+				claimed = 1;
+		}
+		iv = iv->next;
+	}
+
+	/* Signal EOI. */
+	elroy_write32(&r->apic_eoi,
+	    htole32((31 - APIC_INT_IRQ(iv->ih)) & APIC_ENT0_VEC));
+
+	return (claimed);
+}
+
+/* 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);
+}
+
+uint32_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);
+	uint32_t ent0 = APIC_ENT0_LOW | APIC_ENT0_LEV;
+	int bus, mpspo, mpstr;
+	int i;
+
+	bus = le32toh(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)));
+
+	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=%llx\n", sc->sc_int_tbl[i].addr);
+	}
+}
+#endif

Reply via email to