intr_machdep.c revision 279305
1/*- 2 * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights 3 * reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * NETLOGIC_BSD */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/mips/nlm/intr_machdep.c 279305 2015-02-26 02:05:45Z jchandra $"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36#include <sys/interrupt.h> 37#include <sys/kernel.h> 38#include <sys/module.h> 39 40#include <dev/ofw/ofw_bus.h> 41#include <dev/ofw/ofw_bus_subr.h> 42 43#include <machine/cpu.h> 44#include <machine/cpufunc.h> 45#include <machine/cpuinfo.h> 46#include <machine/cpuregs.h> 47#include <machine/frame.h> 48#include <machine/intr_machdep.h> 49#include <machine/md_var.h> 50#include <machine/trap.h> 51#include <machine/hwfunc.h> 52 53#include <mips/nlm/hal/haldefs.h> 54#include <mips/nlm/hal/iomap.h> 55#include <mips/nlm/hal/mips-extns.h> 56#include <mips/nlm/interrupt.h> 57#include <mips/nlm/hal/pic.h> 58#include <mips/nlm/xlp.h> 59 60struct xlp_intrsrc { 61 void (*busack)(int); /* Additional ack */ 62 struct intr_event *ie; /* event corresponding to intr */ 63 int irq; 64}; 65 66static struct xlp_intrsrc xlp_interrupts[XLR_MAX_INTR]; 67static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; 68static int intrcnt_index; 69 70void 71xlp_enable_irq(int irq) 72{ 73 uint64_t eimr; 74 75 eimr = nlm_read_c0_eimr(); 76 nlm_write_c0_eimr(eimr | (1ULL << irq)); 77} 78 79void 80cpu_establish_softintr(const char *name, driver_filter_t * filt, 81 void (*handler) (void *), void *arg, int irq, int flags, 82 void **cookiep) 83{ 84 85 panic("Soft interrupts unsupported!\n"); 86} 87 88void 89cpu_establish_hardintr(const char *name, driver_filter_t * filt, 90 void (*handler) (void *), void *arg, int irq, int flags, 91 void **cookiep) 92{ 93 94 xlp_establish_intr(name, filt, handler, arg, irq, flags, 95 cookiep, NULL); 96} 97 98static void 99xlp_post_filter(void *source) 100{ 101 struct xlp_intrsrc *src = source; 102 103 if (src->busack) 104 src->busack(src->irq); 105 nlm_pic_ack(xlp_pic_base, xlp_irq_to_irt(src->irq)); 106} 107 108static void 109xlp_pre_ithread(void *source) 110{ 111 struct xlp_intrsrc *src = source; 112 113 if (src->busack) 114 src->busack(src->irq); 115} 116 117static void 118xlp_post_ithread(void *source) 119{ 120 struct xlp_intrsrc *src = source; 121 122 nlm_pic_ack(xlp_pic_base, xlp_irq_to_irt(src->irq)); 123} 124 125void 126xlp_establish_intr(const char *name, driver_filter_t filt, 127 driver_intr_t handler, void *arg, int irq, int flags, 128 void **cookiep, void (*busack)(int)) 129{ 130 struct intr_event *ie; /* descriptor for the IRQ */ 131 struct xlp_intrsrc *src = NULL; 132 int errcode; 133 134 if (irq < 0 || irq > XLR_MAX_INTR) 135 panic("%s called for unknown hard intr %d", __func__, irq); 136 137 /* 138 * FIXME locking - not needed now, because we do this only on 139 * startup from CPU0 140 */ 141 src = &xlp_interrupts[irq]; 142 ie = src->ie; 143 if (ie == NULL) { 144 /* 145 * PIC based interrupts need ack in PIC, and some SoC 146 * components need additional acks (e.g. PCI) 147 */ 148 if (XLP_IRQ_IS_PICINTR(irq)) 149 errcode = intr_event_create(&ie, src, 0, irq, 150 xlp_pre_ithread, xlp_post_ithread, xlp_post_filter, 151 NULL, "hard intr%d:", irq); 152 else { 153 if (filt == NULL) 154 panic("Unsupported non filter percpu intr %d", irq); 155 errcode = intr_event_create(&ie, src, 0, irq, 156 NULL, NULL, NULL, NULL, "hard intr%d:", irq); 157 } 158 if (errcode) { 159 printf("Could not create event for intr %d\n", irq); 160 return; 161 } 162 src->irq = irq; 163 src->busack = busack; 164 src->ie = ie; 165 } 166 intr_event_add_handler(ie, name, filt, handler, arg, 167 intr_priority(flags), flags, cookiep); 168 xlp_enable_irq(irq); 169} 170 171void 172cpu_intr(struct trapframe *tf) 173{ 174 struct intr_event *ie; 175 uint64_t eirr, eimr; 176 int i; 177 178 critical_enter(); 179 180 /* find a list of enabled interrupts */ 181 eirr = nlm_read_c0_eirr(); 182 eimr = nlm_read_c0_eimr(); 183 eirr &= eimr; 184 185 if (eirr == 0) { 186 critical_exit(); 187 return; 188 } 189 /* 190 * No need to clear the EIRR here as the handler writes to 191 * compare which ACKs the interrupt. 192 */ 193 if (eirr & (1 << IRQ_TIMER)) { 194 intr_event_handle(xlp_interrupts[IRQ_TIMER].ie, tf); 195 critical_exit(); 196 return; 197 } 198 199 /* FIXME sched pin >? LOCK>? */ 200 for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { 201 if ((eirr & (1ULL << i)) == 0) 202 continue; 203 204 ie = xlp_interrupts[i].ie; 205 /* Don't account special IRQs */ 206 switch (i) { 207 case IRQ_IPI: 208 case IRQ_MSGRING: 209 break; 210 default: 211 mips_intrcnt_inc(mips_intr_counters[i]); 212 } 213 214 /* Ack the IRQ on the CPU */ 215 nlm_write_c0_eirr(1ULL << i); 216 if (intr_event_handle(ie, tf) != 0) { 217 printf("stray interrupt %d\n", i); 218 } 219 } 220 critical_exit(); 221} 222 223void 224mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) 225{ 226 int idx = counter - intrcnt; 227 228 KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); 229 230 snprintf(intrnames + (MAXCOMLEN + 1) * idx, 231 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 232} 233 234mips_intrcnt_t 235mips_intrcnt_create(const char* name) 236{ 237 mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; 238 239 mips_intrcnt_setname(counter, name); 240 return counter; 241} 242 243void 244cpu_init_interrupts() 245{ 246 int i; 247 char name[MAXCOMLEN + 1]; 248 249 /* 250 * Initialize all available vectors so spare IRQ 251 * would show up in systat output 252 */ 253 for (i = 0; i < XLR_MAX_INTR; i++) { 254 snprintf(name, MAXCOMLEN + 1, "int%d:", i); 255 mips_intr_counters[i] = mips_intrcnt_create(name); 256 } 257} 258 259static int xlp_pic_probe(device_t); 260static int xlp_pic_attach(device_t); 261 262static int 263xlp_pic_probe(device_t dev) 264{ 265 266 if (!ofw_bus_is_compatible(dev, "netlogic,xlp-pic")) 267 return (ENXIO); 268 device_set_desc(dev, "XLP PIC"); 269 return (0); 270} 271 272static int 273xlp_pic_attach(device_t dev) 274{ 275 276 return (0); 277} 278 279static device_method_t xlp_pic_methods[] = { 280 DEVMETHOD(device_probe, xlp_pic_probe), 281 DEVMETHOD(device_attach, xlp_pic_attach), 282 283 DEVMETHOD_END 284}; 285 286static driver_t xlp_pic_driver = { 287 "xlp_pic", 288 xlp_pic_methods, 289 1, /* no softc */ 290}; 291 292static devclass_t xlp_pic_devclass; 293DRIVER_MODULE(xlp_pic, simplebus, xlp_pic_driver, xlp_pic_devclass, 0, 0); 294