intr_machdep.c revision 211893
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 211893 2010-08-27 19:53:57Z jchandra $"); 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 52struct xlr_intrsrc { 53 void (*busack)(int); /* Additional ack */ 54 struct intr_event *ie; /* event corresponding to intr */ 55 int irq; 56}; 57 58static struct xlr_intrsrc xlr_interrupts[XLR_MAX_INTR]; 59static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; 60static int intrcnt_index; 61 62void 63xlr_enable_irq(int irq) 64{ 65 66 write_c0_eimr64(read_c0_eimr64() | (1ULL << irq)); 67} 68 69void 70cpu_establish_softintr(const char *name, driver_filter_t * filt, 71 void (*handler) (void *), void *arg, int irq, int flags, 72 void **cookiep) 73{ 74 75 panic("Soft interrupts unsupported!\n"); 76} 77 78void 79cpu_establish_hardintr(const char *name, driver_filter_t * filt, 80 void (*handler) (void *), void *arg, int irq, int flags, 81 void **cookiep) 82{ 83 84 xlr_establish_intr(name, filt, handler, arg, irq, flags, 85 cookiep, NULL); 86} 87 88static void 89xlr_post_filter(void *source) 90{ 91 struct xlr_intrsrc *src = source; 92 93 if (src->busack) 94 src->busack(src->irq); 95 pic_ack(PIC_IRQ_TO_INTR(src->irq)); 96} 97 98static void 99xlr_pre_ithread(void *source) 100{ 101 struct xlr_intrsrc *src = source; 102 103 if (src->busack) 104 src->busack(src->irq); 105} 106 107static void 108xlr_post_ithread(void *source) 109{ 110 struct xlr_intrsrc *src = source; 111 112 pic_ack(PIC_IRQ_TO_INTR(src->irq)); 113} 114 115void 116xlr_establish_intr(const char *name, driver_filter_t filt, 117 driver_intr_t handler, void *arg, int irq, int flags, 118 void **cookiep, void (*busack)(int)) 119{ 120 struct intr_event *ie; /* descriptor for the IRQ */ 121 struct xlr_intrsrc *src = NULL; 122 int errcode; 123 124 if (irq < 0 || irq > XLR_MAX_INTR) 125 panic("%s called for unknown hard intr %d", __func__, irq); 126 127 /* 128 * FIXME locking - not needed now, because we do this only on 129 * startup from CPU0 130 */ 131 printf("[%s] Setup intr %d called on cpu %d (%d)\n", name, irq, 132 xlr_cpu_id(), PCPU_GET(cpuid)); 133 134 src = &xlr_interrupts[irq]; 135 ie = src->ie; 136 if (ie == NULL) { 137 /* 138 * PIC based interrupts need ack in PIC, and some SoC 139 * components need additional acks (e.g. PCI) 140 */ 141 if (PIC_IRQ_IS_PICINTR(irq)) 142 errcode = intr_event_create(&ie, src, 0, irq, 143 xlr_pre_ithread, xlr_post_ithread, xlr_post_filter, 144 NULL, "hard intr%d:", irq); 145 else { 146 if (filt == NULL) 147 panic("Not supported - non filter percpu intr"); 148 errcode = intr_event_create(&ie, src, 0, irq, 149 NULL, NULL, NULL, NULL, "hard intr%d:", irq); 150 } 151 if (errcode) { 152 printf("Could not create event for intr %d\n", irq); 153 return; 154 } 155 src->irq = irq; 156 src->busack = busack; 157 src->ie = ie; 158 } 159 intr_event_add_handler(ie, name, filt, handler, arg, 160 intr_priority(flags), flags, cookiep); 161 xlr_enable_irq(irq); 162} 163 164void 165cpu_intr(struct trapframe *tf) 166{ 167 struct intr_event *ie; 168 uint64_t eirr, eimr; 169 int i; 170 171 critical_enter(); 172 173 /* find a list of enabled interrupts */ 174 eirr = read_c0_eirr64(); 175 eimr = read_c0_eimr64(); 176 eirr &= eimr; 177 178 if (eirr == 0) { 179 critical_exit(); 180 return; 181 } 182 /* 183 * No need to clear the EIRR here as the handler writes to 184 * compare which ACKs the interrupt. 185 */ 186 if (eirr & (1 << IRQ_TIMER)) { 187 intr_event_handle(xlr_interrupts[IRQ_TIMER].ie, tf); 188 critical_exit(); 189 return; 190 } 191 192 /* FIXME sched pin >? LOCK>? */ 193 for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { 194 if ((eirr & (1ULL << i)) == 0) 195 continue; 196 197 ie = xlr_interrupts[i].ie; 198 /* Don't account special IRQs */ 199 switch (i) { 200 case IRQ_IPI: 201 case IRQ_MSGRING: 202 break; 203 default: 204 mips_intrcnt_inc(mips_intr_counters[i]); 205 } 206 207 /* Ack the IRQ on the CPU */ 208 write_c0_eirr64(1ULL << i); 209 if (intr_event_handle(ie, tf) != 0) { 210 printf("stray interrupt %d\n", i); 211 } 212 } 213 critical_exit(); 214} 215 216void 217mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) 218{ 219 int idx = counter - intrcnt; 220 221 KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); 222 223 snprintf(intrnames + (MAXCOMLEN + 1) * idx, 224 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 225} 226 227mips_intrcnt_t 228mips_intrcnt_create(const char* name) 229{ 230 mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; 231 232 mips_intrcnt_setname(counter, name); 233 return counter; 234} 235 236void 237cpu_init_interrupts() 238{ 239 int i; 240 char name[MAXCOMLEN + 1]; 241 242 /* 243 * Initialize all available vectors so spare IRQ 244 * would show up in systat output 245 */ 246 for (i = 0; i < XLR_MAX_INTR; i++) { 247 snprintf(name, MAXCOMLEN + 1, "int%d:", i); 248 mips_intr_counters[i] = mips_intrcnt_create(name); 249 } 250} 251