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 */