intr_machdep.c revision 203024
1/*- 2 * Copyright (c) 2006-2009 RMI Corporation 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: head/sys/mips/rmi/intr_machdep.c 203024 2010-01-26 14:33:57Z rrs $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/interrupt.h> 36#include <sys/kernel.h> 37 38#include <machine/cpu.h> 39#include <machine/cpufunc.h> 40#include <machine/cpuinfo.h> 41#include <machine/cpuregs.h> 42#include <machine/frame.h> 43#include <machine/intr_machdep.h> 44#include <machine/md_var.h> 45#include <machine/trap.h> 46#include <machine/hwfunc.h> 47#include <mips/rmi/xlrconfig.h> 48#include <mips/rmi/interrupt.h> 49#include <mips/rmi/clock.h> 50#include <mips/rmi/pic.h> 51 52/*#include <machine/intrcnt.h>*/ 53static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; 54struct mips_intrhand mips_intr_handlers[XLR_MAX_INTR]; 55static int intrcnt_index; 56 57static void 58mips_mask_hard_irq(void *source) 59{ 60 uintptr_t irq = (uintptr_t) source; 61 62 write_c0_eimr64(read_c0_eimr64() & ~(1ULL << irq)); 63} 64 65static void 66mips_unmask_hard_irq(void *source) 67{ 68 uintptr_t irq = (uintptr_t) source; 69 70 write_c0_eimr64(read_c0_eimr64() | (1ULL << irq)); 71} 72 73void 74cpu_establish_hardintr(const char *name, driver_filter_t * filt, 75 void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) 76{ 77 struct mips_intrhand *mih; /* descriptor for the IRQ */ 78 struct intr_event *ie; /* descriptor for the IRQ */ 79 int errcode; 80 81 if (irq < 0 || irq > XLR_MAX_INTR) 82 panic("%s called for unknown hard intr %d", __func__, irq); 83 84 /* 85 * FIXME locking - not needed now, because we do this only on 86 * startup from CPU0 87 */ 88 mih = &mips_intr_handlers[irq]; 89 /* mih->cntp = &intrcnt[irq]; */ 90 ie = mih->mih_event; 91 if (ie == NULL) { 92 errcode = intr_event_create(&ie, (void *)(uintptr_t) irq, 0, 93 irq, mips_mask_hard_irq, mips_unmask_hard_irq, 94 NULL, NULL, "hard intr%d:", irq); 95 96 if (errcode) { 97 printf("Could not create event for intr %d\n", irq); 98 return; 99 } 100 } 101 intr_event_add_handler(ie, name, filt, handler, arg, 102 intr_priority(flags), flags, cookiep); 103 mih->mih_event = ie; 104 mips_unmask_hard_irq((void *)(uintptr_t) irq); 105} 106 107 108void 109cpu_establish_softintr(const char *name, driver_filter_t * filt, 110 void (*handler) (void *), void *arg, int irq, int flags, 111 void **cookiep) 112{ 113 /* we don't separate them into soft/hard like other mips */ 114 cpu_establish_hardintr(name, filt, handler, arg, irq, flags, cookiep); 115} 116 117void 118cpu_intr(struct trapframe *tf) 119{ 120 struct mips_intrhand *mih; 121 struct intr_event *ie; 122 register_t eirr; 123 int i; 124 125 critical_enter(); 126 eirr = read_c0_eirr64(); 127 if (eirr == 0) { 128 critical_exit(); 129 return; 130 } 131 /* 132 * No need to clear the EIRR here. the handler is gonna write to 133 * compare which clears eirr also 134 */ 135 if (eirr & (1 << IRQ_TIMER)) { 136 count_compare_clockhandler(tf); 137 critical_exit(); 138 return; 139 } 140 141 /* FIXME sched pin >? LOCK>? */ 142 for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { 143 if ((eirr & (1ULL << i)) == 0) 144 continue; 145#ifdef SMP 146 /* These are reserved interrupts */ 147 if ((i == IPI_AST) || (i == IPI_RENDEZVOUS) || (i == IPI_STOP) 148 || (i == IPI_SMP_CALL_FUNCTION)) { 149 write_c0_eirr64(1ULL << i); 150 pic_ack(i, 0); 151 smp_handle_ipi(tf, i); 152 pic_delayed_ack(i, 0); 153 continue; 154 } 155#ifdef XLR_PERFMON 156 if (i == IPI_PERFMON) { 157 write_c0_eirr64(1ULL << i); 158 pic_ack(i, 0); 159 xlr_perfmon_sampler(NULL); 160 pic_delayed_ack(i, 0); 161 continue; 162 } 163#endif 164#endif 165 mih = &mips_intr_handlers[i]; 166 /* atomic_add_long(mih->cntp, 1); */ 167 ie = mih->mih_event; 168 169 write_c0_eirr64(1ULL << i); 170 pic_ack(i, 0); 171 if (!ie || TAILQ_EMPTY(&ie->ie_handlers)) { 172 printf("stray interrupt %d\n", i); 173 continue; 174 } 175 if (intr_event_handle(ie, tf) != 0) { 176 printf("stray interrupt %d\n", i); 177 } 178 pic_delayed_ack(i, 0); 179 } 180 critical_exit(); 181} 182 183void 184mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) 185{ 186 int idx = counter - intrcnt; 187 188 KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); 189 190 snprintf(intrnames + (MAXCOMLEN + 1) * idx, 191 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 192} 193 194mips_intrcnt_t 195mips_intrcnt_create(const char* name) 196{ 197 mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; 198 199 mips_intrcnt_setname(counter, name); 200 return counter; 201} 202 203void 204cpu_init_interrupts() 205{ 206 int i; 207 char name[MAXCOMLEN + 1]; 208 209 /* 210 * Initialize all available vectors so spare IRQ 211 * would show up in systat output 212 */ 213 for (i = 0; i < XLR_MAX_INTR; i++) { 214 snprintf(name, MAXCOMLEN + 1, "int%d:", i); 215 mips_intr_counters[i] = mips_intrcnt_create(name); 216 } 217} 218