[34] | 1 | /* |
---|
| 2 | * This program is free software; you can redistribute it and/or modify |
---|
| 3 | * it under the terms of the GNU General Public License as published by |
---|
| 4 | * the Free Software Foundation; either version 2 of the License, or |
---|
| 5 | * (at your option) any later version. |
---|
| 6 | * |
---|
| 7 | * This program is distributed in the hope that it will be useful, |
---|
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 10 | * GNU General Public License for more details. |
---|
| 11 | * |
---|
| 12 | * You should have received a copy of the GNU General Public License |
---|
| 13 | * along with this program; if not, write to the Free Software |
---|
| 14 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
---|
| 15 | * |
---|
| 16 | * Copyright (C) IBM Corp. 2005, 2006 |
---|
| 17 | * |
---|
| 18 | * Authors: Jimi Xenidis <jimix@watson.ibm.com> |
---|
| 19 | */ |
---|
| 20 | |
---|
| 21 | #include <xen/config.h> |
---|
| 22 | #include <xen/types.h> |
---|
| 23 | #include <xen/sched.h> |
---|
| 24 | #include <xen/lib.h> |
---|
| 25 | #include <xen/event.h> |
---|
| 26 | #include <xen/irq.h> |
---|
| 27 | #include <public/xen.h> |
---|
| 28 | #include <asm/current.h> |
---|
| 29 | #include <asm/hardirq.h> |
---|
| 30 | #include <asm/mpic.h> |
---|
| 31 | #include "mpic_init.h" |
---|
| 32 | #include "exceptions.h" |
---|
| 33 | |
---|
| 34 | #undef DEBUG |
---|
| 35 | #ifdef DEBUG |
---|
| 36 | #define DBG(fmt...) printk(fmt) |
---|
| 37 | #else |
---|
| 38 | #define DBG(fmt...) |
---|
| 39 | #endif |
---|
| 40 | |
---|
| 41 | int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; |
---|
| 42 | |
---|
| 43 | unsigned long io_apic_irqs; |
---|
| 44 | int ioapic_ack_new = 1; |
---|
| 45 | |
---|
| 46 | static struct hw_interrupt_type *hc_irq; |
---|
| 47 | |
---|
| 48 | /* deliver_ee: called with interrupts off when resuming every vcpu */ |
---|
| 49 | void deliver_ee(struct cpu_user_regs *regs) |
---|
| 50 | { |
---|
| 51 | const ulong srr_mask = ~(MSR_IR | MSR_DR | MSR_FE0 | MSR_FE1 | MSR_EE | |
---|
| 52 | MSR_RI | |
---|
| 53 | MSR_BE | MSR_FP | MSR_PMM | MSR_PR | MSR_SE); |
---|
| 54 | |
---|
| 55 | BUG_ON(mfmsr() & MSR_EE); |
---|
| 56 | BUG_ON(regs->msr & MSR_HV); |
---|
| 57 | |
---|
| 58 | if (!local_events_need_delivery()) |
---|
| 59 | return; |
---|
| 60 | |
---|
| 61 | /* XXX OS error: EE was set but RI was not. We could trigger a machine |
---|
| 62 | * check, or kill the domain... for now just crash Xen so we notice. */ |
---|
| 63 | BUG_ON(!(regs->msr & MSR_RI)); |
---|
| 64 | |
---|
| 65 | regs->srr0 = regs->pc; |
---|
| 66 | /* zero SRR1[33:36] and SRR1[42:47] */ |
---|
| 67 | regs->srr1 = regs->msr & ~0x00000000783f0000; |
---|
| 68 | regs->pc = 0x500; |
---|
| 69 | regs->msr &= srr_mask; |
---|
| 70 | regs->msr |= MSR_SF | MSR_ME; |
---|
| 71 | |
---|
| 72 | DBG("<HV: pc=0x%lx, msr=0x%lx\n", regs->pc, regs->msr); |
---|
| 73 | } |
---|
| 74 | |
---|
| 75 | void do_external(struct cpu_user_regs *regs) |
---|
| 76 | { |
---|
| 77 | int vec; |
---|
| 78 | static unsigned spur_count; |
---|
| 79 | |
---|
| 80 | BUG_ON(!(regs->msr & MSR_EE)); |
---|
| 81 | BUG_ON(mfmsr() & MSR_EE); |
---|
| 82 | |
---|
| 83 | vec = xen_mpic_get_irq(regs); |
---|
| 84 | |
---|
| 85 | if (irq_desc[vec].status & IRQ_PER_CPU) { |
---|
| 86 | /* x86 do_IRQ does not respect the per cpu flag. */ |
---|
| 87 | irq_desc_t *desc = &irq_desc[vec]; |
---|
| 88 | regs->entry_vector = vec; |
---|
| 89 | desc->handler->ack(vec); |
---|
| 90 | desc->action->handler(vector_to_irq(vec), desc->action->dev_id, regs); |
---|
| 91 | desc->handler->end(vec); |
---|
| 92 | } else if (vec != -1) { |
---|
| 93 | DBG("EE:0x%lx isrc: %d\n", regs->msr, vec); |
---|
| 94 | regs->entry_vector = vec; |
---|
| 95 | do_IRQ(regs); |
---|
| 96 | |
---|
| 97 | BUG_ON(mfmsr() & MSR_EE); |
---|
| 98 | spur_count = 0; |
---|
| 99 | } else { |
---|
| 100 | ++spur_count; |
---|
| 101 | if (spur_count > 100) |
---|
| 102 | panic("Too many (%d) spurrious interrupts in a row\n" |
---|
| 103 | " Known problem, please halt and let machine idle/cool " |
---|
| 104 | " then reboot\n", |
---|
| 105 | 100); |
---|
| 106 | } |
---|
| 107 | } |
---|
| 108 | |
---|
| 109 | static int xen_local_irq(unsigned int irq) |
---|
| 110 | { |
---|
| 111 | irq_desc_t *desc; |
---|
| 112 | unsigned int vector; |
---|
| 113 | |
---|
| 114 | vector = irq_to_vector(irq); |
---|
| 115 | desc = &irq_desc[vector]; |
---|
| 116 | |
---|
| 117 | return !(desc->status & IRQ_GUEST); |
---|
| 118 | } |
---|
| 119 | |
---|
| 120 | static unsigned int xen_startup_irq(unsigned int irq) |
---|
| 121 | { |
---|
| 122 | DBG("%s(%d)\n", __func__, irq); |
---|
| 123 | if (xen_local_irq(irq)) { |
---|
| 124 | return hc_irq->startup(irq); |
---|
| 125 | } |
---|
| 126 | return 0; |
---|
| 127 | } |
---|
| 128 | |
---|
| 129 | static void xen_shutdown_irq(unsigned int irq) |
---|
| 130 | { |
---|
| 131 | DBG("%s(%d)\n", __func__, irq); |
---|
| 132 | if (xen_local_irq(irq)) { |
---|
| 133 | hc_irq->shutdown(irq); |
---|
| 134 | } |
---|
| 135 | } |
---|
| 136 | |
---|
| 137 | static void xen_enable_irq(unsigned int irq) |
---|
| 138 | { |
---|
| 139 | DBG("%s(%d)\n", __func__, irq); |
---|
| 140 | if (xen_local_irq(irq)) { |
---|
| 141 | hc_irq->enable(irq); |
---|
| 142 | } |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | static void xen_disable_irq(unsigned int irq) |
---|
| 146 | { |
---|
| 147 | DBG("%s(%d)\n", __func__, irq); |
---|
| 148 | if (xen_local_irq(irq)) { |
---|
| 149 | hc_irq->disable(irq); |
---|
| 150 | } |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | static void xen_ack_irq(unsigned int irq) |
---|
| 154 | { |
---|
| 155 | DBG("%s(%d)\n", __func__, irq); |
---|
| 156 | if (xen_local_irq(irq)) { |
---|
| 157 | if (hc_irq->ack) hc_irq->ack(irq); |
---|
| 158 | } |
---|
| 159 | } |
---|
| 160 | |
---|
| 161 | static void xen_end_irq(unsigned int irq) |
---|
| 162 | { |
---|
| 163 | DBG("%s(%d)\n", __func__, irq); |
---|
| 164 | if (xen_local_irq(irq)) { |
---|
| 165 | hc_irq->end(irq); |
---|
| 166 | } |
---|
| 167 | } |
---|
| 168 | |
---|
| 169 | static void xen_set_affinity(unsigned int irq, cpumask_t mask) |
---|
| 170 | { |
---|
| 171 | DBG("%s(%d)\n", __func__, irq); |
---|
| 172 | if (xen_local_irq(irq)) { |
---|
| 173 | if (hc_irq->set_affinity) hc_irq->set_affinity(irq, mask); |
---|
| 174 | } |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | static struct hw_interrupt_type xen_irq = { |
---|
| 178 | .startup = xen_startup_irq, |
---|
| 179 | .enable = xen_enable_irq, |
---|
| 180 | .disable = xen_disable_irq, |
---|
| 181 | .shutdown = xen_shutdown_irq, |
---|
| 182 | .ack = xen_ack_irq, |
---|
| 183 | .end = xen_end_irq, |
---|
| 184 | .set_affinity = xen_set_affinity, |
---|
| 185 | }; |
---|
| 186 | |
---|
| 187 | void init_IRQ(void) |
---|
| 188 | { |
---|
| 189 | hc_irq = xen_mpic_init(&xen_irq); |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | void ack_APIC_irq(void) |
---|
| 193 | { |
---|
| 194 | panic("%s: EOI the whole MPIC?\n", __func__); |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | void ack_bad_irq(unsigned int irq) |
---|
| 198 | { |
---|
| 199 | printk("unexpected IRQ trap at vector %02x\n", irq); |
---|
| 200 | /* |
---|
| 201 | * Currently unexpected vectors happen only on SMP and APIC. |
---|
| 202 | * We _must_ ack these because every local APIC has only N |
---|
| 203 | * irq slots per priority level, and a 'hanging, unacked' IRQ |
---|
| 204 | * holds up an irq slot - in excessive cases (when multiple |
---|
| 205 | * unexpected vectors occur) that might lock up the APIC |
---|
| 206 | * completely. |
---|
| 207 | */ |
---|
| 208 | ack_APIC_irq(); |
---|
| 209 | } |
---|
| 210 | |
---|
| 211 | extern void dump_ioapic_irq_info(void); |
---|
| 212 | void dump_ioapic_irq_info(void) |
---|
| 213 | { |
---|
| 214 | printk("%s: can't dump yet\n", __func__); |
---|
| 215 | } |
---|
| 216 | |
---|
| 217 | /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ |
---|
| 218 | u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; |
---|
| 219 | int assign_irq_vector(int irq) |
---|
| 220 | { |
---|
| 221 | static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; |
---|
| 222 | |
---|
| 223 | BUG_ON(irq >= NR_IRQ_VECTORS); |
---|
| 224 | if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) |
---|
| 225 | return IO_APIC_VECTOR(irq); |
---|
| 226 | next: |
---|
| 227 | current_vector += 8; |
---|
| 228 | |
---|
| 229 | /* Skip the hypercall vector. */ |
---|
| 230 | if (current_vector == HYPERCALL_VECTOR) |
---|
| 231 | goto next; |
---|
| 232 | |
---|
| 233 | /* Skip the Linux/BSD fast-trap vector. */ |
---|
| 234 | if (current_vector == FAST_TRAP) |
---|
| 235 | goto next; |
---|
| 236 | |
---|
| 237 | if (current_vector >= FIRST_SYSTEM_VECTOR) { |
---|
| 238 | offset++; |
---|
| 239 | if (!(offset%8)) |
---|
| 240 | return -ENOSPC; |
---|
| 241 | current_vector = FIRST_DEVICE_VECTOR + offset; |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | vector_irq[current_vector] = irq; |
---|
| 245 | if (irq != AUTO_ASSIGN) |
---|
| 246 | IO_APIC_VECTOR(irq) = current_vector; |
---|
| 247 | |
---|
| 248 | return current_vector; |
---|
| 249 | } |
---|
| 250 | |
---|
| 251 | int ioapic_guest_read(unsigned long physbase, unsigned int reg, u32 *pval) |
---|
| 252 | { |
---|
| 253 | BUG_ON(pval != pval); |
---|
| 254 | |
---|
| 255 | return 0; |
---|
| 256 | } |
---|
| 257 | |
---|
| 258 | int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val) |
---|
| 259 | { |
---|
| 260 | BUG_ON(val != val); |
---|
| 261 | return 0; |
---|
| 262 | } |
---|
| 263 | |
---|
| 264 | void send_IPI_mask(cpumask_t mask, int vector) |
---|
| 265 | { |
---|
| 266 | unsigned int cpus; |
---|
| 267 | int const bits = 8 * sizeof(cpus); |
---|
| 268 | |
---|
| 269 | switch(vector) { |
---|
| 270 | case CALL_FUNCTION_VECTOR: |
---|
| 271 | case EVENT_CHECK_VECTOR: |
---|
| 272 | break; |
---|
| 273 | default: |
---|
| 274 | BUG(); |
---|
| 275 | return; |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | BUG_ON(NR_CPUS > bits); |
---|
| 279 | BUG_ON(fls(mask.bits[0]) > bits); |
---|
| 280 | |
---|
| 281 | cpus = mask.bits[0]; |
---|
| 282 | mpic_send_ipi(vector, cpus); |
---|
| 283 | } |
---|