intr_machdep.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 Oleksandr Tymoshenko 5 * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification, immediately at the beginning of the file. 14 * 2. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/11/sys/mips/mips/intr_machdep.c 330897 2018-03-14 03:19:51Z eadler $"); 33 34#include "opt_hwpmc_hooks.h" 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/bus.h> 39#include <sys/interrupt.h> 40#include <sys/pmc.h> 41#include <sys/pmckern.h> 42 43#include <machine/clock.h> 44#include <machine/cpu.h> 45#include <machine/cpufunc.h> 46#include <machine/cpuinfo.h> 47#include <machine/cpuregs.h> 48#include <machine/frame.h> 49#include <machine/intr_machdep.h> 50#include <machine/md_var.h> 51#include <machine/trap.h> 52 53static struct intr_event *hardintr_events[NHARD_IRQS]; 54static struct intr_event *softintr_events[NSOFT_IRQS]; 55static mips_intrcnt_t mips_intr_counters[NSOFT_IRQS + NHARD_IRQS]; 56 57static int intrcnt_index; 58 59static cpu_intr_mask_t hardintr_mask_func; 60static cpu_intr_unmask_t hardintr_unmask_func; 61 62mips_intrcnt_t 63mips_intrcnt_create(const char* name) 64{ 65 mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; 66 67 mips_intrcnt_setname(counter, name); 68 return counter; 69} 70 71void 72mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) 73{ 74 int idx = counter - intrcnt; 75 76 KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); 77 78 snprintf(intrnames + (MAXCOMLEN + 1) * idx, 79 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 80} 81 82static void 83mips_mask_hard_irq(void *source) 84{ 85 uintptr_t irq = (uintptr_t)source; 86 87 mips_wr_status(mips_rd_status() & ~(((1 << irq) << 8) << 2)); 88} 89 90static void 91mips_unmask_hard_irq(void *source) 92{ 93 uintptr_t irq = (uintptr_t)source; 94 95 mips_wr_status(mips_rd_status() | (((1 << irq) << 8) << 2)); 96} 97 98static void 99mips_mask_soft_irq(void *source) 100{ 101 uintptr_t irq = (uintptr_t)source; 102 103 mips_wr_status(mips_rd_status() & ~((1 << irq) << 8)); 104} 105 106static void 107mips_unmask_soft_irq(void *source) 108{ 109 uintptr_t irq = (uintptr_t)source; 110 111 mips_wr_status(mips_rd_status() | ((1 << irq) << 8)); 112} 113 114/* 115 * Perform initialization of interrupts prior to setting 116 * handlings 117 */ 118void 119cpu_init_interrupts() 120{ 121 int i; 122 char name[MAXCOMLEN + 1]; 123 124 /* 125 * Initialize all available vectors so spare IRQ 126 * would show up in systat output 127 */ 128 for (i = 0; i < NSOFT_IRQS; i++) { 129 snprintf(name, MAXCOMLEN + 1, "sint%d:", i); 130 mips_intr_counters[i] = mips_intrcnt_create(name); 131 } 132 133 for (i = 0; i < NHARD_IRQS; i++) { 134 snprintf(name, MAXCOMLEN + 1, "int%d:", i); 135 mips_intr_counters[NSOFT_IRQS + i] = mips_intrcnt_create(name); 136 } 137} 138 139void 140cpu_set_hardintr_mask_func(cpu_intr_mask_t func) 141{ 142 143 hardintr_mask_func = func; 144} 145 146void 147cpu_set_hardintr_unmask_func(cpu_intr_unmask_t func) 148{ 149 150 hardintr_unmask_func = func; 151} 152 153void 154cpu_establish_hardintr(const char *name, driver_filter_t *filt, 155 void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) 156{ 157 struct intr_event *event; 158 int error; 159 160 /* 161 * We have 6 levels, but thats 0 - 5 (not including 6) 162 */ 163 if (irq < 0 || irq >= NHARD_IRQS) 164 panic("%s called for unknown hard intr %d", __func__, irq); 165 166 if (hardintr_mask_func == NULL) 167 hardintr_mask_func = mips_mask_hard_irq; 168 169 if (hardintr_unmask_func == NULL) 170 hardintr_unmask_func = mips_unmask_hard_irq; 171 172 event = hardintr_events[irq]; 173 if (event == NULL) { 174 error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, 175 irq, hardintr_mask_func, hardintr_unmask_func, 176 NULL, NULL, "int%d", irq); 177 if (error) 178 return; 179 hardintr_events[irq] = event; 180 mips_unmask_hard_irq((void*)(uintptr_t)irq); 181 } 182 183 intr_event_add_handler(event, name, filt, handler, arg, 184 intr_priority(flags), flags, cookiep); 185 186 mips_intrcnt_setname(mips_intr_counters[NSOFT_IRQS + irq], 187 event->ie_fullname); 188} 189 190void 191cpu_establish_softintr(const char *name, driver_filter_t *filt, 192 void (*handler)(void*), void *arg, int irq, int flags, 193 void **cookiep) 194{ 195 struct intr_event *event; 196 int error; 197 198#if 0 199 printf("Establish SOFT IRQ %d: filt %p handler %p arg %p\n", 200 irq, filt, handler, arg); 201#endif 202 if (irq < 0 || irq > NSOFT_IRQS) 203 panic("%s called for unknown hard intr %d", __func__, irq); 204 205 event = softintr_events[irq]; 206 if (event == NULL) { 207 error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, 208 irq, mips_mask_soft_irq, mips_unmask_soft_irq, 209 NULL, NULL, "sint%d:", irq); 210 if (error) 211 return; 212 softintr_events[irq] = event; 213 mips_unmask_soft_irq((void*)(uintptr_t)irq); 214 } 215 216 intr_event_add_handler(event, name, filt, handler, arg, 217 intr_priority(flags), flags, cookiep); 218 219 mips_intrcnt_setname(mips_intr_counters[irq], event->ie_fullname); 220} 221 222void 223cpu_intr(struct trapframe *tf) 224{ 225 struct intr_event *event; 226 register_t cause, status; 227 int hard, i, intr; 228 229 critical_enter(); 230 231 cause = mips_rd_cause(); 232 status = mips_rd_status(); 233 intr = (cause & MIPS_INT_MASK) >> 8; 234 /* 235 * Do not handle masked interrupts. They were masked by 236 * pre_ithread function (mips_mask_XXX_intr) and will be 237 * unmasked once ithread is through with handler 238 */ 239 intr &= (status & MIPS_INT_MASK) >> 8; 240 while ((i = fls(intr)) != 0) { 241 intr &= ~(1 << (i - 1)); 242 switch (i) { 243 case 1: case 2: 244 /* Software interrupt. */ 245 i--; /* Get a 0-offset interrupt. */ 246 hard = 0; 247 event = softintr_events[i]; 248 mips_intrcnt_inc(mips_intr_counters[i]); 249 break; 250 default: 251 /* Hardware interrupt. */ 252 i -= 2; /* Trim software interrupt bits. */ 253 i--; /* Get a 0-offset interrupt. */ 254 hard = 1; 255 event = hardintr_events[i]; 256 mips_intrcnt_inc(mips_intr_counters[NSOFT_IRQS + i]); 257 break; 258 } 259 260 if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 261 printf("stray %s interrupt %d\n", 262 hard ? "hard" : "soft", i); 263 continue; 264 } 265 266 if (intr_event_handle(event, tf) != 0) { 267 printf("stray %s interrupt %d\n", 268 hard ? "hard" : "soft", i); 269 } 270 } 271 272 KASSERT(i == 0, ("all interrupts handled")); 273 274 critical_exit(); 275 276#ifdef HWPMC_HOOKS 277 if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN)) 278 pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf); 279#endif 280} 281