NetBSD/sys/arch/sh5/dev/intc.c
scw 89612efe30 Interrupt overhaul:
- Allocate interrupt handles dynamically from a pool(9) to reduce the
   number of TLB misses during interrupt dispatch.
 - Fully support evcnt(9) in all interrupt dispatchers.
2002-10-14 14:19:27 +00:00

238 lines
7.4 KiB
C

/* $NetBSD: intc.c,v 1.8 2002/10/14 14:19:27 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
* 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.
*/
/*
* SH-5 Interrupt Controller
*/
#include "opt_sh5_intc.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <sh5/dev/pbridgevar.h>
#include <sh5/dev/intcvar.h>
#include <sh5/dev/intcreg.h>
/*
* Check the IRL mode setting, from the config file via opt_sh5_intc.h
*/
#ifdef SH5_INTC_IRL_MODE_INDEP
#ifdef SH5_INTC_IRL_MODE_LEVEL
#error "Only one of SH5_INTC_IRL_MODE_INDEP and SH5_INTC_IRL_MODE_INDEP should be defined"
#endif
#else
#ifndef SH5_INTC_IRL_MODE_LEVEL
/*
* Default to Independent Mode if no option specified
*/
#define SH5_INTC_IRL_MODE_INDEP
#endif
#endif
static int intcmatch(struct device *, struct cfdata *, void *);
static void intcattach(struct device *, struct device *, void *);
CFATTACH_DECL(intc, sizeof(struct intc_softc),
intcmatch, intcattach, NULL, NULL);
extern struct cfdriver intc_cd;
static void intc_enable(void *, u_int, int, int);
static void intc_disable(void *, u_int);
static int8_t intevt2inum[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, /* 0x000 - 0x0e0 */
-1, -1, -1, -1, -1, -1, -1, -1, /* 0x100 - 0x1e0 */
-1, -1, /* 0x200 - 0x220 */
INTC_INUM_IRL0, /* 0x240 */
-1, -1, /* 0x260 - 0x280 */
INTC_INUM_IRL1, /* 0x2a0 */
-1, -1, /* 0x2c0 - 0x2e0 */
INTC_INUM_IRL2, /* 0x300 */
-1, -1, /* 0x320 - 0x340 */
INTC_INUM_IRL3, /* 0x360 */
-1, -1, -1, -1, /* 0x380 - 0x3e0 */
INTC_INUM_TMU_TUNI0, INTC_INUM_TMU_TUNI1, /* 0x400 - 0x420 */
INTC_INUM_TMU_TUNI2, INTC_INUM_TMU_TICPI2, /* 0x440 - 0x460 */
INTC_INUM_RTC_ATI, INTC_INUM_RTC_PRI, /* 0x480 - 0x4a0 */
INTC_INUM_RTC_CUI, /* 0x4c0 */
-1, -1, -1, -1, /* 0x4e0 - 0x540 */
INTC_INUM_WDT_ITI, /* 0x560 */
-1, -1, -1, -1, -1, -1, /* 0x580 - 0x620 */
INTC_INUM_DMAC_DMTE0, INTC_INUM_DMAC_DMTE1, /* 0x640 - 0x660 */
INTC_INUM_DMAC_DMTE2, INTC_INUM_DMAC_DMTE3, /* 0x680 - 0x6a0 */
INTC_INUM_DMAC_DAERR, /* 0x6c0 */
-1, /* 0x6e0 */
INTC_INUM_SCIF_ERI, INTC_INUM_SCIF_RXI, /* 0x700 - 0x720 */
INTC_INUM_SCIF_BRI, INTC_INUM_SCIF_TXI, /* 0x740 - 0x760 */
-1, -1, -1, -1, /* 0x780 - 0x7e0 */
INTC_INUM_PCI_INTA, INTC_INUM_PCI_INTB, /* 0x800 - 0x820 */
INTC_INUM_PCI_INTC, INTC_INUM_PCI_INTD, /* 0x840 - 0x860 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x880 - 0x9e0 */
INTC_INUM_PCI_SERR, INTC_INUM_PCI_ERR, /* 0xa00 - 0xa20 */
INTC_INUM_PCI_PWR3, INTC_INUM_PCI_PWR2, /* 0xa40 - 0xa60 */
INTC_INUM_PCI_PWR1, INTC_INUM_PCI_PWR0, /* 0xa80 - 0xaa0 */
-1, -1, /* 0xac0 - 0xae0 */
/* 0xb00 - 0x1fe0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1
};
/*ARGSUSED*/
static int
intcmatch(struct device *parent, struct cfdata *cf, void *args)
{
struct pbridge_attach_args *pa = args;
return (strcmp(pa->pa_name, intc_cd.cd_name) == 0);
}
/*ARGSUSED*/
static void
intcattach(struct device *parent, struct device *self, void *args)
{
struct pbridge_attach_args *pa = args;
struct intc_softc *sc = (struct intc_softc *)self;
sc->sc_bust = pa->pa_bust;
bus_space_map(sc->sc_bust, pa->pa_offset, INTC_REG_SIZE,0,&sc->sc_bush);
intc_reg_write(sc, INTC_REG_INTDISB(0x00), INTC_INTDISB_ALL);
intc_reg_write(sc, INTC_REG_INTDISB(0x20), INTC_INTDISB_ALL);
intc_reg_write(sc, INTC_REG_INTPRI(0x00), 0);
intc_reg_write(sc, INTC_REG_INTPRI(0x20), 0);
#ifdef SH5_INTC_IRL_MODE_INDEP
intc_reg_write(sc, INTC_REG_ICR_SET, INTC_ICR_SET_IRL_MODE_INDEP);
#else
intc_reg_write(sc, INTC_REG_ICR_CLEAR, INTC_ICR_CLEAR_IRL_MODE_LEVEL);
#endif
sh5_intr_init(intc_enable, intc_disable, sc);
printf(": Interrupt Controller\n");
}
static void
intc_enable(void *arg, u_int intevt, int trigger, int level)
{
struct intc_softc *sc = arg;
u_int32_t reg;
int inum;
int s;
KDASSERT(trigger == IST_LEVEL);
KDASSERT(level > 0 && level < NIPL);
intevt >>= 5;
#ifdef DEBUG
if (intevt >= 0x100 || intevt2inum[intevt] < 0)
panic("intc_enable: Invalid INTEVT: 0x%x", intevt << 5);
#endif
inum = intevt2inum[intevt];
s = splhigh();
/*
* Program the priority for this interrupt
*/
reg = intc_reg_read(sc, INTC_REG_INTPRI(inum));
reg &= ~(INTC_INTPRI_MASK << INTC_INTPRI_SHIFT(inum));
reg |= level << INTC_INTPRI_SHIFT(inum);
intc_reg_write(sc, INTC_REG_INTPRI(inum), reg);
/*
* Enable the interrupt
*/
intc_reg_write(sc, INTC_REG_INTENB(inum), INTC_INTENB_BIT(inum));
splx(s);
}
static void
intc_disable(void *arg, u_int intevt)
{
struct intc_softc *sc = arg;
u_int32_t reg;
int inum;
int s;
intevt >>= 5;
#ifdef DEBUG
if (intevt >= 0x100 || intevt2inum[intevt] < 0)
panic("intc_disable: Invalid INTEVT: 0x%x", intevt << 5);
#endif
s = splhigh();
inum = intevt2inum[intevt];
/*
* Disable the interrupt
*/
intc_reg_write(sc, INTC_REG_INTDISB(inum), INTC_INTDISB_BIT(inum));
/*
* Set the priority to zero
*/
reg = intc_reg_read(sc, INTC_REG_INTPRI(inum));
reg &= ~(INTC_INTPRI_MASK << INTC_INTPRI_SHIFT(inum));
intc_reg_write(sc, INTC_REG_INTPRI(inum), reg);
splx(s);
}