Module Name:    src
Committed By:   bsh
Date:           Fri Mar 11 03:26:37 UTC 2011

Added Files:
        src/sys/arch/arm/mpcore: dic.c dic_intr.h dicreg.h

Log Message:
DIC: ARM11 MPCore's Distributed Interrupt Controller.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/mpcore/dic.c \
    src/sys/arch/arm/mpcore/dic_intr.h src/sys/arch/arm/mpcore/dicreg.h

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/arm/mpcore/dic.c
diff -u /dev/null src/sys/arch/arm/mpcore/dic.c:1.1
--- /dev/null	Fri Mar 11 03:26:37 2011
+++ src/sys/arch/arm/mpcore/dic.c	Fri Mar 11 03:26:37 2011
@@ -0,0 +1,357 @@
+/*	$NetBSD: dic.c,v 1.1 2011/03/11 03:26:37 bsh Exp $ */
+
+/*
+ * Copyright (c) 2010, 2011 Genetec Corporation.  All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: dic.c,v 1.1 2011/03/11 03:26:37 bsh Exp $");
+
+#define	_INTR_PRIVATE	/* for arm/pic/picvar.h */
+
+#include "locators.h"
+#include "opt_dic.h"
+
+#include <sys/param.h>
+#include <sys/evcnt.h>
+#include <sys/device.h>
+#include <sys/atomic.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <arm/cpu.h>
+#include <arm/armreg.h>
+#include <arm/cpufunc.h>
+#include <arm/pic/picvar.h>
+
+#include <arm/mpcore/mpcorevar.h>
+#include <arm/mpcore/mpcorereg.h>
+#include <arm/mpcore/dicreg.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+/*
+ * 0 is the highest priority.
+ */
+#define	HW_TO_SW_IPL(ipl)	(IPL_HIGH - (ipl))
+#define	SW_TO_HW_IPL(ipl)	(IPL_HIGH - (ipl))
+
+struct dic_softc {
+	device_t sc_dev;
+	struct pic_softc sc_pic;
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_cii_ioh;
+	volatile uint32_t *sc_cii_vaddr;	/* CPU interface */
+	bus_space_handle_t sc_gid_ioh;
+	volatile uint32_t *sc_gid_vaddr;	/* Global distributor */
+	int sc_nsrcs;
+//	uint32_t sc_enabled_mask[4];
+};
+
+#define	PIC_TO_SOFTC(pic) \
+	((struct dic_softc *)((char *)(pic) - \
+		offsetof(struct dic_softc, sc_pic)))
+
+
+static int dic_match(device_t, cfdata_t, void *);
+static void dic_attach(device_t, device_t, void *);
+
+static void dic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
+static void dic_block_irqs(struct pic_softc *, size_t, uint32_t);
+static void dic_establish_irq(struct pic_softc *, struct intrsource *);
+
+#define	DIC_READ(sc, offset)	\
+	(*((sc)->sc_gid_vaddr + (offset) / sizeof (uint32_t)))
+#define	DIC_WRITE(sc, offset, val)					\
+	(*((sc)->sc_gid_vaddr + (offset) / sizeof (uint32_t)) = (val))
+
+#define	CII_READ(sc, offset)	\
+	(*((sc)->sc_cii_vaddr + (offset) / sizeof (uint32_t)))
+#define	CII_WRITE(sc, offset, val)					\
+	(*((sc)->sc_cii_vaddr + (offset) / sizeof (uint32_t)) = (val))
+
+const struct pic_ops dic_pic_ops = {
+	.pic_unblock_irqs = dic_unblock_irqs,
+	.pic_block_irqs = dic_block_irqs,
+	.pic_establish_irq = dic_establish_irq,
+	.pic_source_name = NULL
+};
+
+
+CFATTACH_DECL_NEW(dic, sizeof(struct dic_softc),
+    dic_match, dic_attach, NULL, NULL);
+
+struct dic_softc *dic_softc;
+
+static int
+dic_match(device_t parent, cfdata_t cf, void *aux)
+{
+	if (strcmp(cf->cf_name, "dic") == 0)
+		return 1;
+
+	return 0;
+}
+
+
+static void
+dic_attach(device_t parent, device_t self, void *aux)
+{
+	struct dic_softc *dic = device_private(self);
+	struct pmr_attach_args * const pa = aux;
+	uint32_t typ;
+
+	aprint_normal(": Distributed Interrupt Controller\n");
+	aprint_naive("\n");
+
+	dic->sc_dev = self;
+	dic->sc_iot = pa->pa_iot;
+
+	dic_softc = dic;
+
+	if (bus_space_subregion(dic->sc_iot, pa->pa_ioh, 
+		MPCORE_PMR_CII, MPCORE_PMR_CII_SIZE,
+		&dic->sc_cii_ioh) ||
+	    bus_space_subregion(dic->sc_iot, pa->pa_ioh, 
+		MPCORE_PMR_GID, MPCORE_PMR_GID_SIZE,
+		&dic->sc_gid_ioh)) {
+
+		aprint_error_dev(self, "can't subregion\n");
+		return;
+	}
+
+	dic->sc_cii_vaddr = bus_space_vaddr(dic->sc_iot, dic->sc_cii_ioh);
+	dic->sc_gid_vaddr = bus_space_vaddr(dic->sc_iot, dic->sc_gid_ioh);
+
+	typ = DIC_READ(dic, DIC_TYPE);
+
+	dic->sc_nsrcs =
+	    32 * (1 +
+		((typ & DIC_TYPE_NLINES_MASK) >> DIC_TYPE_NLINES_SHIFT));
+	
+	aprint_normal_dev(self, "%d CPUs, %d interrupt sources\n",
+	    1 + (u_int)((typ & DIC_TYPE_NCPUS_MASK) >> DIC_TYPE_NCPUS_SHIFT),
+	    dic->sc_nsrcs);
+
+
+	DIC_WRITE(dic, DIC_CONTROL, DIC_CONTROL_ENABLE);
+
+	CII_WRITE(dic, CII_CONTROL, CII_CONTROL_ENABLE);
+
+	dic->sc_pic.pic_ops = &dic_pic_ops;
+	dic->sc_pic.pic_maxsources = dic->sc_nsrcs;
+	strlcpy(dic->sc_pic.pic_name, device_xname(self),
+	    sizeof(dic->sc_pic.pic_name));
+
+	pic_add(&dic->sc_pic, 0);
+
+	enable_interrupts(I32_bit|F32_bit);
+}
+
+void
+dic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
+{
+	struct dic_softc * const dic = PIC_TO_SOFTC(pic);
+	size_t group = irq_base / 32;
+
+	DIC_WRITE(dic, DIC_ENSET(group), irq_mask);
+}
+
+void
+dic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
+{
+	struct dic_softc * const dic = PIC_TO_SOFTC(pic);
+	size_t group = irq_base / 32;
+
+	DIC_WRITE(dic, DIC_ENCLEAR(group), irq_mask);
+}
+
+static __inline u_int
+my_core_id(void)
+{
+	uint32_t id;
+
+	__asm ("mrc p15, 0, %0, c0, c0, 5" : "=r" (id));
+
+	return id & 0x0f;
+}
+
+static void
+dic_establish_irq(struct pic_softc *pic, struct intrsource *is)
+{
+	struct dic_softc * const dic = PIC_TO_SOFTC(pic);
+	int irq = is->is_irq;
+	int shift;
+	int group;
+	uint32_t reg;
+
+	KASSERT(irq < dic->sc_nsrcs);
+	KASSERT(is->is_ipl < 16);
+
+#ifdef	NO_DIC_INITIALIZE
+	/*
+	 * DIC is configured by the firmware.
+	 * don't change the settings.
+	 */
+#else
+
+	group = irq / 4;
+	shift = (irq % 4) * 8 + 4;
+	reg = DIC_READ(dic, DIC_PRIORITY(group));
+	reg &= ~(0xf << shift);
+	reg |= SW_TO_HW_IPL(is->is_ipl) << shift;
+	DIC_WRITE(dic, DIC_PRIORITY(group), reg);
+
+	/* edge or level triggered.
+	 * always use 1-N interrupt software model.
+	 * XXX: limited to high-level or rising-edege trigger.
+	 */
+	shift = (irq % 16) * 2;
+	group = (irq / 16);
+	reg = DIC_READ(dic, DIC_CONFIG(group));
+	reg &= ~(0x03 << shift);
+	if (is->is_type == IST_EDGE)
+		reg |= 0x01 << shift;
+	else
+		reg |= 0x03 << shift;
+	DIC_WRITE(dic, DIC_CONFIG(group), reg);
+
+	group = irq / 4;
+	shift = (irq % 4) * 8;
+
+	reg = DIC_READ(dic, DIC_TARGET(group));
+	reg &= ~(0x0f << shift);
+#ifdef	MULTIPROCESSOR
+#error	not yet.
+#else
+	reg |= 1 << (my_core_id() + shift);
+#endif
+	DIC_WRITE(dic, DIC_TARGET(group), reg);
+
+#endif	/* NO_DIC_INITIALIZE */
+
+	/* enable the interrupt */
+	group = irq / 32;
+	DIC_WRITE(dic, DIC_ENSET(group), 1 << (irq % 32));
+}
+
+void
+mpcore_irq_handler(void *frame)
+{
+	struct cpu_info * const ci = curcpu();
+	int irq;
+	uint32_t reg, intack;
+
+	ci->ci_data.cpu_nintr++;
+
+	for (;;) {
+		struct intrsource *is;
+		
+		intack = CII_READ(dic_softc, CII_INTACK);
+		irq = intack & CII_INTACK_INTID_MASK;
+
+		if (irq == 1023)	/* spurious */
+			break;
+
+		reg = CII_READ(dic_softc, CII_RUNPRI);
+		CII_WRITE(dic_softc, CII_PRIMASK, reg);
+		
+		is = dic_softc->sc_pic.pic_sources[irq];
+		if (__predict_true(is != NULL)) {
+			int oldipl = ci->ci_cpl;
+			ci->ci_cpl = HW_TO_SW_IPL((reg & CII_PRIMASK_MASK)
+			    >> CII_PRIMASK_SHIFT);
+
+			cpsie(I32_bit);
+			pic_dispatch(is, frame);
+			cpsid(I32_bit);
+
+			ci->ci_cpl = oldipl;
+			CII_WRITE(dic_softc, CII_PRIMASK, 
+			    SW_TO_HW_IPL(oldipl) << CII_PRIMASK_SHIFT);
+		}
+		CII_WRITE(dic_softc, CII_EOI, intack);
+	}
+
+
+#ifdef	DIC_CASCADED_IRQ
+	/* handle cascaded interrupts through PIC framework */
+	pic_do_pending_ints(I32_bit, ci->ci_cpl, frame);
+#endif
+}
+
+
+int
+_splraise(int newipl)
+{
+	struct cpu_info * const ci = curcpu();
+	const int oldipl = ci->ci_cpl;
+	KASSERT(newipl < NIPL);
+	if (newipl > ci->ci_cpl) {
+		register_t psw = disable_interrupts(I32_bit);
+		ci->ci_cpl = newipl;
+		CII_WRITE(dic_softc, CII_PRIMASK, 
+		    SW_TO_HW_IPL(newipl) << CII_PRIMASK_SHIFT);
+		restore_interrupts(psw);
+	}
+
+	return oldipl;
+}
+int
+_spllower(int newipl)
+{
+	struct cpu_info * const ci = curcpu();
+	const int oldipl = ci->ci_cpl;
+	KASSERT(panicstr || newipl <= ci->ci_cpl);
+	if (newipl < ci->ci_cpl) {
+		register_t psw = disable_interrupts(I32_bit);
+		CII_WRITE(dic_softc, CII_PRIMASK, 
+		    SW_TO_HW_IPL(newipl) << CII_PRIMASK_SHIFT);
+		pic_do_pending_ints(psw, newipl, NULL);
+		restore_interrupts(psw);
+	}
+	return oldipl;
+}
+
+void
+splx(int savedipl)
+{
+	struct cpu_info * const ci = curcpu();
+	KASSERT(savedipl < NIPL);
+	if (savedipl < ci->ci_cpl) {
+		register_t psw = disable_interrupts(I32_bit);
+		CII_WRITE(dic_softc, CII_PRIMASK, 
+		    SW_TO_HW_IPL(savedipl) << CII_PRIMASK_SHIFT);
+#ifdef	DIC_CASCADED_IRQ
+		pic_do_pending_ints(psw, savedipl, NULL);
+#endif
+		restore_interrupts(psw);
+	}
+	ci->ci_cpl = savedipl;
+}
Index: src/sys/arch/arm/mpcore/dic_intr.h
diff -u /dev/null src/sys/arch/arm/mpcore/dic_intr.h:1.1
--- /dev/null	Fri Mar 11 03:26:37 2011
+++ src/sys/arch/arm/mpcore/dic_intr.h	Fri Mar 11 03:26:37 2011
@@ -0,0 +1,49 @@
+/*	$NetBSD: dic_intr.h,v 1.1 2011/03/11 03:26:37 bsh Exp $ */
+
+/*
+ * Copyright (c) 2010, 2011 Genetec Corporation.  All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_MPCORE_DIC_INTR_H
+#define _ARM_MPCORE_DIC_INTR_H
+
+#ifndef	ARM_IRQ_HANDLER
+#define	ARM_IRQ_HANDLER	_C_LABEL(mpcore_irq_handler)
+#endif
+
+#ifndef	PIC_MAXMAXSOURCES
+#define	PIC_MAXMAXSOURCES	(256 + 64)
+#endif
+
+#ifndef	_LOCORE
+int _splraise(int);
+int _spllower(int);
+void splx(int);
+
+void mpcore_irq_handler(void *);
+
+#endif	/* !_LOCORE */
+
+#endif	/* _ARM_MPCORE_DIC_INTR_H */
Index: src/sys/arch/arm/mpcore/dicreg.h
diff -u /dev/null src/sys/arch/arm/mpcore/dicreg.h:1.1
--- /dev/null	Fri Mar 11 03:26:37 2011
+++ src/sys/arch/arm/mpcore/dicreg.h	Fri Mar 11 03:26:37 2011
@@ -0,0 +1,89 @@
+/*	$NetBSD: dicreg.h,v 1.1 2011/03/11 03:26:37 bsh Exp $ */
+
+/*
+ * Copyright (c) 2010, 2011 Genetec Corporation.  All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_MPCORE_DICREG_H
+#define _ARM_MPCORE_DICREG_H
+
+#include <sys/cdefs.h>
+
+/*
+ * CPU Interrupt Interface Registers (per core)
+ */
+#define	CII_CONTROL	0x00
+#define	 CII_CONTROL_ENABLE	__BIT(0)
+
+#define	CII_PRIMASK	0x04
+#define	 CII_PRIMASK_SHIFT	4
+#define	 CII_PRIMASK_MASK 	__BITS(CII_PRIMASK_SHIFT, 7)
+#define	 CII_PRIMASK_MASKALL	(0 << CII_PRIMASK_SHIFT)
+#define	 CII_PRIMASK_MASKNONE	(0x0f << CII_PRIMASK_SHIFT)
+/* NOTE: interrupt level 15 is always masked. */
+
+
+#define	CII_BINPOINT	0x08
+
+#define	CII_INTACK	0x0c
+#define	 CII_INTACK_CPUSRC_SHIFT	10
+#define	 CII_INTACK_CPUSRC_MASK  	__BITS(CII_INTACK_CPUSRC_SHIFT, 12)
+#define	 CII_INTACK_INTID_SHIFT  	0
+#define	 CII_INTACK_INTID_MASK  	__BITS(CII_INTACK_INTID_SHIFT, 9)
+
+#define	CII_EOI  	0x10
+
+#define	CII_RUNPRI	0x14	/* Running Priority */
+
+#define	CII_PENDPRI	0x18	/* highest Pending Interrupt */ 
+
+/*
+ * Interrupt Disctibutor (global)
+ */
+#define	DIC_CONTROL	0x000
+#define	 DIC_CONTROL_ENABLE	__BIT(0)
+
+#define	DIC_TYPE	0x004
+#define	 DIC_TYPE_NCPUS_SHIFT	5
+#define	 DIC_TYPE_NCPUS_MASK	__BITS(DIC_TYPE_NCPUS_SHIFT,7)
+#define	 DIC_TYPE_NLINES_SHIFT	0
+#define	 DIC_TYPE_NLINES_MASK	__BITS(DIC_TYPE_NLINES_SHIFT,4)
+
+#define	DIC_ENSET(n)		(0x100 + (n)*sizeof (uint32_t))	/* n: 0..7 */
+#define	DIC_ENCLEAR(n)		(0x180 + (n)*sizeof (uint32_t))
+#define	DIC_PENDSET(n)  	(0x200 + (n)*sizeof (uint32_t))
+#define	DIC_PENDCLEAR(n)	(0x280 + (n)*sizeof (uint32_t))
+#define	DIC_ACTIVE(n)		(0x300 + (n)*sizeof (uint32_t))
+
+#define	DIC_PRIORITY(n)  	(0x400 + (n)*sizeof (uint32_t))	/* n: 0..63 */
+#define	DIC_TARGET(n)		(0x800 + (n)*sizeof (uint32_t))
+
+#define	DIC_CONFIG(n)		(0xc00 + (n)*sizeof (uint32_t))	/* n: 0..15 */
+
+#define	DIC_LINELEVEL(n)	(0xd00 + (n)*sizeof (uint32_t))
+
+#define	DIC_SOFTINT	0xf00
+
+#endif	/* _ARM_MPCORE_DICREG_H */

Reply via email to