intr_machdep.c revision 198484
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$"); 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 <machine/intrcnt.h> 48 49struct mips_intrhand mips_intr_handlers[XLR_MAX_INTR]; 50 51static void 52mips_mask_hard_irq(void *source) 53{ 54 uintptr_t irq = (uintptr_t)source; 55 56 write_c0_eimr64(read_c0_eimr64() & ~(1ULL<<irq)); 57} 58 59static void 60mips_unmask_hard_irq(void *source) 61{ 62 uintptr_t irq = (uintptr_t)source; 63 64 write_c0_eimr64(read_c0_eimr64() | (1ULL<<irq)); 65} 66 67void 68cpu_establish_hardintr(const char *name, driver_filter_t *filt, 69 void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) 70{ 71 struct mips_intrhand *mih; /* descriptor for the IRQ */ 72 struct intr_event *ie; /* descriptor for the IRQ */ 73 int errcode; 74 75 if (intr < 0 || intr > XLR_MAX_INTR) 76 panic("%s called for unknown hard intr %d", __func__, intr); 77 78 /* FIXME locking - not needed now, because we do this only on startup from 79 CPU0 */ 80 mih = &mips_intr_handlers[irq]; 81 mih->cntp = &intrcnt[irq]; 82 ie = mih->mih_event; 83 if (ie == NULL) { 84 errcode = intr_event_create(&event, (void *)(uintptr_t)irq, 0, 85 irq, mips_mask_hard_irq, mips_unmask_hard_irq, 86 NULL, NULL, "hard intr%d:", irq); 87 88 if (errcode) { 89 printf("Could not create event for intr %d\n", irq); 90 return; 91 } 92 } 93 intr_event_add_handler(event, name, filt, handler, arg, 94 intr_priority(flags), flags, cookiep); 95 mih->mih_event = ie; 96 mips_unmask_hard_irq((void*)(uintptr_t)irq); 97} 98 99 100void 101cpu_establish_softintr(const char *name, driver_filter_t *filt, 102 void (*handler)(void*), void *arg, int irq, int flags, 103 void **cookiep) 104{ 105 /* we don't separate them into soft/hard like other mips */ 106 cpu_establish_hardintr(name, filt, handler, arg, intr, flags, cookiep); 107} 108 109void 110cpu_intr(struct trapframe *tf) 111{ 112 struct mips_intrhand *mih; 113 struct intr_handler *ih; 114 struct intr_event *ie; 115 register_t eirr; 116 int i, thread, error; 117 118 critical_enter(); 119 eirr = read_c0_eirr64(); 120 if (eirr == 0) { 121 critical_exit(); 122 return; 123 } 124 125 /* No need to clear the EIRR here. the handler is gonna 126 * write to compare which clears eirr also 127 */ 128 if (eirr & (1 << IRQ_TIMER)) { 129 count_compare_clockhandler(tf); 130 critical_exit(); 131 return; 132 } 133 134 /* FIXME sched pin >? LOCK>? */ 135 for(i = sizeof(eirr)*8 - 1; i>=0; i--) { 136 if ((eirr & 1ULL<<i) == 0) 137 continue; 138#ifdef SMP 139 /* These are reserved interrupts */ 140 if((i == IPI_AST) || (i == IPI_RENDEZVOUS) || (i == IPI_STOP) 141 || (i == IPI_SMP_CALL_FUNCTION)) { 142 write_c0_eirr64(1ULL << i); 143 pic_ack(i); 144 smp_handle_ipi(tf, i); 145 pic_delayed_ack(i); 146 continue; 147 } 148#ifdef XLR_PERFMON 149 if (i == IPI_PERFMON) { 150 write_c0_eirr64(1ULL << i); 151 pic_ack(i); 152 xlr_perfmon_sampler(NULL); 153 pic_delayed_ack(i); 154 continue; 155 } 156#endif 157#endif 158 mih = &mips_intr_handlers[i]; 159 atomic_add_long(mih->cntp, 1); 160 ie = mih->mih_event; 161 162 write_c0_eirr64(1ULL << i); 163 if (!ie || TAILQ_EMPTY(&ie->ie_handlers)) { 164 printf("stray interrupt %d\n", i); 165 continue; 166 } 167 168 if (intr_event_handle(ie, tf) != 0) { 169 printf("stray %s interrupt %d\n", 170 hard ? "hard" : "soft", i); 171 } 172 173 } 174 critical_exit(); 175} 176