1198155Srrs/*- 2198484Srrs * Copyright (c) 2006-2009 RMI Corporation 3198155Srrs * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org> 4198155Srrs * All rights reserved. 5198155Srrs * 6198155Srrs * Redistribution and use in source and binary forms, with or without 7198155Srrs * modification, are permitted provided that the following conditions 8198155Srrs * are met: 9198155Srrs * 1. Redistributions of source code must retain the above copyright 10198155Srrs * notice, this list of conditions, and the following disclaimer, 11198155Srrs * without modification, immediately at the beginning of the file. 12198155Srrs * 2. The name of the author may not be used to endorse or promote products 13198155Srrs * derived from this software without specific prior written permission. 14198155Srrs * 15198155Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16198155Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17198155Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18198155Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19198155Srrs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20198155Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21198155Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22198155Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23198155Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24198155Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25198155Srrs * SUCH DAMAGE. 26198155Srrs * 27198155Srrs */ 28198155Srrs 29198155Srrs#include <sys/cdefs.h> 30198155Srrs__FBSDID("$FreeBSD$"); 31198155Srrs 32198155Srrs#include <sys/param.h> 33198155Srrs#include <sys/systm.h> 34198155Srrs#include <sys/bus.h> 35198155Srrs#include <sys/interrupt.h> 36198155Srrs#include <sys/kernel.h> 37198155Srrs 38198155Srrs#include <machine/cpu.h> 39198155Srrs#include <machine/cpufunc.h> 40198155Srrs#include <machine/cpuinfo.h> 41198155Srrs#include <machine/cpuregs.h> 42198155Srrs#include <machine/frame.h> 43198155Srrs#include <machine/intr_machdep.h> 44198155Srrs#include <machine/md_var.h> 45198155Srrs#include <machine/trap.h> 46198155Srrs#include <machine/hwfunc.h> 47211994Sjchandra 48211994Sjchandra#include <mips/rmi/rmi_mips_exts.h> 49198607Srrs#include <mips/rmi/interrupt.h> 50199203Srrs#include <mips/rmi/pic.h> 51198155Srrs 52211893Sjchandrastruct xlr_intrsrc { 53211893Sjchandra void (*busack)(int); /* Additional ack */ 54211893Sjchandra struct intr_event *ie; /* event corresponding to intr */ 55211893Sjchandra int irq; 56211893Sjchandra}; 57211893Sjchandra 58211893Sjchandrastatic struct xlr_intrsrc xlr_interrupts[XLR_MAX_INTR]; 59200901Srrsstatic mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; 60200901Srrsstatic int intrcnt_index; 61198155Srrs 62204130Srrsvoid 63211893Sjchandraxlr_enable_irq(int irq) 64198155Srrs{ 65212102Sjchandra uint64_t eimr; 66198155Srrs 67212102Sjchandra eimr = read_c0_eimr64(); 68212102Sjchandra write_c0_eimr64(eimr | (1ULL << irq)); 69198155Srrs} 70198155Srrs 71204130Srrsvoid 72211893Sjchandracpu_establish_softintr(const char *name, driver_filter_t * filt, 73211893Sjchandra void (*handler) (void *), void *arg, int irq, int flags, 74211893Sjchandra void **cookiep) 75198155Srrs{ 76198155Srrs 77211893Sjchandra panic("Soft interrupts unsupported!\n"); 78198155Srrs} 79198155Srrs 80198155Srrsvoid 81211893Sjchandracpu_establish_hardintr(const char *name, driver_filter_t * filt, 82211893Sjchandra void (*handler) (void *), void *arg, int irq, int flags, 83211893Sjchandra void **cookiep) 84198155Srrs{ 85211893Sjchandra 86211893Sjchandra xlr_establish_intr(name, filt, handler, arg, irq, flags, 87211893Sjchandra cookiep, NULL); 88211893Sjchandra} 89211893Sjchandra 90211893Sjchandrastatic void 91211893Sjchandraxlr_post_filter(void *source) 92211893Sjchandra{ 93211893Sjchandra struct xlr_intrsrc *src = source; 94211893Sjchandra 95211893Sjchandra if (src->busack) 96211893Sjchandra src->busack(src->irq); 97211893Sjchandra pic_ack(PIC_IRQ_TO_INTR(src->irq)); 98211893Sjchandra} 99211893Sjchandra 100211893Sjchandrastatic void 101211893Sjchandraxlr_pre_ithread(void *source) 102211893Sjchandra{ 103211893Sjchandra struct xlr_intrsrc *src = source; 104211893Sjchandra 105211893Sjchandra if (src->busack) 106211893Sjchandra src->busack(src->irq); 107211893Sjchandra} 108211893Sjchandra 109211893Sjchandrastatic void 110211893Sjchandraxlr_post_ithread(void *source) 111211893Sjchandra{ 112211893Sjchandra struct xlr_intrsrc *src = source; 113211893Sjchandra 114211893Sjchandra pic_ack(PIC_IRQ_TO_INTR(src->irq)); 115211893Sjchandra} 116211893Sjchandra 117211893Sjchandravoid 118211893Sjchandraxlr_establish_intr(const char *name, driver_filter_t filt, 119211893Sjchandra driver_intr_t handler, void *arg, int irq, int flags, 120211893Sjchandra void **cookiep, void (*busack)(int)) 121211893Sjchandra{ 122198625Srrs struct intr_event *ie; /* descriptor for the IRQ */ 123211893Sjchandra struct xlr_intrsrc *src = NULL; 124198155Srrs int errcode; 125198625Srrs 126198607Srrs if (irq < 0 || irq > XLR_MAX_INTR) 127198607Srrs panic("%s called for unknown hard intr %d", __func__, irq); 128198155Srrs 129198625Srrs /* 130198625Srrs * FIXME locking - not needed now, because we do this only on 131198625Srrs * startup from CPU0 132198625Srrs */ 133211893Sjchandra src = &xlr_interrupts[irq]; 134211893Sjchandra ie = src->ie; 135198155Srrs if (ie == NULL) { 136211893Sjchandra /* 137211893Sjchandra * PIC based interrupts need ack in PIC, and some SoC 138211893Sjchandra * components need additional acks (e.g. PCI) 139211893Sjchandra */ 140211893Sjchandra if (PIC_IRQ_IS_PICINTR(irq)) 141211893Sjchandra errcode = intr_event_create(&ie, src, 0, irq, 142211893Sjchandra xlr_pre_ithread, xlr_post_ithread, xlr_post_filter, 143211893Sjchandra NULL, "hard intr%d:", irq); 144211893Sjchandra else { 145211893Sjchandra if (filt == NULL) 146211893Sjchandra panic("Not supported - non filter percpu intr"); 147211893Sjchandra errcode = intr_event_create(&ie, src, 0, irq, 148211893Sjchandra NULL, NULL, NULL, NULL, "hard intr%d:", irq); 149211893Sjchandra } 150198155Srrs if (errcode) { 151198155Srrs printf("Could not create event for intr %d\n", irq); 152198155Srrs return; 153198155Srrs } 154211893Sjchandra src->irq = irq; 155211893Sjchandra src->busack = busack; 156211893Sjchandra src->ie = ie; 157198155Srrs } 158198607Srrs intr_event_add_handler(ie, name, filt, handler, arg, 159198155Srrs intr_priority(flags), flags, cookiep); 160211893Sjchandra xlr_enable_irq(irq); 161198155Srrs} 162198155Srrs 163204130Srrsvoid 164198155Srrscpu_intr(struct trapframe *tf) 165198155Srrs{ 166198155Srrs struct intr_event *ie; 167204130Srrs uint64_t eirr, eimr; 168198607Srrs int i; 169198155Srrs 170198155Srrs critical_enter(); 171204130Srrs 172204130Srrs /* find a list of enabled interrupts */ 173198155Srrs eirr = read_c0_eirr64(); 174204130Srrs eimr = read_c0_eimr64(); 175204130Srrs eirr &= eimr; 176204130Srrs 177204130Srrs if (eirr == 0) { 178198155Srrs critical_exit(); 179198155Srrs return; 180198155Srrs } 181198625Srrs /* 182210528Sjchandra * No need to clear the EIRR here as the handler writes to 183210528Sjchandra * compare which ACKs the interrupt. 184198155Srrs */ 185198155Srrs if (eirr & (1 << IRQ_TIMER)) { 186211893Sjchandra intr_event_handle(xlr_interrupts[IRQ_TIMER].ie, tf); 187198155Srrs critical_exit(); 188198155Srrs return; 189198155Srrs } 190199098Srrs 191198155Srrs /* FIXME sched pin >? LOCK>? */ 192198625Srrs for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { 193199098Srrs if ((eirr & (1ULL << i)) == 0) 194198155Srrs continue; 195208165Srrs 196211893Sjchandra ie = xlr_interrupts[i].ie; 197208165Srrs /* Don't account special IRQs */ 198208165Srrs switch (i) { 199208165Srrs case IRQ_IPI: 200208165Srrs case IRQ_MSGRING: 201208165Srrs break; 202208165Srrs default: 203208165Srrs mips_intrcnt_inc(mips_intr_counters[i]); 204198155Srrs } 205211893Sjchandra 206211893Sjchandra /* Ack the IRQ on the CPU */ 207198155Srrs write_c0_eirr64(1ULL << i); 208198155Srrs if (intr_event_handle(ie, tf) != 0) { 209198625Srrs printf("stray interrupt %d\n", i); 210198155Srrs } 211198155Srrs } 212198155Srrs critical_exit(); 213198155Srrs} 214200901Srrs 215200901Srrsvoid 216200901Srrsmips_intrcnt_setname(mips_intrcnt_t counter, const char *name) 217200901Srrs{ 218200901Srrs int idx = counter - intrcnt; 219200901Srrs 220200901Srrs KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); 221200901Srrs 222200901Srrs snprintf(intrnames + (MAXCOMLEN + 1) * idx, 223200901Srrs MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 224200901Srrs} 225200901Srrs 226200901Srrsmips_intrcnt_t 227200901Srrsmips_intrcnt_create(const char* name) 228200901Srrs{ 229200901Srrs mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; 230200901Srrs 231200901Srrs mips_intrcnt_setname(counter, name); 232200901Srrs return counter; 233200901Srrs} 234200901Srrs 235200901Srrsvoid 236200901Srrscpu_init_interrupts() 237200901Srrs{ 238200901Srrs int i; 239200901Srrs char name[MAXCOMLEN + 1]; 240200901Srrs 241200901Srrs /* 242200901Srrs * Initialize all available vectors so spare IRQ 243200901Srrs * would show up in systat output 244200901Srrs */ 245200901Srrs for (i = 0; i < XLR_MAX_INTR; i++) { 246200901Srrs snprintf(name, MAXCOMLEN + 1, "int%d:", i); 247200901Srrs mips_intr_counters[i] = mips_intrcnt_create(name); 248200901Srrs } 249200901Srrs} 250