intr_machdep.c revision 208165
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 208165 2010-05-16 19:43:48Z 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]; 54static struct intr_event *mips_intr_events[XLR_MAX_INTR]; 55static int intrcnt_index; 56 57void 58xlr_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 65void 66xlr_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 74xlr_cpu_establish_hardintr(const char *name, driver_filter_t * filt, 75 void (*handler) (void *), void *arg, int irq, int flags, void **cookiep, 76 void (*pre_ithread)(void *), void (*post_ithread)(void *), 77 void (*post_filter)(void *), int (*assign_cpu)(void *, u_char)) 78{ 79 struct intr_event *ie; /* descriptor for the IRQ */ 80 int errcode; 81 82 if (irq < 0 || irq > XLR_MAX_INTR) 83 panic("%s called for unknown hard intr %d", __func__, irq); 84 85 /* 86 * FIXME locking - not needed now, because we do this only on 87 * startup from CPU0 88 */ 89 ie = mips_intr_events[irq]; 90 /* mih->cntp = &intrcnt[irq]; */ 91 if (ie == NULL) { 92 errcode = intr_event_create(&ie, (void *)(uintptr_t) irq, 0, 93 irq, pre_ithread, post_ithread, post_filter, assign_cpu, 94 "hard intr%d:", irq); 95 96 if (errcode) { 97 printf("Could not create event for intr %d\n", irq); 98 return; 99 } 100 mips_intr_events[irq] = ie; 101 } 102 103 intr_event_add_handler(ie, name, filt, handler, arg, 104 intr_priority(flags), flags, cookiep); 105 xlr_unmask_hard_irq((void *)(uintptr_t) irq); 106} 107 108void 109cpu_establish_hardintr(const char *name, driver_filter_t * filt, 110 void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) 111{ 112 xlr_cpu_establish_hardintr(name, filt, handler, arg, irq, 113 flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq, 114 NULL, NULL); 115} 116 117void 118cpu_establish_softintr(const char *name, driver_filter_t * filt, 119 void (*handler) (void *), void *arg, int irq, int flags, 120 void **cookiep) 121{ 122 /* we don't separate them into soft/hard like other mips */ 123 xlr_cpu_establish_hardintr(name, filt, handler, arg, irq, 124 flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq, 125 NULL, NULL); 126} 127 128void 129cpu_intr(struct trapframe *tf) 130{ 131 struct intr_event *ie; 132 uint64_t eirr, eimr; 133 int i; 134 135 critical_enter(); 136 137 /* find a list of enabled interrupts */ 138 eirr = read_c0_eirr64(); 139 eimr = read_c0_eimr64(); 140 eirr &= eimr; 141 142 if (eirr == 0) { 143 critical_exit(); 144 return; 145 } 146 /* 147 * No need to clear the EIRR here. the handler is gonna write to 148 * compare which clears eirr also 149 */ 150 if (eirr & (1 << IRQ_TIMER)) { 151 count_compare_clockhandler(tf); 152 critical_exit(); 153 return; 154 } 155 156 /* FIXME sched pin >? LOCK>? */ 157 for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { 158 if ((eirr & (1ULL << i)) == 0) 159 continue; 160 161 ie = mips_intr_events[i]; 162 /* Don't account special IRQs */ 163 switch (i) { 164 case IRQ_IPI: 165 case IRQ_MSGRING: 166 break; 167 default: 168 mips_intrcnt_inc(mips_intr_counters[i]); 169 } 170 write_c0_eirr64(1ULL << i); 171 pic_ack(i, 0); 172 if (!ie || TAILQ_EMPTY(&ie->ie_handlers)) { 173 printf("stray interrupt %d\n", i); 174 continue; 175 } 176 if (intr_event_handle(ie, tf) != 0) { 177 printf("stray interrupt %d\n", i); 178 } 179 pic_delayed_ack(i, 0); 180 } 181 critical_exit(); 182} 183 184void 185mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) 186{ 187 int idx = counter - intrcnt; 188 189 KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); 190 191 snprintf(intrnames + (MAXCOMLEN + 1) * idx, 192 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 193} 194 195mips_intrcnt_t 196mips_intrcnt_create(const char* name) 197{ 198 mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; 199 200 mips_intrcnt_setname(counter, name); 201 return counter; 202} 203 204void 205cpu_init_interrupts() 206{ 207 int i; 208 char name[MAXCOMLEN + 1]; 209 210 /* 211 * Initialize all available vectors so spare IRQ 212 * would show up in systat output 213 */ 214 for (i = 0; i < XLR_MAX_INTR; i++) { 215 snprintf(name, MAXCOMLEN + 1, "int%d:", i); 216 mips_intr_counters[i] = mips_intrcnt_create(name); 217 } 218} 219