Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.15.4.2
      1  1.15.4.2    martin /*	$NetBSD: bcm2835_intr.c,v 1.15.4.2 2020/04/08 14:07:28 martin Exp $	*/
      2       1.1     skrll 
      3       1.1     skrll /*-
      4  1.15.4.2    martin  * Copyright (c) 2012, 2015, 2019 The NetBSD Foundation, Inc.
      5       1.1     skrll  * All rights reserved.
      6       1.1     skrll  *
      7       1.1     skrll  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1     skrll  * by Nick Hudson
      9       1.1     skrll  *
     10       1.1     skrll  * Redistribution and use in source and binary forms, with or without
     11       1.1     skrll  * modification, are permitted provided that the following conditions
     12       1.1     skrll  * are met:
     13       1.1     skrll  * 1. Redistributions of source code must retain the above copyright
     14       1.1     skrll  *    notice, this list of conditions and the following disclaimer.
     15       1.1     skrll  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1     skrll  *    notice, this list of conditions and the following disclaimer in the
     17       1.1     skrll  *    documentation and/or other materials provided with the distribution.
     18       1.1     skrll  *
     19       1.1     skrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1     skrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1     skrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1     skrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1     skrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1     skrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1     skrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1     skrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1     skrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1     skrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1     skrll  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1     skrll  */
     31       1.1     skrll 
     32       1.1     skrll #include <sys/cdefs.h>
     33  1.15.4.2    martin __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.15.4.2 2020/04/08 14:07:28 martin Exp $");
     34       1.1     skrll 
     35       1.1     skrll #define _INTR_PRIVATE
     36       1.1     skrll 
     37       1.5     skrll #include "opt_bcm283x.h"
     38       1.5     skrll 
     39       1.1     skrll #include <sys/param.h>
     40       1.5     skrll #include <sys/bus.h>
     41       1.5     skrll #include <sys/cpu.h>
     42       1.5     skrll #include <sys/device.h>
     43  1.15.4.1  christos #include <sys/kernel.h>
     44  1.15.4.1  christos #include <sys/kmem.h>
     45       1.1     skrll #include <sys/proc.h>
     46       1.1     skrll 
     47      1.15     skrll #include <dev/fdt/fdtvar.h>
     48      1.15     skrll 
     49       1.1     skrll #include <machine/intr.h>
     50       1.5     skrll 
     51       1.5     skrll #include <arm/locore.h>
     52       1.1     skrll 
     53       1.1     skrll #include <arm/pic/picvar.h>
     54       1.5     skrll #include <arm/cortex/gtmr_var.h>
     55       1.1     skrll 
     56      1.15     skrll #include <arm/broadcom/bcm2835_intr.h>
     57       1.1     skrll #include <arm/broadcom/bcm2835reg.h>
     58       1.5     skrll #include <arm/broadcom/bcm2835var.h>
     59       1.1     skrll 
     60      1.15     skrll #include <arm/fdt/arm_fdtvar.h>
     61      1.15     skrll 
     62      1.15     skrll static void bcm2835_irq_handler(void *);
     63      1.15     skrll static void bcm2836mp_intr_init(void *, struct cpu_info *);
     64      1.15     skrll 
     65       1.1     skrll static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     66       1.1     skrll static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     67       1.1     skrll static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     68       1.1     skrll static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     69       1.1     skrll static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     70       1.1     skrll     size_t);
     71       1.1     skrll 
     72       1.5     skrll static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     73       1.5     skrll static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     74       1.5     skrll static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
     75       1.5     skrll static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
     76       1.5     skrll static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
     77       1.5     skrll     size_t);
     78       1.5     skrll #ifdef MULTIPROCESSOR
     79       1.5     skrll int bcm2836mp_ipi_handler(void *);
     80       1.5     skrll static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
     81       1.5     skrll static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
     82       1.5     skrll #endif
     83      1.15     skrll 
     84      1.15     skrll static int bcm2835_icu_fdt_decode_irq(u_int *);
     85      1.15     skrll static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
     86      1.15     skrll     int (*)(void *), void *);
     87      1.15     skrll static void bcm2835_icu_fdt_disestablish(device_t, void *);
     88      1.15     skrll static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
     89      1.15     skrll 
     90  1.15.4.2    martin static int bcm2835_icu_intr(void *);
     91  1.15.4.2    martin 
     92      1.15     skrll static int bcm2836mp_icu_fdt_decode_irq(u_int *);
     93      1.15     skrll static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
     94      1.15     skrll     int (*)(void *), void *);
     95      1.15     skrll static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
     96      1.15     skrll static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
     97       1.5     skrll 
     98       1.1     skrll static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     99       1.1     skrll static void bcm2835_icu_attach(device_t, device_t, void *);
    100       1.1     skrll 
    101  1.15.4.2    martin static int bcm2835_int_base;
    102  1.15.4.2    martin static int bcm2836mp_int_base[BCM2836_NCPUS];
    103  1.15.4.2    martin 
    104  1.15.4.2    martin #define	BCM2835_INT_BASE		bcm2835_int_base
    105  1.15.4.2    martin #define	BCM2836_INT_BASECPUN(n)		bcm2836mp_int_base[(n)]
    106  1.15.4.2    martin 
    107      1.15     skrll static void
    108      1.15     skrll bcm2835_set_priority(struct pic_softc *pic, int ipl)
    109      1.15     skrll {
    110      1.15     skrll }
    111      1.15     skrll 
    112       1.1     skrll static struct pic_ops bcm2835_picops = {
    113       1.1     skrll 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
    114       1.1     skrll 	.pic_block_irqs = bcm2835_pic_block_irqs,
    115       1.1     skrll 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
    116       1.1     skrll 	.pic_establish_irq = bcm2835_pic_establish_irq,
    117       1.1     skrll 	.pic_source_name = bcm2835_pic_source_name,
    118      1.15     skrll 	.pic_set_priority = bcm2835_set_priority,
    119       1.1     skrll };
    120       1.1     skrll 
    121  1.15.4.1  christos static struct pic_softc bcm2835_pic = {
    122       1.1     skrll 	.pic_ops = &bcm2835_picops,
    123       1.1     skrll 	.pic_maxsources = BCM2835_NIRQ,
    124       1.1     skrll 	.pic_name = "bcm2835 pic",
    125       1.1     skrll };
    126       1.1     skrll 
    127       1.5     skrll static struct pic_ops bcm2836mp_picops = {
    128       1.5     skrll 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
    129       1.5     skrll 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
    130       1.5     skrll 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
    131       1.5     skrll 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
    132       1.5     skrll 	.pic_source_name = bcm2836mp_pic_source_name,
    133       1.8     skrll #if defined(MULTIPROCESSOR)
    134       1.5     skrll 	.pic_cpu_init = bcm2836mp_cpu_init,
    135       1.5     skrll 	.pic_ipi_send = bcm2836mp_send_ipi,
    136       1.5     skrll #endif
    137       1.5     skrll };
    138       1.5     skrll 
    139  1.15.4.1  christos static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
    140      1.13     skrll 	[0 ... BCM2836_NCPUS - 1] = {
    141       1.8     skrll 		.pic_ops = &bcm2836mp_picops,
    142       1.8     skrll 		.pic_maxsources = BCM2836_NIRQPERCPU,
    143       1.8     skrll 		.pic_name = "bcm2836 pic",
    144      1.13     skrll 	}
    145       1.5     skrll };
    146      1.15     skrll 
    147      1.15     skrll static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
    148      1.15     skrll 	.establish = bcm2835_icu_fdt_establish,
    149      1.15     skrll 	.disestablish = bcm2835_icu_fdt_disestablish,
    150      1.15     skrll 	.intrstr = bcm2835_icu_fdt_intrstr
    151      1.15     skrll };
    152      1.15     skrll 
    153      1.15     skrll static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
    154      1.15     skrll 	.establish = bcm2836mp_icu_fdt_establish,
    155      1.15     skrll 	.disestablish = bcm2836mp_icu_fdt_disestablish,
    156      1.15     skrll 	.intrstr = bcm2836mp_icu_fdt_intrstr
    157      1.15     skrll };
    158       1.5     skrll 
    159  1.15.4.1  christos struct bcm2836mp_interrupt {
    160  1.15.4.1  christos 	bool bi_done;
    161  1.15.4.1  christos 	TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
    162  1.15.4.1  christos 	int bi_irq;
    163  1.15.4.1  christos 	int bi_ipl;
    164  1.15.4.1  christos 	int bi_flags;
    165  1.15.4.1  christos 	int (*bi_func)(void *);
    166  1.15.4.1  christos 	void *bi_arg;
    167  1.15.4.1  christos 	void *bi_ihs[BCM2836_NCPUS];
    168  1.15.4.1  christos };
    169  1.15.4.1  christos 
    170  1.15.4.1  christos static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
    171  1.15.4.1  christos     TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
    172  1.15.4.1  christos 
    173  1.15.4.2    martin struct bcm2835icu_irqhandler;
    174  1.15.4.2    martin struct bcm2835icu_irq;
    175  1.15.4.2    martin struct bcm2835icu_softc;
    176  1.15.4.2    martin 
    177  1.15.4.2    martin struct bcm2835icu_irqhandler {
    178  1.15.4.2    martin 	struct bcm2835icu_irq	*ih_irq;
    179  1.15.4.2    martin 	int			(*ih_fn)(void *);
    180  1.15.4.2    martin 	void			*ih_arg;
    181  1.15.4.2    martin 	TAILQ_ENTRY(bcm2835icu_irqhandler) ih_next;
    182  1.15.4.2    martin };
    183  1.15.4.2    martin 
    184  1.15.4.2    martin struct bcm2835icu_irq {
    185  1.15.4.2    martin 	struct bcm2835icu_softc	*intr_sc;
    186  1.15.4.2    martin 	void			*intr_ih;
    187  1.15.4.2    martin 	void			*intr_arg;
    188  1.15.4.2    martin 	int			intr_refcnt;
    189  1.15.4.2    martin 	int			intr_ipl;
    190  1.15.4.2    martin 	int			intr_irq;
    191  1.15.4.2    martin 	int			intr_mpsafe;
    192  1.15.4.2    martin 	TAILQ_HEAD(, bcm2835icu_irqhandler) intr_handlers;
    193  1.15.4.2    martin };
    194  1.15.4.2    martin 
    195       1.1     skrll struct bcm2835icu_softc {
    196       1.1     skrll 	device_t		sc_dev;
    197       1.1     skrll 	bus_space_tag_t		sc_iot;
    198       1.1     skrll 	bus_space_handle_t	sc_ioh;
    199      1.15     skrll 
    200  1.15.4.2    martin 	struct bcm2835icu_irq	*sc_irq[BCM2835_NIRQ];
    201  1.15.4.2    martin 
    202      1.15     skrll 	int sc_phandle;
    203       1.1     skrll };
    204       1.1     skrll 
    205      1.15     skrll struct bcm2835icu_softc *bcml1icu_sc;
    206       1.1     skrll struct bcm2835icu_softc *bcmicu_sc;
    207       1.3     skrll 
    208       1.1     skrll #define read_bcm2835reg(o)	\
    209       1.1     skrll 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
    210       1.3     skrll 
    211       1.1     skrll #define write_bcm2835reg(o, v)	\
    212       1.1     skrll 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
    213       1.1     skrll 
    214       1.1     skrll 
    215       1.1     skrll #define bcm2835_barrier() \
    216       1.1     skrll 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
    217       1.1     skrll 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
    218       1.3     skrll 
    219       1.1     skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
    220       1.1     skrll 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
    221       1.1     skrll 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
    222       1.2  jakllsch 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
    223       1.2  jakllsch 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
    224       1.4     skrll 	"dma0",		"dma1",		"dma2",		"dma3",
    225       1.4     skrll 	"dma4",		"dma5",		"dma6",		"dma7",
    226       1.4     skrll 	"dma8",		"dma9",		"dma10",	"dma11",
    227       1.4     skrll 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
    228       1.1     skrll 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    229       1.1     skrll 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    230       1.1     skrll 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    231       1.1     skrll 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    232       1.1     skrll 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    233       1.1     skrll 	"gpio[3]",	"i2c",		"spi",		"pcm",
    234      1.12  jmcneill 	"sdhost",	"uart",		"(unused 58)",	"(unused 59)",
    235       1.1     skrll 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    236       1.1     skrll 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    237       1.1     skrll 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    238       1.1     skrll };
    239       1.1     skrll 
    240       1.8     skrll static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
    241       1.5     skrll 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
    242       1.5     skrll 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
    243  1.15.4.1  christos 	"gpu",		"pmu"
    244       1.5     skrll };
    245       1.5     skrll 
    246       1.5     skrll #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
    247       1.5     skrll 
    248       1.1     skrll #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    249       1.1     skrll #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    250       1.1     skrll #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    251       1.1     skrll #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    252       1.1     skrll #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    253       1.1     skrll 
    254       1.1     skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    255       1.1     skrll     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    256       1.1     skrll 
    257       1.1     skrll static int
    258       1.1     skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    259       1.1     skrll {
    260      1.15     skrll 	const char * const compatible[] = {
    261      1.15     skrll 	    "brcm,bcm2708-armctrl-ic",
    262      1.15     skrll 	    "brcm,bcm2709-armctrl-ic",
    263      1.15     skrll 	    "brcm,bcm2835-armctrl-ic",
    264      1.15     skrll 	    "brcm,bcm2836-armctrl-ic",
    265      1.15     skrll 	    "brcm,bcm2836-l1-intc",
    266      1.15     skrll 	    NULL
    267      1.15     skrll 	};
    268      1.15     skrll 	struct fdt_attach_args * const faa = aux;
    269       1.1     skrll 
    270      1.15     skrll 	return of_match_compatible(faa->faa_phandle, compatible);
    271       1.1     skrll }
    272       1.1     skrll 
    273       1.1     skrll static void
    274       1.1     skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    275       1.1     skrll {
    276      1.15     skrll 	struct bcm2835icu_softc * const sc = device_private(self);
    277      1.15     skrll 	struct fdt_attach_args * const faa = aux;
    278      1.15     skrll 	struct fdtbus_interrupt_controller_func *ifuncs;
    279      1.15     skrll 	const int phandle = faa->faa_phandle;
    280      1.15     skrll 	bus_addr_t addr;
    281      1.15     skrll 	bus_size_t size;
    282      1.15     skrll 	bus_space_handle_t ioh;
    283      1.15     skrll 	int error;
    284      1.15     skrll 
    285      1.15     skrll 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    286      1.15     skrll 		aprint_error(": couldn't get registers\n");
    287      1.15     skrll 		return;
    288      1.15     skrll 	}
    289       1.1     skrll 
    290       1.1     skrll 	sc->sc_dev = self;
    291      1.15     skrll 	sc->sc_iot = faa->faa_bst;
    292       1.1     skrll 
    293      1.15     skrll 	if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
    294      1.15     skrll 		aprint_error(": couldn't map device\n");
    295       1.1     skrll 		return;
    296       1.1     skrll 	}
    297       1.1     skrll 
    298      1.15     skrll 	sc->sc_ioh = ioh;
    299      1.15     skrll 	sc->sc_phandle = phandle;
    300       1.5     skrll 
    301      1.15     skrll 	const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
    302      1.15     skrll 	if (of_match_compatible(faa->faa_phandle, local_intc)) {
    303       1.8     skrll #if defined(MULTIPROCESSOR)
    304      1.15     skrll 		aprint_normal(": Multiprocessor");
    305       1.5     skrll #endif
    306      1.15     skrll 		bcml1icu_sc = sc;
    307       1.5     skrll 
    308      1.15     skrll 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    309      1.15     skrll 		    BCM2836_LOCAL_CONTROL, 0);
    310      1.15     skrll 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    311      1.15     skrll 		    BCM2836_LOCAL_PRESCALER, 0x80000000);
    312      1.15     skrll 
    313      1.15     skrll 		ifuncs = &bcm2836mpicu_fdt_funcs;
    314      1.15     skrll 
    315      1.15     skrll 		bcm2836mp_intr_init(self, curcpu());
    316      1.15     skrll 		arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
    317      1.15     skrll 	} else {
    318      1.15     skrll 		if (bcml1icu_sc == NULL)
    319      1.15     skrll 			arm_fdt_irq_set_handler(bcm2835_irq_handler);
    320      1.15     skrll 		bcmicu_sc = sc;
    321      1.15     skrll 		sc->sc_ioh = ioh;
    322      1.15     skrll 		sc->sc_phandle = phandle;
    323  1.15.4.2    martin 		bcm2835_int_base = pic_add(&bcm2835_pic, PIC_IRQBASE_ALLOC);
    324      1.15     skrll 		ifuncs = &bcm2835icu_fdt_funcs;
    325      1.15     skrll 	}
    326      1.15     skrll 
    327      1.15     skrll 	error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
    328      1.15     skrll 	if (error != 0) {
    329      1.15     skrll 		aprint_error(": couldn't register with fdtbus: %d\n", error);
    330      1.15     skrll 		return;
    331      1.15     skrll 	}
    332       1.1     skrll 	aprint_normal("\n");
    333       1.1     skrll }
    334       1.1     skrll 
    335      1.15     skrll static void
    336       1.1     skrll bcm2835_irq_handler(void *frame)
    337       1.1     skrll {
    338       1.1     skrll 	struct cpu_info * const ci = curcpu();
    339       1.1     skrll 	const int oldipl = ci->ci_cpl;
    340  1.15.4.1  christos 	const cpuid_t cpuid = ci->ci_core_id;
    341       1.1     skrll 	const uint32_t oldipl_mask = __BIT(oldipl);
    342       1.1     skrll 	int ipl_mask = 0;
    343       1.1     skrll 
    344       1.1     skrll 	ci->ci_data.cpu_nintr++;
    345       1.1     skrll 
    346       1.1     skrll 	bcm2835_barrier();
    347       1.8     skrll 	if (cpuid == 0) {
    348       1.8     skrll 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    349       1.8     skrll 	}
    350      1.15     skrll #if defined(SOC_BCM2836)
    351       1.8     skrll 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
    352       1.5     skrll #endif
    353       1.1     skrll 
    354       1.1     skrll 	/*
    355       1.1     skrll 	 * Record the pending_ipls and deliver them if we can.
    356       1.1     skrll 	 */
    357       1.1     skrll 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    358       1.1     skrll 		pic_do_pending_ints(I32_bit, oldipl, frame);
    359       1.1     skrll }
    360       1.1     skrll 
    361       1.1     skrll static void
    362       1.1     skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    363       1.1     skrll     uint32_t irq_mask)
    364       1.1     skrll {
    365       1.1     skrll 
    366       1.1     skrll 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    367       1.1     skrll 	bcm2835_barrier();
    368       1.1     skrll }
    369       1.1     skrll 
    370       1.1     skrll static void
    371       1.1     skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    372       1.1     skrll     uint32_t irq_mask)
    373       1.1     skrll {
    374       1.1     skrll 
    375       1.1     skrll 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    376       1.1     skrll 	bcm2835_barrier();
    377       1.1     skrll }
    378       1.1     skrll 
    379       1.1     skrll /*
    380       1.1     skrll  * Called with interrupts disabled
    381       1.1     skrll  */
    382       1.1     skrll static int
    383       1.1     skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    384       1.1     skrll {
    385       1.1     skrll 	int ipl = 0;
    386       1.1     skrll 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    387       1.1     skrll 
    388       1.1     skrll 	bcm2835_barrier();
    389       1.1     skrll 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    390       1.1     skrll 	if (bpending == 0)
    391       1.1     skrll 		return 0;
    392       1.1     skrll 
    393       1.1     skrll 	armirq = bpending & BCM2835_INTBIT_ARM;
    394       1.1     skrll 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    395       1.1     skrll 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    396       1.1     skrll 
    397       1.1     skrll 	if (armirq) {
    398       1.8     skrll 		ipl |= pic_mark_pending_sources(pic,
    399       1.8     skrll 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
    400       1.1     skrll 	}
    401       1.1     skrll 
    402       1.1     skrll 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    403       1.1     skrll 		uint32_t pending1;
    404       1.3     skrll 
    405       1.1     skrll 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    406       1.8     skrll 		ipl |= pic_mark_pending_sources(pic,
    407       1.8     skrll 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
    408       1.1     skrll 	}
    409       1.1     skrll 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    410       1.1     skrll 		uint32_t pending2;
    411       1.3     skrll 
    412       1.1     skrll 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    413       1.8     skrll 		ipl |= pic_mark_pending_sources(pic,
    414       1.8     skrll 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
    415       1.1     skrll 	}
    416       1.3     skrll 
    417       1.1     skrll 	return ipl;
    418       1.1     skrll }
    419       1.1     skrll 
    420       1.1     skrll static void
    421       1.1     skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    422       1.1     skrll {
    423       1.1     skrll 
    424       1.1     skrll 	/* Nothing really*/
    425       1.1     skrll 	KASSERT(is->is_irq < BCM2835_NIRQ);
    426       1.1     skrll 	KASSERT(is->is_type == IST_LEVEL);
    427       1.1     skrll }
    428       1.1     skrll 
    429       1.1     skrll static void
    430       1.1     skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    431       1.1     skrll {
    432       1.1     skrll 
    433       1.1     skrll 	strlcpy(buf, bcm2835_sources[irq], len);
    434       1.1     skrll }
    435       1.5     skrll 
    436      1.15     skrll static int
    437      1.15     skrll bcm2835_icu_fdt_decode_irq(u_int *specifier)
    438      1.15     skrll {
    439      1.15     skrll 	u_int base;
    440      1.15     skrll 
    441      1.15     skrll 	if (!specifier)
    442      1.15     skrll 		return -1;
    443      1.15     skrll 
    444      1.15     skrll 	/* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
    445      1.15     skrll 	/* 2nd cell is the irq relative to that bank */
    446      1.15     skrll 
    447      1.15     skrll 	const u_int bank = be32toh(specifier[0]);
    448      1.15     skrll 	switch (bank) {
    449      1.15     skrll 	case 0:
    450      1.15     skrll 		base = BCM2835_INT_BASICBASE;
    451      1.15     skrll 		break;
    452      1.15     skrll 	case 1:
    453      1.15     skrll 		base = BCM2835_INT_GPU0BASE;
    454      1.15     skrll 		break;
    455      1.15     skrll 	case 2:
    456      1.15     skrll 		base = BCM2835_INT_GPU1BASE;
    457      1.15     skrll 		break;
    458      1.15     skrll 	default:
    459      1.15     skrll 		return -1;
    460      1.15     skrll 	}
    461      1.15     skrll 	const u_int off = be32toh(specifier[1]);
    462      1.15     skrll 
    463      1.15     skrll 	return base + off;
    464      1.15     skrll }
    465      1.15     skrll 
    466      1.15     skrll static void *
    467      1.15     skrll bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    468      1.15     skrll     int (*func)(void *), void *arg)
    469      1.15     skrll {
    470  1.15.4.2    martin 	struct bcm2835icu_softc * const sc = device_private(dev);
    471  1.15.4.2    martin 	struct bcm2835icu_irq *firq;
    472  1.15.4.2    martin 	struct bcm2835icu_irqhandler *firqh;
    473      1.15     skrll 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    474  1.15.4.2    martin 	int irq, irqidx;
    475      1.15     skrll 
    476      1.15     skrll 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    477      1.15     skrll 	if (irq == -1)
    478      1.15     skrll 		return NULL;
    479  1.15.4.2    martin 	irqidx = irq - BCM2835_INT_BASE;
    480  1.15.4.2    martin 
    481  1.15.4.2    martin 	KASSERT(irqidx < BCM2835_NIRQ);
    482  1.15.4.2    martin 
    483  1.15.4.2    martin 	firq = sc->sc_irq[irqidx];
    484  1.15.4.2    martin 	if (firq == NULL) {
    485  1.15.4.2    martin 		firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
    486  1.15.4.2    martin 		firq->intr_sc = sc;
    487  1.15.4.2    martin 		firq->intr_refcnt = 0;
    488  1.15.4.2    martin 		firq->intr_arg = arg;
    489  1.15.4.2    martin 		firq->intr_ipl = ipl;
    490  1.15.4.2    martin 		firq->intr_mpsafe = iflags;
    491  1.15.4.2    martin 		firq->intr_irq = irq;
    492  1.15.4.2    martin 		TAILQ_INIT(&firq->intr_handlers);
    493  1.15.4.2    martin 		if (arg == NULL) {
    494  1.15.4.2    martin 			firq->intr_ih = intr_establish(irq, ipl,
    495  1.15.4.2    martin 			    IST_LEVEL | iflags, func, NULL);
    496  1.15.4.2    martin 		} else {
    497  1.15.4.2    martin 			firq->intr_ih = intr_establish(irq, ipl,
    498  1.15.4.2    martin 			    IST_LEVEL | iflags, bcm2835_icu_intr, firq);
    499  1.15.4.2    martin 		}
    500  1.15.4.2    martin 		if (firq->intr_ih == NULL) {
    501  1.15.4.2    martin 			kmem_free(firq, sizeof(*firq));
    502  1.15.4.2    martin 			return NULL;
    503  1.15.4.2    martin 		}
    504  1.15.4.2    martin 		sc->sc_irq[irqidx] = firq;
    505  1.15.4.2    martin 	} else {
    506  1.15.4.2    martin 		if (firq->intr_arg == NULL || arg == NULL) {
    507  1.15.4.2    martin 			device_printf(dev,
    508  1.15.4.2    martin 			    "cannot share irq with NULL-arg handler\n");
    509  1.15.4.2    martin 			return NULL;
    510  1.15.4.2    martin 		}
    511  1.15.4.2    martin 		if (firq->intr_ipl != ipl) {
    512  1.15.4.2    martin 			device_printf(dev,
    513  1.15.4.2    martin 			    "cannot share irq with different ipl\n");
    514  1.15.4.2    martin 			return NULL;
    515  1.15.4.2    martin 		}
    516  1.15.4.2    martin 		if (firq->intr_mpsafe != iflags) {
    517  1.15.4.2    martin 			device_printf(dev,
    518  1.15.4.2    martin 			    "cannot share irq between mpsafe/non-mpsafe\n");
    519  1.15.4.2    martin 			return NULL;
    520  1.15.4.2    martin 		}
    521  1.15.4.2    martin 	}
    522       1.5     skrll 
    523  1.15.4.2    martin 	firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
    524  1.15.4.2    martin 	firqh->ih_irq = firq;
    525  1.15.4.2    martin 	firqh->ih_fn = func;
    526  1.15.4.2    martin 	firqh->ih_arg = arg;
    527  1.15.4.2    martin 
    528  1.15.4.2    martin 	firq->intr_refcnt++;
    529  1.15.4.2    martin 	TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
    530  1.15.4.2    martin 
    531  1.15.4.2    martin 	/*
    532  1.15.4.2    martin 	 * XXX interrupt_distribute(9) assumes that any interrupt
    533  1.15.4.2    martin 	 * handle can be used as an input to the MD interrupt_distribute
    534  1.15.4.2    martin 	 * implementationm, so we are forced to return the handle
    535  1.15.4.2    martin 	 * we got back from intr_establish().  Upshot is that the
    536  1.15.4.2    martin 	 * input to bcm2835_icu_fdt_disestablish() is ambiguous for
    537  1.15.4.2    martin 	 * shared IRQs, rendering them un-disestablishable.
    538  1.15.4.2    martin 	 */
    539  1.15.4.2    martin 
    540  1.15.4.2    martin 	return firq->intr_ih;
    541      1.15     skrll }
    542      1.15     skrll 
    543      1.15     skrll static void
    544      1.15     skrll bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
    545      1.15     skrll {
    546  1.15.4.2    martin 	struct bcm2835icu_softc * const sc = device_private(dev);
    547  1.15.4.2    martin 	struct bcm2835icu_irqhandler *firqh;
    548  1.15.4.2    martin 	struct bcm2835icu_irq *firq;
    549  1.15.4.2    martin 	u_int n;
    550  1.15.4.2    martin 
    551  1.15.4.2    martin 	for (n = 0; n < BCM2835_NIRQ; n++) {
    552  1.15.4.2    martin 		firq = sc->sc_irq[n];
    553  1.15.4.2    martin 		if (firq == NULL || firq->intr_ih != ih)
    554  1.15.4.2    martin 			continue;
    555  1.15.4.2    martin 
    556  1.15.4.2    martin 		KASSERT(firq->intr_refcnt > 0);
    557  1.15.4.2    martin 		KASSERT(n == (firq->intr_irq - BCM2835_INT_BASE));
    558  1.15.4.2    martin 
    559  1.15.4.2    martin 		/* XXX see above */
    560  1.15.4.2    martin 		if (firq->intr_refcnt > 1)
    561  1.15.4.2    martin 			panic("%s: cannot disestablish shared irq", __func__);
    562  1.15.4.2    martin 
    563  1.15.4.2    martin 		intr_disestablish(firq->intr_ih);
    564  1.15.4.2    martin 
    565  1.15.4.2    martin 		firqh = TAILQ_FIRST(&firq->intr_handlers);
    566  1.15.4.2    martin 		TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
    567  1.15.4.2    martin 		kmem_free(firqh, sizeof(*firqh));
    568  1.15.4.2    martin 
    569  1.15.4.2    martin 		sc->sc_irq[n] = NULL;
    570  1.15.4.2    martin 		kmem_free(firq, sizeof(*firq));
    571  1.15.4.2    martin 
    572  1.15.4.2    martin 		return;
    573  1.15.4.2    martin 	}
    574  1.15.4.2    martin 
    575  1.15.4.2    martin 	panic("%s: interrupt not established", __func__);
    576  1.15.4.2    martin }
    577  1.15.4.2    martin 
    578  1.15.4.2    martin static int
    579  1.15.4.2    martin bcm2835_icu_intr(void *priv)
    580  1.15.4.2    martin {
    581  1.15.4.2    martin 	struct bcm2835icu_irq *firq = priv;
    582  1.15.4.2    martin 	struct bcm2835icu_irqhandler *firqh;
    583  1.15.4.2    martin 	int handled = 0;
    584  1.15.4.2    martin 
    585  1.15.4.2    martin 	TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
    586  1.15.4.2    martin 		handled |= firqh->ih_fn(firqh->ih_arg);
    587  1.15.4.2    martin 	}
    588  1.15.4.2    martin 
    589  1.15.4.2    martin 	return handled;
    590      1.15     skrll }
    591      1.15     skrll 
    592      1.15     skrll static bool
    593      1.15     skrll bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
    594      1.15     skrll {
    595      1.15     skrll 	int irq;
    596      1.15     skrll 
    597      1.15     skrll 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    598      1.15     skrll 	if (irq == -1)
    599      1.15     skrll 		return false;
    600      1.15     skrll 
    601      1.15     skrll 	snprintf(buf, buflen, "icu irq %d", irq);
    602      1.15     skrll 
    603      1.15     skrll 	return true;
    604      1.15     skrll }
    605       1.5     skrll 
    606       1.5     skrll #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    607  1.15.4.1  christos #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,7)
    608  1.15.4.1  christos #define	BCM2836MP_GPU_IRQ	__BIT(8)
    609  1.15.4.1  christos #define	BCM2836MP_PMU_IRQ	__BIT(9)
    610  1.15.4.1  christos #define	BCM2836MP_ALL_IRQS	(BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
    611       1.5     skrll 
    612       1.5     skrll static void
    613       1.5     skrll bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    614       1.5     skrll     uint32_t irq_mask)
    615       1.5     skrll {
    616      1.15     skrll 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    617      1.15     skrll 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    618  1.15.4.1  christos 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    619       1.5     skrll 
    620       1.8     skrll 	KASSERT(irqbase == 0);
    621       1.5     skrll 
    622       1.5     skrll 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    623       1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    624      1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    625       1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    626       1.5     skrll 		val |= mask;
    627      1.15     skrll 		bus_space_write_4(iot, ioh,
    628       1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    629       1.5     skrll 		    val);
    630      1.15     skrll 		bus_space_barrier(iot, ioh,
    631       1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    632       1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    633       1.5     skrll 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    634      1.10     skrll 	}
    635      1.10     skrll 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    636       1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    637      1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    638       1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    639       1.5     skrll 		val |= mask;
    640      1.15     skrll 		bus_space_write_4(iot, ioh,
    641       1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    642       1.5     skrll 		    val);
    643      1.15     skrll 		bus_space_barrier(iot, ioh,
    644       1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    645       1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    646       1.5     skrll 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    647       1.5     skrll 	}
    648  1.15.4.1  christos 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    649  1.15.4.1  christos 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
    650  1.15.4.1  christos 		    __BIT(cpuid));
    651  1.15.4.1  christos 		bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
    652  1.15.4.1  christos 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    653  1.15.4.1  christos 	}
    654       1.5     skrll 
    655       1.5     skrll 	return;
    656       1.5     skrll }
    657       1.5     skrll 
    658       1.5     skrll static void
    659       1.5     skrll bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    660       1.5     skrll     uint32_t irq_mask)
    661       1.5     skrll {
    662      1.15     skrll 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    663      1.15     skrll 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    664  1.15.4.1  christos 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    665       1.8     skrll 
    666       1.8     skrll 	KASSERT(irqbase == 0);
    667       1.5     skrll 
    668       1.5     skrll 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    669       1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    670      1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    671       1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    672       1.5     skrll 		val &= ~mask;
    673      1.15     skrll 		bus_space_write_4(iot, ioh,
    674       1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    675       1.5     skrll 		    val);
    676      1.10     skrll 	}
    677      1.10     skrll 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    678       1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    679      1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    680       1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    681       1.5     skrll 		val &= ~mask;
    682      1.15     skrll 		bus_space_write_4(iot, ioh,
    683       1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    684       1.5     skrll 		    val);
    685       1.5     skrll 	}
    686  1.15.4.1  christos 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    687  1.15.4.1  christos 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
    688  1.15.4.1  christos 		     __BIT(cpuid));
    689  1.15.4.1  christos 	}
    690       1.5     skrll 
    691       1.5     skrll 	bcm2835_barrier();
    692       1.5     skrll 	return;
    693       1.5     skrll }
    694       1.5     skrll 
    695       1.5     skrll static int
    696       1.5     skrll bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    697       1.5     skrll {
    698       1.8     skrll 	struct cpu_info * const ci = curcpu();
    699  1.15.4.1  christos 	const cpuid_t cpuid = ci->ci_core_id;
    700       1.5     skrll 	uint32_t lpending;
    701       1.5     skrll 	int ipl = 0;
    702       1.5     skrll 
    703       1.8     skrll 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    704       1.8     skrll 
    705       1.5     skrll 	bcm2835_barrier();
    706       1.5     skrll 
    707      1.15     skrll 	lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    708       1.5     skrll 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    709       1.5     skrll 
    710       1.5     skrll 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    711  1.15.4.2    martin 	const uint32_t allirqs = lpending & BCM2836MP_ALL_IRQS;
    712  1.15.4.2    martin 	if (allirqs) {
    713  1.15.4.2    martin 		ipl |= pic_mark_pending_sources(pic, 0, allirqs);
    714       1.5     skrll 	}
    715       1.5     skrll 
    716       1.5     skrll 	return ipl;
    717       1.5     skrll }
    718       1.5     skrll 
    719       1.5     skrll static void
    720       1.5     skrll bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    721       1.5     skrll {
    722       1.5     skrll 	/* Nothing really*/
    723       1.5     skrll 	KASSERT(is->is_irq >= 0);
    724       1.8     skrll 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
    725       1.8     skrll }
    726       1.8     skrll 
    727       1.8     skrll static void
    728       1.8     skrll bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    729       1.8     skrll {
    730       1.8     skrll 
    731       1.8     skrll 	irq %= BCM2836_NIRQPERCPU;
    732       1.8     skrll 	strlcpy(buf, bcm2836mp_sources[irq], len);
    733       1.8     skrll }
    734       1.5     skrll 
    735       1.5     skrll 
    736      1.15     skrll #if defined(MULTIPROCESSOR)
    737       1.8     skrll static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
    738       1.8     skrll {
    739       1.8     skrll 
    740       1.8     skrll 	/* Enable IRQ and not FIQ */
    741      1.15     skrll 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    742  1.15.4.1  christos 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_core_id), 1);
    743       1.5     skrll }
    744       1.5     skrll 
    745       1.5     skrll static void
    746       1.8     skrll bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
    747       1.8     skrll {
    748      1.10     skrll 	KASSERT(pic != NULL);
    749      1.10     skrll 	KASSERT(pic != &bcm2835_pic);
    750      1.10     skrll 	KASSERT(pic->pic_cpus != NULL);
    751      1.10     skrll 
    752       1.8     skrll 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    753       1.8     skrll 
    754      1.15     skrll 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    755       1.9  jmcneill 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
    756       1.8     skrll }
    757       1.8     skrll 
    758       1.8     skrll int
    759       1.8     skrll bcm2836mp_ipi_handler(void *priv)
    760       1.8     skrll {
    761       1.8     skrll 	const struct cpu_info *ci = curcpu();
    762  1.15.4.1  christos 	const cpuid_t cpuid = ci->ci_core_id;
    763       1.9  jmcneill 	uint32_t ipimask, bit;
    764       1.9  jmcneill 
    765      1.15     skrll 	ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    766       1.8     skrll 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
    767      1.15     skrll 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    768      1.15     skrll 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
    769       1.8     skrll 
    770       1.9  jmcneill 	while ((bit = ffs(ipimask)) > 0) {
    771       1.9  jmcneill 		const u_int ipi = bit - 1;
    772       1.9  jmcneill 		switch (ipi) {
    773       1.9  jmcneill 		case IPI_AST:
    774      1.11     skrll 			pic_ipi_ast(priv);
    775      1.11     skrll 			break;
    776       1.9  jmcneill 		case IPI_NOP:
    777      1.11     skrll 			pic_ipi_nop(priv);
    778      1.11     skrll 			break;
    779       1.9  jmcneill #ifdef __HAVE_PREEMPTION
    780       1.9  jmcneill 		case IPI_KPREEMPT:
    781      1.11     skrll 			pic_ipi_kpreempt(priv);
    782      1.11     skrll 			break;
    783       1.9  jmcneill #endif
    784       1.9  jmcneill 		case IPI_XCALL:
    785       1.9  jmcneill 			pic_ipi_xcall(priv);
    786       1.9  jmcneill 			break;
    787       1.9  jmcneill 		case IPI_GENERIC:
    788       1.9  jmcneill 			pic_ipi_generic(priv);
    789       1.9  jmcneill 			break;
    790       1.9  jmcneill 		case IPI_SHOOTDOWN:
    791       1.9  jmcneill 			pic_ipi_shootdown(priv);
    792       1.9  jmcneill 			break;
    793       1.8     skrll #ifdef DDB
    794       1.9  jmcneill 		case IPI_DDB:
    795       1.9  jmcneill 			pic_ipi_ddb(priv);
    796       1.9  jmcneill 			break;
    797       1.8     skrll #endif
    798       1.9  jmcneill 		}
    799       1.9  jmcneill 		ipimask &= ~__BIT(ipi);
    800       1.8     skrll 	}
    801       1.8     skrll 
    802       1.8     skrll 	return 1;
    803       1.8     skrll }
    804      1.15     skrll #endif
    805       1.8     skrll 
    806      1.15     skrll static void
    807      1.15     skrll bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
    808       1.5     skrll {
    809  1.15.4.1  christos 	const cpuid_t cpuid = ci->ci_core_id;
    810       1.8     skrll 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
    811       1.8     skrll 
    812      1.15     skrll #if defined(MULTIPROCESSOR)
    813       1.8     skrll 	pic->pic_cpus = ci->ci_kcpuset;
    814  1.15.4.1  christos 
    815  1.15.4.1  christos 	/*
    816  1.15.4.1  christos 	 * Append "#n" to avoid duplication of .pic_name[]
    817  1.15.4.1  christos 	 * It should be a unique id for intr_get_source()
    818  1.15.4.1  christos 	 */
    819  1.15.4.1  christos 	char suffix[sizeof("#00000")];
    820  1.15.4.1  christos 	snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
    821  1.15.4.1  christos 	strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
    822      1.15     skrll #endif
    823  1.15.4.2    martin 	bcm2836mp_int_base[cpuid] = pic_add(pic, PIC_IRQBASE_ALLOC);
    824       1.8     skrll 
    825      1.15     skrll #if defined(MULTIPROCESSOR)
    826      1.10     skrll 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
    827       1.8     skrll 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
    828       1.8     skrll 
    829  1.15.4.1  christos 	struct bcm2836mp_interrupt *bip;
    830  1.15.4.1  christos 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    831  1.15.4.1  christos 		if (bip->bi_done)
    832  1.15.4.1  christos 			continue;
    833  1.15.4.1  christos 
    834  1.15.4.1  christos 		const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
    835  1.15.4.1  christos 		void *ih = intr_establish(irq, bip->bi_ipl,
    836  1.15.4.1  christos 		    IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
    837  1.15.4.1  christos 
    838  1.15.4.1  christos 		bip->bi_ihs[cpuid] = ih;
    839  1.15.4.1  christos 	}
    840      1.15     skrll #endif
    841       1.5     skrll }
    842       1.8     skrll 
    843      1.15     skrll static int
    844      1.15     skrll bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
    845      1.15     skrll {
    846      1.15     skrll 	if (!specifier)
    847      1.15     skrll 		return -1;
    848  1.15.4.1  christos 	return be32toh(specifier[0]);
    849      1.15     skrll }
    850      1.15     skrll 
    851      1.15     skrll static void *
    852      1.15     skrll bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    853      1.15     skrll     int (*func)(void *), void *arg)
    854      1.15     skrll {
    855      1.15     skrll 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    856  1.15.4.1  christos 	struct bcm2836mp_interrupt *bip;
    857  1.15.4.1  christos 	void *ih;
    858      1.15     skrll 
    859  1.15.4.1  christos 	int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    860      1.15     skrll 	if (irq == -1)
    861      1.15     skrll 		return NULL;
    862      1.15     skrll 
    863  1.15.4.1  christos 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    864  1.15.4.1  christos 		if (irq == bip->bi_irq)
    865  1.15.4.1  christos 			return NULL;
    866  1.15.4.1  christos 	}
    867  1.15.4.1  christos 
    868  1.15.4.1  christos 	bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
    869  1.15.4.1  christos 	if (bip == NULL)
    870  1.15.4.1  christos 		return NULL;
    871  1.15.4.1  christos 
    872  1.15.4.1  christos 	bip->bi_done = false;
    873  1.15.4.1  christos 	bip->bi_irq = irq;
    874  1.15.4.1  christos 	bip->bi_ipl = ipl;
    875  1.15.4.1  christos 	bip->bi_flags = IST_LEVEL | iflags;
    876  1.15.4.1  christos 	bip->bi_func = func;
    877  1.15.4.1  christos 	bip->bi_arg = arg;
    878  1.15.4.1  christos 
    879  1.15.4.1  christos 	/*
    880  1.15.4.1  christos 	 * If we're not cold and the BPs have been started then we can register the
    881  1.15.4.1  christos 	 * interupt for all CPUs now, e.g. PMU
    882  1.15.4.1  christos 	 */
    883  1.15.4.1  christos 	if (!cold) {
    884  1.15.4.1  christos 		for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
    885  1.15.4.1  christos 			ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
    886  1.15.4.1  christos 			    IST_LEVEL | iflags, func, arg);
    887  1.15.4.1  christos 			if (!ih) {
    888  1.15.4.1  christos 				kmem_free(bip, sizeof(*bip));
    889  1.15.4.1  christos 				return NULL;
    890  1.15.4.1  christos 			}
    891  1.15.4.1  christos 			bip->bi_ihs[cpuid] = ih;
    892  1.15.4.1  christos 
    893  1.15.4.1  christos 		}
    894  1.15.4.1  christos 		bip->bi_done = true;
    895  1.15.4.1  christos 		ih = bip->bi_ihs[0];
    896  1.15.4.1  christos 		goto done;
    897  1.15.4.1  christos 	}
    898  1.15.4.1  christos 
    899  1.15.4.1  christos 	/*
    900  1.15.4.1  christos 	 * Otherwise we can only establish the interrupt for the BP and
    901  1.15.4.1  christos 	 * delay until bcm2836mp_intr_init is called for each AP, e.g.
    902  1.15.4.1  christos 	 * gtmr
    903  1.15.4.1  christos 	 */
    904  1.15.4.1  christos 	ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
    905  1.15.4.1  christos 	    IST_LEVEL | iflags, func, arg);
    906  1.15.4.1  christos 	if (!ih) {
    907  1.15.4.1  christos 		kmem_free(bip, sizeof(*bip));
    908  1.15.4.1  christos 		return NULL;
    909  1.15.4.1  christos 	}
    910  1.15.4.1  christos 
    911  1.15.4.1  christos 	bip->bi_ihs[0] = ih;
    912  1.15.4.1  christos 	for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
    913  1.15.4.1  christos 		bip->bi_ihs[cpuid] = NULL;
    914  1.15.4.1  christos 
    915  1.15.4.1  christos done:
    916  1.15.4.1  christos 	TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
    917  1.15.4.1  christos 
    918  1.15.4.1  christos 	/*
    919  1.15.4.1  christos 	 * Return the intr_establish handle for cpu 0 for API compatibility.
    920  1.15.4.1  christos 	 * Any cpu would do here as these sources don't support set_affinity
    921  1.15.4.1  christos 	 * when the handle is used in interrupt_distribute(9)
    922  1.15.4.1  christos 	 */
    923  1.15.4.1  christos 	return ih;
    924      1.15     skrll }
    925      1.15     skrll 
    926      1.15     skrll static void
    927      1.15     skrll bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
    928      1.15     skrll {
    929  1.15.4.1  christos 	struct bcm2836mp_interrupt *bip;
    930  1.15.4.1  christos 
    931  1.15.4.1  christos 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    932  1.15.4.1  christos 		if (bip->bi_ihs[0] == ih)
    933  1.15.4.1  christos 			break;
    934  1.15.4.1  christos 	}
    935  1.15.4.1  christos 
    936  1.15.4.1  christos 	if (bip == NULL)
    937  1.15.4.1  christos 		return;
    938  1.15.4.1  christos 
    939  1.15.4.1  christos 	for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
    940  1.15.4.1  christos 		intr_disestablish(bip->bi_ihs[cpuid]);
    941  1.15.4.1  christos 
    942  1.15.4.1  christos 	TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
    943  1.15.4.1  christos 
    944  1.15.4.1  christos 	kmem_free(bip, sizeof(*bip));
    945      1.15     skrll }
    946      1.15     skrll 
    947      1.15     skrll static bool
    948      1.15     skrll bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
    949      1.15     skrll     size_t buflen)
    950      1.15     skrll {
    951      1.15     skrll 	int irq;
    952      1.15     skrll 
    953      1.15     skrll 	irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    954      1.15     skrll 	if (irq == -1)
    955      1.15     skrll 		return false;
    956      1.15     skrll 
    957      1.15     skrll 	snprintf(buf, buflen, "local_intc irq %d", irq);
    958      1.15     skrll 
    959      1.15     skrll 	return true;
    960      1.15     skrll }
    961