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