1178172Simp/*- 2195162Simp * Copyright (c) 2006 Oleksandr Tymoshenko 3178172Simp * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org> 4178172Simp * All rights reserved. 5178172Simp * 6178172Simp * Redistribution and use in source and binary forms, with or without 7178172Simp * modification, are permitted provided that the following conditions 8178172Simp * are met: 9178172Simp * 1. Redistributions of source code must retain the above copyright 10178172Simp * notice, this list of conditions, and the following disclaimer, 11178172Simp * without modification, immediately at the beginning of the file. 12178172Simp * 2. The name of the author may not be used to endorse or promote products 13178172Simp * derived from this software without specific prior written permission. 14178172Simp * 15178172Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18178172Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19178172Simp * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25178172Simp * SUCH DAMAGE. 26178172Simp * 27178172Simp */ 28178172Simp 29178172Simp#include <sys/cdefs.h> 30178172Simp__FBSDID("$FreeBSD$"); 31178172Simp 32233318Sgonzo#include "opt_hwpmc_hooks.h" 33233318Sgonzo 34178172Simp#include <sys/param.h> 35178172Simp#include <sys/systm.h> 36178172Simp#include <sys/bus.h> 37178172Simp#include <sys/interrupt.h> 38233318Sgonzo#include <sys/pmc.h> 39233318Sgonzo#include <sys/pmckern.h> 40178172Simp 41178172Simp#include <machine/clock.h> 42178172Simp#include <machine/cpu.h> 43178172Simp#include <machine/cpufunc.h> 44178172Simp#include <machine/cpuinfo.h> 45178172Simp#include <machine/cpuregs.h> 46178172Simp#include <machine/frame.h> 47178172Simp#include <machine/intr_machdep.h> 48178172Simp#include <machine/md_var.h> 49178172Simp#include <machine/trap.h> 50178172Simp 51178172Simpstatic struct intr_event *hardintr_events[NHARD_IRQS]; 52178172Simpstatic struct intr_event *softintr_events[NSOFT_IRQS]; 53202046Simpstatic mips_intrcnt_t mips_intr_counters[NSOFT_IRQS + NHARD_IRQS]; 54178172Simp 55202046Simpstatic int intrcnt_index; 56178172Simp 57203697Sneelstatic cpu_intr_mask_t hardintr_mask_func; 58203697Sneelstatic cpu_intr_unmask_t hardintr_unmask_func; 59203697Sneel 60202046Simpmips_intrcnt_t 61202046Simpmips_intrcnt_create(const char* name) 62202046Simp{ 63202046Simp mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; 64202046Simp 65202046Simp mips_intrcnt_setname(counter, name); 66202046Simp return counter; 67202046Simp} 68202046Simp 69182765Sobrienvoid 70202046Simpmips_intrcnt_setname(mips_intrcnt_t counter, const char *name) 71178172Simp{ 72202046Simp int idx = counter - intrcnt; 73178172Simp 74202046Simp KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); 75202046Simp 76202046Simp snprintf(intrnames + (MAXCOMLEN + 1) * idx, 77202046Simp MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 78178172Simp} 79178172Simp 80202046Simpstatic void 81202046Simpmips_mask_hard_irq(void *source) 82202046Simp{ 83202046Simp uintptr_t irq = (uintptr_t)source; 84202046Simp 85202046Simp mips_wr_status(mips_rd_status() & ~(((1 << irq) << 8) << 2)); 86202046Simp} 87202046Simp 88202046Simpstatic void 89202046Simpmips_unmask_hard_irq(void *source) 90202046Simp{ 91202046Simp uintptr_t irq = (uintptr_t)source; 92202046Simp 93202046Simp mips_wr_status(mips_rd_status() | (((1 << irq) << 8) << 2)); 94202046Simp} 95202046Simp 96202046Simpstatic void 97202046Simpmips_mask_soft_irq(void *source) 98202046Simp{ 99202046Simp uintptr_t irq = (uintptr_t)source; 100202046Simp 101202046Simp mips_wr_status(mips_rd_status() & ~((1 << irq) << 8)); 102202046Simp} 103202046Simp 104202046Simpstatic void 105202046Simpmips_unmask_soft_irq(void *source) 106202046Simp{ 107202046Simp uintptr_t irq = (uintptr_t)source; 108202046Simp 109202046Simp mips_wr_status(mips_rd_status() | ((1 << irq) << 8)); 110202046Simp} 111202046Simp 112202046Simp/* 113202046Simp * Perform initialization of interrupts prior to setting 114202046Simp * handlings 115202046Simp */ 116182765Sobrienvoid 117202046Simpcpu_init_interrupts() 118178172Simp{ 119202046Simp int i; 120202046Simp char name[MAXCOMLEN + 1]; 121178172Simp 122202046Simp /* 123202046Simp * Initialize all available vectors so spare IRQ 124202046Simp * would show up in systat output 125202046Simp */ 126202046Simp for (i = 0; i < NSOFT_IRQS; i++) { 127202046Simp snprintf(name, MAXCOMLEN + 1, "sint%d:", i); 128202046Simp mips_intr_counters[i] = mips_intrcnt_create(name); 129202046Simp } 130202046Simp 131202046Simp for (i = 0; i < NHARD_IRQS; i++) { 132202046Simp snprintf(name, MAXCOMLEN + 1, "int%d:", i); 133202046Simp mips_intr_counters[NSOFT_IRQS + i] = mips_intrcnt_create(name); 134202046Simp } 135178172Simp} 136178172Simp 137178172Simpvoid 138203697Sneelcpu_set_hardintr_mask_func(cpu_intr_mask_t func) 139203697Sneel{ 140203697Sneel 141203697Sneel hardintr_mask_func = func; 142203697Sneel} 143203697Sneel 144203697Sneelvoid 145203697Sneelcpu_set_hardintr_unmask_func(cpu_intr_unmask_t func) 146203697Sneel{ 147203697Sneel 148203697Sneel hardintr_unmask_func = func; 149203697Sneel} 150203697Sneel 151203697Sneelvoid 152182765Sobriencpu_establish_hardintr(const char *name, driver_filter_t *filt, 153182765Sobrien void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) 154178172Simp{ 155182765Sobrien struct intr_event *event; 156182765Sobrien int error; 157178172Simp 158178172Simp /* 159178172Simp * We have 6 levels, but thats 0 - 5 (not including 6) 160178172Simp */ 161178172Simp if (irq < 0 || irq >= NHARD_IRQS) 162178172Simp panic("%s called for unknown hard intr %d", __func__, irq); 163178172Simp 164203697Sneel if (hardintr_mask_func == NULL) 165203697Sneel hardintr_mask_func = mips_mask_hard_irq; 166203697Sneel 167203697Sneel if (hardintr_unmask_func == NULL) 168203697Sneel hardintr_unmask_func = mips_unmask_hard_irq; 169203697Sneel 170182765Sobrien event = hardintr_events[irq]; 171182765Sobrien if (event == NULL) { 172202046Simp error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, 173203697Sneel irq, hardintr_mask_func, hardintr_unmask_func, 174202046Simp NULL, NULL, "int%d", irq); 175182765Sobrien if (error) 176182765Sobrien return; 177182765Sobrien hardintr_events[irq] = event; 178203697Sneel mips_unmask_hard_irq((void*)(uintptr_t)irq); 179182765Sobrien } 180178172Simp 181182765Sobrien intr_event_add_handler(event, name, filt, handler, arg, 182182765Sobrien intr_priority(flags), flags, cookiep); 183182765Sobrien 184203697Sneel mips_intrcnt_setname(mips_intr_counters[NSOFT_IRQS + irq], 185203697Sneel event->ie_fullname); 186178172Simp} 187178172Simp 188178172Simpvoid 189182765Sobriencpu_establish_softintr(const char *name, driver_filter_t *filt, 190182765Sobrien void (*handler)(void*), void *arg, int irq, int flags, 191178172Simp void **cookiep) 192178172Simp{ 193182765Sobrien struct intr_event *event; 194182765Sobrien int error; 195178172Simp 196202046Simp#if 0 197182765Sobrien printf("Establish SOFT IRQ %d: filt %p handler %p arg %p\n", 198182765Sobrien irq, filt, handler, arg); 199202046Simp#endif 200178172Simp if (irq < 0 || irq > NSOFT_IRQS) 201178172Simp panic("%s called for unknown hard intr %d", __func__, irq); 202178172Simp 203182765Sobrien event = softintr_events[irq]; 204182765Sobrien if (event == NULL) { 205202046Simp error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, 206202046Simp irq, mips_mask_soft_irq, mips_unmask_soft_irq, 207202046Simp NULL, NULL, "sint%d:", irq); 208182765Sobrien if (error) 209182765Sobrien return; 210182765Sobrien softintr_events[irq] = event; 211203697Sneel mips_unmask_soft_irq((void*)(uintptr_t)irq); 212182765Sobrien } 213178172Simp 214182765Sobrien intr_event_add_handler(event, name, filt, handler, arg, 215182765Sobrien intr_priority(flags), flags, cookiep); 216178172Simp 217202046Simp mips_intrcnt_setname(mips_intr_counters[irq], event->ie_fullname); 218178172Simp} 219178172Simp 220178172Simpvoid 221178172Simpcpu_intr(struct trapframe *tf) 222178172Simp{ 223178172Simp struct intr_event *event; 224202046Simp register_t cause, status; 225183174Simp int hard, i, intr; 226178172Simp 227178172Simp critical_enter(); 228178172Simp 229178172Simp cause = mips_rd_cause(); 230202046Simp status = mips_rd_status(); 231178172Simp intr = (cause & MIPS_INT_MASK) >> 8; 232202046Simp /* 233202046Simp * Do not handle masked interrupts. They were masked by 234202046Simp * pre_ithread function (mips_mask_XXX_intr) and will be 235202046Simp * unmasked once ithread is through with handler 236202046Simp */ 237202046Simp intr &= (status & MIPS_INT_MASK) >> 8; 238178172Simp while ((i = fls(intr)) != 0) { 239178172Simp intr &= ~(1 << (i - 1)); 240178172Simp switch (i) { 241178172Simp case 1: case 2: 242178172Simp /* Software interrupt. */ 243178172Simp i--; /* Get a 0-offset interrupt. */ 244178172Simp hard = 0; 245178172Simp event = softintr_events[i]; 246202046Simp mips_intrcnt_inc(mips_intr_counters[i]); 247178172Simp break; 248178172Simp default: 249178172Simp /* Hardware interrupt. */ 250178172Simp i -= 2; /* Trim software interrupt bits. */ 251178172Simp i--; /* Get a 0-offset interrupt. */ 252178172Simp hard = 1; 253178172Simp event = hardintr_events[i]; 254202046Simp mips_intrcnt_inc(mips_intr_counters[NSOFT_IRQS + i]); 255178172Simp break; 256178172Simp } 257178172Simp 258182765Sobrien if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 259182765Sobrien printf("stray %s interrupt %d\n", 260182765Sobrien hard ? "hard" : "soft", i); 261182765Sobrien continue; 262178172Simp } 263178172Simp 264183174Simp if (intr_event_handle(event, tf) != 0) { 265183174Simp printf("stray %s interrupt %d\n", 266183174Simp hard ? "hard" : "soft", i); 267178172Simp } 268178172Simp } 269178172Simp 270178172Simp KASSERT(i == 0, ("all interrupts handled")); 271178172Simp 272178172Simp critical_exit(); 273233318Sgonzo 274233318Sgonzo#ifdef HWPMC_HOOKS 275233318Sgonzo if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN)) 276233318Sgonzo pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf); 277233318Sgonzo#endif 278178172Simp} 279