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