xref: /netbsd-src/sys/arch/arm/xscale/ixp425_intr.c (revision cf0030cb2878780138a787886514b97c57932329)
1*cf0030cbSthorpej /*	$NetBSD: ixp425_intr.c,v 1.28 2020/11/20 18:49:45 thorpej Exp $ */
200eb02e3Sichiro 
300eb02e3Sichiro /*
400eb02e3Sichiro  * Copyright (c) 2003
500eb02e3Sichiro  *	Ichiro FUKUHARA <ichiro@ichiro.org>.
600eb02e3Sichiro  * All rights reserved.
700eb02e3Sichiro  *
800eb02e3Sichiro  * Redistribution and use in source and binary forms, with or without
900eb02e3Sichiro  * modification, are permitted provided that the following conditions
1000eb02e3Sichiro  * are met:
1100eb02e3Sichiro  * 1. Redistributions of source code must retain the above copyright
1200eb02e3Sichiro  *    notice, this list of conditions and the following disclaimer.
1300eb02e3Sichiro  * 2. Redistributions in binary form must reproduce the above copyright
1400eb02e3Sichiro  *    notice, this list of conditions and the following disclaimer in the
1500eb02e3Sichiro  *    documentation and/or other materials provided with the distribution.
1600eb02e3Sichiro  *
1700eb02e3Sichiro  * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR
1800eb02e3Sichiro  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1900eb02e3Sichiro  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2000eb02e3Sichiro  * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
2100eb02e3Sichiro  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2200eb02e3Sichiro  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2300eb02e3Sichiro  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2400eb02e3Sichiro  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2500eb02e3Sichiro  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2600eb02e3Sichiro  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2700eb02e3Sichiro  * SUCH DAMAGE.
2800eb02e3Sichiro  */
2900eb02e3Sichiro /*
3000eb02e3Sichiro  * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
3100eb02e3Sichiro  * All rights reserved.
3200eb02e3Sichiro  *
3300eb02e3Sichiro  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
3400eb02e3Sichiro  *
3500eb02e3Sichiro  * Redistribution and use in source and binary forms, with or without
3600eb02e3Sichiro  * modification, are permitted provided that the following conditions
3700eb02e3Sichiro  * are met:
3800eb02e3Sichiro  * 1. Redistributions of source code must retain the above copyright
3900eb02e3Sichiro  *    notice, this list of conditions and the following disclaimer.
4000eb02e3Sichiro  * 2. Redistributions in binary form must reproduce the above copyright
4100eb02e3Sichiro  *    notice, this list of conditions and the following disclaimer in the
4200eb02e3Sichiro  *    documentation and/or other materials provided with the distribution.
4300eb02e3Sichiro  * 3. All advertising materials mentioning features or use of this software
4400eb02e3Sichiro  *    must display the following acknowledgement:
4500eb02e3Sichiro  *      This product includes software developed for the NetBSD Project by
4600eb02e3Sichiro  *      Wasabi Systems, Inc.
4700eb02e3Sichiro  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
4800eb02e3Sichiro  *    or promote products derived from this software without specific prior
4900eb02e3Sichiro  *    written permission.
5000eb02e3Sichiro  *
5100eb02e3Sichiro  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
5200eb02e3Sichiro  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
5300eb02e3Sichiro  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
5400eb02e3Sichiro  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
5500eb02e3Sichiro  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5600eb02e3Sichiro  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5700eb02e3Sichiro  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5800eb02e3Sichiro  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5900eb02e3Sichiro  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
6000eb02e3Sichiro  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6100eb02e3Sichiro  * POSSIBILITY OF SUCH DAMAGE.
6200eb02e3Sichiro  */
6300eb02e3Sichiro 
6400eb02e3Sichiro #include <sys/cdefs.h>
65*cf0030cbSthorpej __KERNEL_RCSID(0, "$NetBSD: ixp425_intr.c,v 1.28 2020/11/20 18:49:45 thorpej Exp $");
6600eb02e3Sichiro 
6700eb02e3Sichiro #ifndef EVBARM_SPL_NOINLINE
6800eb02e3Sichiro #define	EVBARM_SPL_NOINLINE
6900eb02e3Sichiro #endif
7000eb02e3Sichiro 
7100eb02e3Sichiro /*
7200eb02e3Sichiro  * Interrupt support for the Intel IXP425 NetworkProcessor.
7300eb02e3Sichiro  */
7400eb02e3Sichiro 
7500eb02e3Sichiro #include <sys/param.h>
7600eb02e3Sichiro #include <sys/systm.h>
77*cf0030cbSthorpej #include <sys/kmem.h>
7800eb02e3Sichiro 
79ed9977b1Sdyoung #include <sys/bus.h>
8000eb02e3Sichiro #include <machine/intr.h>
8100eb02e3Sichiro 
8200eb02e3Sichiro #include <arm/cpufunc.h>
8300eb02e3Sichiro 
8400eb02e3Sichiro #include <arm/xscale/ixp425reg.h>
8500eb02e3Sichiro #include <arm/xscale/ixp425var.h>
8600eb02e3Sichiro 
8700eb02e3Sichiro /* Interrupt handler queues. */
8800eb02e3Sichiro struct intrq intrq[NIRQ];
8900eb02e3Sichiro 
9000eb02e3Sichiro /* Interrupts to mask at each level. */
9100eb02e3Sichiro int ixp425_imask[NIPL];
9200eb02e3Sichiro 
9300eb02e3Sichiro /* Interrupts pending. */
945f1c88d7Sperry volatile int ixp425_ipending;
9500eb02e3Sichiro 
9600eb02e3Sichiro /* Software copy of the IRQs we have enabled. */
975f1c88d7Sperry volatile uint32_t intr_enabled;
9800eb02e3Sichiro 
9900eb02e3Sichiro /* Mask if interrupts steered to FIQs. */
10000eb02e3Sichiro uint32_t intr_steer;
10100eb02e3Sichiro 
1026bc0c582Smatt #ifdef __HAVE_FAST_SOFTINTS
10300eb02e3Sichiro /*
10400eb02e3Sichiro  * Map a software interrupt queue index
105a402937cSscw  *
106a402937cSscw  * XXX: !NOTE! :XXX
107a402937cSscw  * We 'borrow' bits from the interrupt status register for interrupt sources
108a402937cSscw  * which are not used by the current IXP425 port. Should any of the following
109a402937cSscw  * interrupt sources be used at some future time, this must be revisited.
110a402937cSscw  *
111a402937cSscw  *  Bit#31: SW Interrupt 1
112a402937cSscw  *  Bit#30: SW Interrupt 0
113a402937cSscw  *  Bit#14: Timestamp Timer
114a402937cSscw  *  Bit#11: General-purpose Timer 1
115a402937cSscw  */
11600eb02e3Sichiro static const uint32_t si_to_irqbit[SI_NQUEUES] = {
11700eb02e3Sichiro 	IXP425_INT_bit31,		/* SI_SOFT */
11800eb02e3Sichiro 	IXP425_INT_bit30,		/* SI_SOFTCLOCK */
119a402937cSscw 	IXP425_INT_bit14,		/* SI_SOFTNET */
120a402937cSscw 	IXP425_INT_bit11,		/* SI_SOFTSERIAL */
12100eb02e3Sichiro };
12200eb02e3Sichiro 
12300eb02e3Sichiro #define	SI_TO_IRQBIT(si)	(1U << si_to_irqbit[(si)])
12400eb02e3Sichiro 
12500eb02e3Sichiro /*
12600eb02e3Sichiro  * Map a software interrupt queue to an interrupt priority level.
12700eb02e3Sichiro  */
1286bc0c582Smatt static const int si_to_ipl[] = {
1296bc0c582Smatt 	[SI_SOFTCLOCK] =	IPL_SOFTCLOCK,
1306bc0c582Smatt 	[SI_SOFTBIO] =		IPL_SOFTBIO,
1316bc0c582Smatt 	[SI_SOFTNET] =		IPL_SOFTNET,
1326bc0c582Smatt 	[SI_SOFTSERIAL] =	IPL_SOFTSERIAL,
13300eb02e3Sichiro };
1346bc0c582Smatt #endif /* __HAVE_FAST_SOFTINTS */
13500eb02e3Sichiro void	ixp425_intr_dispatch(struct clockframe *frame);
13600eb02e3Sichiro 
1375f1c88d7Sperry static inline uint32_t
ixp425_irq_read(void)13800eb02e3Sichiro ixp425_irq_read(void)
13900eb02e3Sichiro {
14000eb02e3Sichiro 	return IXPREG(IXP425_INT_STATUS) & intr_enabled;
14100eb02e3Sichiro }
14200eb02e3Sichiro 
1435f1c88d7Sperry static inline void
ixp425_set_intrsteer(void)14400eb02e3Sichiro ixp425_set_intrsteer(void)
14500eb02e3Sichiro {
14600eb02e3Sichiro 	IXPREG(IXP425_INT_SELECT) = intr_steer & IXP425_INT_HWMASK;
14700eb02e3Sichiro }
14800eb02e3Sichiro 
1495f1c88d7Sperry static inline void
ixp425_enable_irq(int irq)15000eb02e3Sichiro ixp425_enable_irq(int irq)
15100eb02e3Sichiro {
15200eb02e3Sichiro 
15300eb02e3Sichiro 	intr_enabled |= (1U << irq);
15400eb02e3Sichiro 	ixp425_set_intrmask();
15500eb02e3Sichiro }
15600eb02e3Sichiro 
1575f1c88d7Sperry static inline void
ixp425_disable_irq(int irq)15800eb02e3Sichiro ixp425_disable_irq(int irq)
15900eb02e3Sichiro {
16000eb02e3Sichiro 
16100eb02e3Sichiro 	intr_enabled &= ~(1U << irq);
16200eb02e3Sichiro 	ixp425_set_intrmask();
16300eb02e3Sichiro }
16400eb02e3Sichiro 
16508a4aba7Sskrll static inline uint32_t
ixp425_irq2gpio_bit(int irq)166fb2c5211Sscw ixp425_irq2gpio_bit(int irq)
167fb2c5211Sscw {
168fb2c5211Sscw 
16908a4aba7Sskrll 	static const uint8_t int2gpio[32] __attribute__ ((aligned(32))) = {
170fb2c5211Sscw 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* INT#0 -> INT#5 */
171fb2c5211Sscw 		0x00, 0x01,				/* GPIO#0 -> GPIO#1 */
172fb2c5211Sscw 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* INT#8 -> INT#13 */
173fb2c5211Sscw 		0xff, 0xff, 0xff, 0xff, 0xff,		/* INT#14 -> INT#18 */
174fb2c5211Sscw 		0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* GPIO#2 -> GPIO#7 */
175fb2c5211Sscw 		0x08, 0x09, 0x0a, 0x0b, 0x0c,		/* GPIO#8 -> GPIO#12 */
176fb2c5211Sscw 		0xff, 0xff				/* INT#30 -> INT#31 */
177fb2c5211Sscw 	};
178fb2c5211Sscw 
179fb2c5211Sscw #ifdef DEBUG
180fb2c5211Sscw 	if (int2gpio[irq] == 0xff)
181fb2c5211Sscw 		panic("ixp425_irq2gpio_bit: bad GPIO irq: %d\n", irq);
182fb2c5211Sscw #endif
183fb2c5211Sscw 	return (1U << int2gpio[irq]);
184fb2c5211Sscw }
185fb2c5211Sscw 
18600eb02e3Sichiro /*
18700eb02e3Sichiro  * NOTE: This routine must be called with interrupts disabled in the CPSR.
18800eb02e3Sichiro  */
18900eb02e3Sichiro static void
ixp425_intr_calculate_masks(void)19000eb02e3Sichiro ixp425_intr_calculate_masks(void)
19100eb02e3Sichiro {
19200eb02e3Sichiro 	struct intrq *iq;
19300eb02e3Sichiro 	struct intrhand *ih;
19400eb02e3Sichiro 	int irq, ipl;
19500eb02e3Sichiro 
19600eb02e3Sichiro 	/* First, figure out which IPLs each IRQ has. */
19700eb02e3Sichiro 	for (irq = 0; irq < NIRQ; irq++) {
19800eb02e3Sichiro 		int levels = 0;
19900eb02e3Sichiro 		iq = &intrq[irq];
20000eb02e3Sichiro 		ixp425_disable_irq(irq);
20100eb02e3Sichiro 		for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
20200eb02e3Sichiro 		     ih = TAILQ_NEXT(ih, ih_list))
20300eb02e3Sichiro 			levels |= (1U << ih->ih_ipl);
20400eb02e3Sichiro 		iq->iq_levels = levels;
20500eb02e3Sichiro 	}
20600eb02e3Sichiro 
20700eb02e3Sichiro 	/* Next, figure out which IRQs are used by each IPL. */
20800eb02e3Sichiro 	for (ipl = 0; ipl < NIPL; ipl++) {
20900eb02e3Sichiro 		int irqs = 0;
21000eb02e3Sichiro 		for (irq = 0; irq < NIRQ; irq++) {
21100eb02e3Sichiro 			if (intrq[irq].iq_levels & (1U << ipl))
21200eb02e3Sichiro 				irqs |= (1U << irq);
21300eb02e3Sichiro 		}
21400eb02e3Sichiro 		ixp425_imask[ipl] = irqs;
21500eb02e3Sichiro 	}
21600eb02e3Sichiro 
2176bc0c582Smatt 	KASSERT(ixp425_imask[IPL_NONE] == 0);
21800eb02e3Sichiro 
2196bc0c582Smatt #ifdef __HAVE_FAST_SOFTINTS
22000eb02e3Sichiro 	/*
22100eb02e3Sichiro 	 * Initialize the soft interrupt masks to block themselves.
22200eb02e3Sichiro 	 */
22300eb02e3Sichiro 	ixp425_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTCLOCK);
2244b293a84Sad 	ixp425_imask[IPL_SOFTBIO] = SI_TO_IRQBIT(SI_SOFTBIO);
22500eb02e3Sichiro 	ixp425_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTNET);
22600eb02e3Sichiro 	ixp425_imask[IPL_SOFTSERIAL] = SI_TO_IRQBIT(SI_SOFTSERIAL);
227be8e5859Stsutsui #else
228be8e5859Stsutsui 	KASSERT(ixp425_imask[IPL_SOFTCLOCK] == 0);
229be8e5859Stsutsui 	KASSERT(ixp425_imask[IPL_SOFTBIO] == 0);
230be8e5859Stsutsui 	KASSERT(ixp425_imask[IPL_SOFTNET] == 0);
231be8e5859Stsutsui 	KASSERT(ixp425_imask[IPL_SOFTSERIAL] == 0);
2326bc0c582Smatt #endif
23300eb02e3Sichiro 
23400eb02e3Sichiro 	/*
235d6a98601Swiz 	 * Enforce a hierarchy that gives "slow" device (or devices with
23600eb02e3Sichiro 	 * limited input buffer space/"real-time" requirements) a better
23700eb02e3Sichiro 	 * chance at not dropping data.
23800eb02e3Sichiro 	 */
2394b293a84Sad 	ixp425_imask[IPL_SCHED] |= ixp425_imask[IPL_VM];
2404b293a84Sad 	ixp425_imask[IPL_HIGH] |= ixp425_imask[IPL_SCHED];
24100eb02e3Sichiro 
24200eb02e3Sichiro 	/*
24300eb02e3Sichiro 	 * Now compute which IRQs must be blocked when servicing any
24400eb02e3Sichiro 	 * given IRQ.
24500eb02e3Sichiro 	 */
24600eb02e3Sichiro 	for (irq = 0; irq < NIRQ; irq++) {
24700eb02e3Sichiro 		int irqs = (1U << irq);
24800eb02e3Sichiro 		iq = &intrq[irq];
24900eb02e3Sichiro 		if (TAILQ_FIRST(&iq->iq_list) != NULL)
25000eb02e3Sichiro 			ixp425_enable_irq(irq);
25100eb02e3Sichiro 		for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
25200eb02e3Sichiro 		     ih = TAILQ_NEXT(ih, ih_list))
25300eb02e3Sichiro 			irqs |= ixp425_imask[ih->ih_ipl];
25400eb02e3Sichiro 		iq->iq_mask = irqs;
25500eb02e3Sichiro 	}
25600eb02e3Sichiro }
25700eb02e3Sichiro 
25800eb02e3Sichiro void
splx(int new)25900eb02e3Sichiro splx(int new)
26000eb02e3Sichiro {
26100eb02e3Sichiro 	ixp425_splx(new);
26200eb02e3Sichiro }
26300eb02e3Sichiro 
26400eb02e3Sichiro int
_spllower(int ipl)26500eb02e3Sichiro _spllower(int ipl)
26600eb02e3Sichiro {
26700eb02e3Sichiro 	return (ixp425_spllower(ipl));
26800eb02e3Sichiro }
26900eb02e3Sichiro 
27000eb02e3Sichiro int
_splraise(int ipl)27100eb02e3Sichiro _splraise(int ipl)
27200eb02e3Sichiro {
27300eb02e3Sichiro 	return (ixp425_splraise(ipl));
27400eb02e3Sichiro }
27500eb02e3Sichiro 
27600eb02e3Sichiro /*
27700eb02e3Sichiro  * ixp425_icu_init:
27800eb02e3Sichiro  *
27900eb02e3Sichiro  * 	Called early in bootstrap to make clear interrupt register
28000eb02e3Sichiro  */
28100eb02e3Sichiro void
ixp425_icu_init(void)28200eb02e3Sichiro ixp425_icu_init(void)
28300eb02e3Sichiro {
28400eb02e3Sichiro 
28500eb02e3Sichiro 	intr_enabled = 0;	/* All interrupts disabled */
28600eb02e3Sichiro 	ixp425_set_intrmask();
28700eb02e3Sichiro 
28800eb02e3Sichiro 	intr_steer = 0;		/* All interrupts steered to IRQ */
28900eb02e3Sichiro 	ixp425_set_intrsteer();
29000eb02e3Sichiro }
29100eb02e3Sichiro 
29200eb02e3Sichiro /*
29300eb02e3Sichiro  * ixp425_intr_init:
29400eb02e3Sichiro  *
29500eb02e3Sichiro  *	Initialize the rest of the interrupt subsystem, making it
29600eb02e3Sichiro  *	ready to handle interrupts from devices.
29700eb02e3Sichiro  */
29800eb02e3Sichiro void
ixp425_intr_init(void)29900eb02e3Sichiro ixp425_intr_init(void)
30000eb02e3Sichiro {
30100eb02e3Sichiro 	struct intrq *iq;
30200eb02e3Sichiro 	int i;
30300eb02e3Sichiro 
30400eb02e3Sichiro 	intr_enabled = 0;
30500eb02e3Sichiro 
30600eb02e3Sichiro 	for (i = 0; i < NIRQ; i++) {
30700eb02e3Sichiro 		iq = &intrq[i];
30800eb02e3Sichiro 		TAILQ_INIT(&iq->iq_list);
30900eb02e3Sichiro 
310d02e70faSchristos 		snprintf(iq->iq_name, sizeof(iq->iq_name), "irq %d", i);
31100eb02e3Sichiro 	}
31200eb02e3Sichiro 
31300eb02e3Sichiro 	ixp425_intr_calculate_masks();
31400eb02e3Sichiro 
31500eb02e3Sichiro 	/* Enable IRQs (don't yet use FIQs). */
31600eb02e3Sichiro 	enable_interrupts(I32_bit);
31700eb02e3Sichiro }
31800eb02e3Sichiro 
31982faf916Sryo void
ixp425_intr_evcnt_attach(void)32082faf916Sryo ixp425_intr_evcnt_attach(void)
32182faf916Sryo {
32282faf916Sryo 	struct intrq *iq;
32382faf916Sryo 	int i;
32482faf916Sryo 
32582faf916Sryo 	for (i = 0; i < NIRQ; i++) {
32682faf916Sryo 		iq = &intrq[i];
32782faf916Sryo 		evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
32882faf916Sryo 		    NULL, "ixp425", iq->iq_name);
32982faf916Sryo 	}
33082faf916Sryo }
33182faf916Sryo 
33200eb02e3Sichiro void *
ixp425_intr_establish(int irq,int ipl,int (* func)(void *),void * arg)33300eb02e3Sichiro ixp425_intr_establish(int irq, int ipl, int (*func)(void *), void *arg)
33400eb02e3Sichiro {
33500eb02e3Sichiro 	struct intrq *iq;
33600eb02e3Sichiro 	struct intrhand *ih;
33700eb02e3Sichiro 	u_int oldirqstate;
33800eb02e3Sichiro 
33900eb02e3Sichiro 	if (irq < 0 || irq > NIRQ)
34000eb02e3Sichiro 		panic("ixp425_intr_establish: IRQ %d out of range", irq);
34100eb02e3Sichiro #ifdef DEBUG
34200eb02e3Sichiro 	printf("ixp425_intr_establish(irq=%d, ipl=%d, func=%08x, arg=%08x)\n",
34308a4aba7Sskrll 	       irq, ipl, (uint32_t) func, (uint32_t) arg);
34400eb02e3Sichiro #endif
34500eb02e3Sichiro 
346*cf0030cbSthorpej 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
34700eb02e3Sichiro 	ih->ih_func = func;
34800eb02e3Sichiro 	ih->ih_arg = arg;
34900eb02e3Sichiro 	ih->ih_ipl = ipl;
35000eb02e3Sichiro 	ih->ih_irq = irq;
35100eb02e3Sichiro 
35200eb02e3Sichiro 	iq = &intrq[irq];
35300eb02e3Sichiro 
35400eb02e3Sichiro 	/* All IXP425 interrupts are level-triggered. */
35500eb02e3Sichiro 	iq->iq_ist = IST_LEVEL; /* XXX */
35600eb02e3Sichiro 
35700eb02e3Sichiro 	oldirqstate = disable_interrupts(I32_bit);
35800eb02e3Sichiro 
35900eb02e3Sichiro 	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
36000eb02e3Sichiro 
36100eb02e3Sichiro 	ixp425_intr_calculate_masks();
36200eb02e3Sichiro 
36300eb02e3Sichiro 	restore_interrupts(oldirqstate);
36400eb02e3Sichiro 
36500eb02e3Sichiro 	return (ih);
36600eb02e3Sichiro }
36700eb02e3Sichiro 
36800eb02e3Sichiro void
ixp425_intr_disestablish(void * cookie)36900eb02e3Sichiro ixp425_intr_disestablish(void *cookie)
37000eb02e3Sichiro {
37100eb02e3Sichiro 	struct intrhand *ih = cookie;
37200eb02e3Sichiro 	struct intrq *iq = &intrq[ih->ih_irq];
37300eb02e3Sichiro 	int oldirqstate;
37400eb02e3Sichiro 
37500eb02e3Sichiro 	oldirqstate = disable_interrupts(I32_bit);
37600eb02e3Sichiro 
37700eb02e3Sichiro 	TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
37800eb02e3Sichiro 
37900eb02e3Sichiro 	ixp425_intr_calculate_masks();
38000eb02e3Sichiro 
38100eb02e3Sichiro 	restore_interrupts(oldirqstate);
38200eb02e3Sichiro }
38300eb02e3Sichiro 
38400eb02e3Sichiro void
ixp425_intr_dispatch(struct clockframe * frame)38500eb02e3Sichiro ixp425_intr_dispatch(struct clockframe *frame)
38600eb02e3Sichiro {
38700eb02e3Sichiro 	struct intrq *iq;
38800eb02e3Sichiro 	struct intrhand *ih;
389825088edSmatt 	int oldirqstate, irq, ibit, hwpend;
390825088edSmatt 	struct cpu_info * const ci = curcpu();
391825088edSmatt 	const int ppl = ci->ci_cpl;
392825088edSmatt 	const uint32_t imask = ixp425_imask[ppl];
39300eb02e3Sichiro 
39400eb02e3Sichiro 	hwpend = ixp425_irq_read();
39500eb02e3Sichiro 
39600eb02e3Sichiro 	/*
39700eb02e3Sichiro 	 * Disable all the interrupts that are pending.  We will
39800eb02e3Sichiro 	 * reenable them once they are processed and not masked.
39900eb02e3Sichiro 	 */
40000eb02e3Sichiro 	intr_enabled &= ~hwpend;
40100eb02e3Sichiro 	ixp425_set_intrmask();
40200eb02e3Sichiro 
40300eb02e3Sichiro 	while (hwpend != 0) {
40400eb02e3Sichiro 		irq = ffs(hwpend) - 1;
40500eb02e3Sichiro 		ibit = (1U << irq);
40600eb02e3Sichiro 
40700eb02e3Sichiro 		hwpend &= ~ibit;
40800eb02e3Sichiro 
409825088edSmatt 		if (imask & ibit) {
41000eb02e3Sichiro 			/*
41100eb02e3Sichiro 			 * IRQ is masked; mark it as pending and check
41200eb02e3Sichiro 			 * the next one.  Note: the IRQ is already disabled.
41300eb02e3Sichiro 			 */
41400eb02e3Sichiro 			ixp425_ipending |= ibit;
41500eb02e3Sichiro 			continue;
41600eb02e3Sichiro 		}
41700eb02e3Sichiro 
41800eb02e3Sichiro 		ixp425_ipending &= ~ibit;
41900eb02e3Sichiro 
42000eb02e3Sichiro 		iq = &intrq[irq];
42100eb02e3Sichiro 		iq->iq_ev.ev_count++;
4226a66466fSmatt 		ci->ci_data.cpu_nintr++;
423fb2c5211Sscw 
424fb2c5211Sscw 		/* Clear down non-level triggered GPIO interrupts now */
425fb2c5211Sscw 		if ((ibit & IXP425_INT_GPIOMASK) && iq->iq_ist != IST_LEVEL) {
426fb2c5211Sscw 			IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) =
427fb2c5211Sscw 			    ixp425_irq2gpio_bit(irq);
428fb2c5211Sscw 		}
429fb2c5211Sscw 
430825088edSmatt 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
431825088edSmatt 			ci->ci_cpl = ih->ih_ipl;
43200eb02e3Sichiro 			oldirqstate = enable_interrupts(I32_bit);
4330047ff3fSscw 			(void) (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
43400eb02e3Sichiro 			restore_interrupts(oldirqstate);
435825088edSmatt 		}
43600eb02e3Sichiro 
437fb2c5211Sscw 		/* Clear down level triggered GPIO interrupts now */
438fb2c5211Sscw 		if ((ibit & IXP425_INT_GPIOMASK) && iq->iq_ist == IST_LEVEL) {
439fb2c5211Sscw 			IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) =
440fb2c5211Sscw 			    ixp425_irq2gpio_bit(irq);
441fb2c5211Sscw 		}
442fb2c5211Sscw 
443825088edSmatt 		ci->ci_cpl = ppl;
44400eb02e3Sichiro 
44500eb02e3Sichiro 		/* Re-enable this interrupt now that's it's cleared. */
44600eb02e3Sichiro 		intr_enabled |= ibit;
44700eb02e3Sichiro 		ixp425_set_intrmask();
44899df1a0aSscw 
44999df1a0aSscw 		/*
45099df1a0aSscw 		 * Don't forget to include interrupts which may have
45199df1a0aSscw 		 * arrived in the meantime.
45299df1a0aSscw 		 */
453825088edSmatt 		hwpend |= ((ixp425_ipending & IXP425_INT_HWMASK) & ~imask);
45400eb02e3Sichiro 	}
45500eb02e3Sichiro 
4566bc0c582Smatt #ifdef __HAVE_FAST_SOFTINTS
457825088edSmatt 	cpu_dosoftints();
4586bc0c582Smatt #endif
45900eb02e3Sichiro }
460