intr.c revision 331017
1/* $NetBSD: intr.c,v 1.12 2003/07/15 00:24:41 lukem Exp $ */ 2 3/*- 4 * SPDX-License-Identifier: BSD-4-Clause 5 * 6 * Copyright (c) 2004 Olivier Houchard. 7 * Copyright (c) 1994-1998 Mark Brinicombe. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Mark Brinicombe 21 * for the NetBSD Project. 22 * 4. The name of the company nor the name of the author may be used to 23 * endorse or promote products derived from this software without specific 24 * prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * Soft interrupt and other generic interrupt functions. 39 */ 40 41#include "opt_platform.h" 42#include "opt_hwpmc_hooks.h" 43 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: stable/11/sys/arm/arm/intr.c 331017 2018-03-15 19:08:33Z kevans $"); 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/syslog.h> 50#include <sys/kernel.h> 51#include <sys/malloc.h> 52#include <sys/proc.h> 53#include <sys/bus.h> 54#include <sys/interrupt.h> 55#include <sys/conf.h> 56#include <sys/pmc.h> 57#include <sys/pmckern.h> 58#include <sys/vmmeter.h> 59 60#include <machine/atomic.h> 61#include <machine/bus.h> 62#include <machine/intr.h> 63#include <machine/cpu.h> 64 65#ifdef FDT 66#include <dev/fdt/fdt_common.h> 67#include <machine/fdt.h> 68#endif 69 70#define INTRNAME_LEN (MAXCOMLEN + 1) 71 72typedef void (*mask_fn)(void *); 73 74static struct intr_event *intr_events[NIRQ]; 75 76void intr_irq_handler(struct trapframe *); 77 78void (*arm_post_filter)(void *) = NULL; 79int (*arm_config_irq)(int irq, enum intr_trigger trig, 80 enum intr_polarity pol) = NULL; 81 82/* Data for statistics reporting. */ 83u_long intrcnt[NIRQ]; 84char intrnames[(NIRQ * INTRNAME_LEN) + 1]; 85size_t sintrcnt = sizeof(intrcnt); 86size_t sintrnames = sizeof(intrnames); 87 88/* 89 * Pre-format intrnames into an array of fixed-size strings containing spaces. 90 * This allows us to avoid the need for an intermediate table of indices into 91 * the names and counts arrays, while still meeting the requirements and 92 * assumptions of vmstat(8) and the kdb "show intrcnt" command, the two 93 * consumers of this data. 94 */ 95static void 96intr_init(void *unused) 97{ 98 int i; 99 100 for (i = 0; i < NIRQ; ++i) { 101 snprintf(&intrnames[i * INTRNAME_LEN], INTRNAME_LEN, "%-*s", 102 INTRNAME_LEN - 1, ""); 103 } 104} 105 106SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL); 107 108#ifdef FDT 109int 110intr_fdt_map_irq(phandle_t iparent, pcell_t *intr, int icells) 111{ 112 fdt_pic_decode_t intr_decode; 113 phandle_t intr_parent; 114 int i, rv, interrupt, trig, pol; 115 116 intr_parent = OF_node_from_xref(iparent); 117 for (i = 0; i < icells; i++) 118 intr[i] = cpu_to_fdt32(intr[i]); 119 120 for (i = 0; fdt_pic_table[i] != NULL; i++) { 121 intr_decode = fdt_pic_table[i]; 122 rv = intr_decode(intr_parent, intr, &interrupt, &trig, &pol); 123 124 if (rv == 0) { 125 /* This was recognized as our PIC and decoded. */ 126 interrupt = FDT_MAP_IRQ(intr_parent, interrupt); 127 return (interrupt); 128 } 129 } 130 131 /* Not in table, so guess */ 132 interrupt = FDT_MAP_IRQ(intr_parent, fdt32_to_cpu(intr[0])); 133 134 return (interrupt); 135} 136#endif 137 138void 139arm_setup_irqhandler(const char *name, driver_filter_t *filt, 140 void (*hand)(void*), void *arg, int irq, int flags, void **cookiep) 141{ 142 struct intr_event *event; 143 int error; 144 145 if (irq < 0 || irq >= NIRQ) 146 return; 147 event = intr_events[irq]; 148 if (event == NULL) { 149 error = intr_event_create(&event, (void *)irq, 0, irq, 150 (mask_fn)arm_mask_irq, (mask_fn)arm_unmask_irq, 151 arm_post_filter, NULL, "intr%d:", irq); 152 if (error) 153 return; 154 intr_events[irq] = event; 155 snprintf(&intrnames[irq * INTRNAME_LEN], INTRNAME_LEN, 156 "irq%d: %-*s", irq, INTRNAME_LEN - 1, name); 157 } 158 intr_event_add_handler(event, name, filt, hand, arg, 159 intr_priority(flags), flags, cookiep); 160} 161 162int 163arm_remove_irqhandler(int irq, void *cookie) 164{ 165 struct intr_event *event; 166 int error; 167 168 event = intr_events[irq]; 169 arm_mask_irq(irq); 170 171 error = intr_event_remove_handler(cookie); 172 173 if (!TAILQ_EMPTY(&event->ie_handlers)) 174 arm_unmask_irq(irq); 175 return (error); 176} 177 178void dosoftints(void); 179void 180dosoftints(void) 181{ 182} 183 184void 185intr_irq_handler(struct trapframe *frame) 186{ 187 struct intr_event *event; 188 int i; 189 190 PCPU_INC(cnt.v_intr); 191 i = -1; 192 while ((i = arm_get_next_irq(i)) != -1) { 193 intrcnt[i]++; 194 event = intr_events[i]; 195 if (intr_event_handle(event, frame) != 0) { 196 /* XXX: Log stray IRQs */ 197 arm_mask_irq(i); 198 } 199 } 200#ifdef HWPMC_HOOKS 201 if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN)) 202 pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, frame); 203#endif 204} 205