Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.12-rc4 243 lines 5.9 kB view raw
1/* 2* This file is subject to the terms and conditions of the GNU General Public 3* License. See the file "COPYING" in the main directory of this archive 4* for more details. 5* 6* KVM/MIPS: Interrupt delivery 7* 8* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. 9* Authors: Sanjay Lal <sanjayl@kymasys.com> 10*/ 11 12#include <linux/errno.h> 13#include <linux/err.h> 14#include <linux/module.h> 15#include <linux/vmalloc.h> 16#include <linux/fs.h> 17#include <linux/bootmem.h> 18#include <asm/page.h> 19#include <asm/cacheflush.h> 20 21#include <linux/kvm_host.h> 22 23#include "kvm_mips_int.h" 24 25void kvm_mips_queue_irq(struct kvm_vcpu *vcpu, uint32_t priority) 26{ 27 set_bit(priority, &vcpu->arch.pending_exceptions); 28} 29 30void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, uint32_t priority) 31{ 32 clear_bit(priority, &vcpu->arch.pending_exceptions); 33} 34 35void kvm_mips_queue_timer_int_cb(struct kvm_vcpu *vcpu) 36{ 37 /* Cause bits to reflect the pending timer interrupt, 38 * the EXC code will be set when we are actually 39 * delivering the interrupt: 40 */ 41 kvm_set_c0_guest_cause(vcpu->arch.cop0, (C_IRQ5 | C_TI)); 42 43 /* Queue up an INT exception for the core */ 44 kvm_mips_queue_irq(vcpu, MIPS_EXC_INT_TIMER); 45 46} 47 48void kvm_mips_dequeue_timer_int_cb(struct kvm_vcpu *vcpu) 49{ 50 kvm_clear_c0_guest_cause(vcpu->arch.cop0, (C_IRQ5 | C_TI)); 51 kvm_mips_dequeue_irq(vcpu, MIPS_EXC_INT_TIMER); 52} 53 54void 55kvm_mips_queue_io_int_cb(struct kvm_vcpu *vcpu, struct kvm_mips_interrupt *irq) 56{ 57 int intr = (int)irq->irq; 58 59 /* Cause bits to reflect the pending IO interrupt, 60 * the EXC code will be set when we are actually 61 * delivering the interrupt: 62 */ 63 switch (intr) { 64 case 2: 65 kvm_set_c0_guest_cause(vcpu->arch.cop0, (C_IRQ0)); 66 /* Queue up an INT exception for the core */ 67 kvm_mips_queue_irq(vcpu, MIPS_EXC_INT_IO); 68 break; 69 70 case 3: 71 kvm_set_c0_guest_cause(vcpu->arch.cop0, (C_IRQ1)); 72 kvm_mips_queue_irq(vcpu, MIPS_EXC_INT_IPI_1); 73 break; 74 75 case 4: 76 kvm_set_c0_guest_cause(vcpu->arch.cop0, (C_IRQ2)); 77 kvm_mips_queue_irq(vcpu, MIPS_EXC_INT_IPI_2); 78 break; 79 80 default: 81 break; 82 } 83 84} 85 86void 87kvm_mips_dequeue_io_int_cb(struct kvm_vcpu *vcpu, 88 struct kvm_mips_interrupt *irq) 89{ 90 int intr = (int)irq->irq; 91 switch (intr) { 92 case -2: 93 kvm_clear_c0_guest_cause(vcpu->arch.cop0, (C_IRQ0)); 94 kvm_mips_dequeue_irq(vcpu, MIPS_EXC_INT_IO); 95 break; 96 97 case -3: 98 kvm_clear_c0_guest_cause(vcpu->arch.cop0, (C_IRQ1)); 99 kvm_mips_dequeue_irq(vcpu, MIPS_EXC_INT_IPI_1); 100 break; 101 102 case -4: 103 kvm_clear_c0_guest_cause(vcpu->arch.cop0, (C_IRQ2)); 104 kvm_mips_dequeue_irq(vcpu, MIPS_EXC_INT_IPI_2); 105 break; 106 107 default: 108 break; 109 } 110 111} 112 113/* Deliver the interrupt of the corresponding priority, if possible. */ 114int 115kvm_mips_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority, 116 uint32_t cause) 117{ 118 int allowed = 0; 119 uint32_t exccode; 120 121 struct kvm_vcpu_arch *arch = &vcpu->arch; 122 struct mips_coproc *cop0 = vcpu->arch.cop0; 123 124 switch (priority) { 125 case MIPS_EXC_INT_TIMER: 126 if ((kvm_read_c0_guest_status(cop0) & ST0_IE) 127 && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL))) 128 && (kvm_read_c0_guest_status(cop0) & IE_IRQ5)) { 129 allowed = 1; 130 exccode = T_INT; 131 } 132 break; 133 134 case MIPS_EXC_INT_IO: 135 if ((kvm_read_c0_guest_status(cop0) & ST0_IE) 136 && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL))) 137 && (kvm_read_c0_guest_status(cop0) & IE_IRQ0)) { 138 allowed = 1; 139 exccode = T_INT; 140 } 141 break; 142 143 case MIPS_EXC_INT_IPI_1: 144 if ((kvm_read_c0_guest_status(cop0) & ST0_IE) 145 && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL))) 146 && (kvm_read_c0_guest_status(cop0) & IE_IRQ1)) { 147 allowed = 1; 148 exccode = T_INT; 149 } 150 break; 151 152 case MIPS_EXC_INT_IPI_2: 153 if ((kvm_read_c0_guest_status(cop0) & ST0_IE) 154 && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL))) 155 && (kvm_read_c0_guest_status(cop0) & IE_IRQ2)) { 156 allowed = 1; 157 exccode = T_INT; 158 } 159 break; 160 161 default: 162 break; 163 } 164 165 /* Are we allowed to deliver the interrupt ??? */ 166 if (allowed) { 167 168 if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { 169 /* save old pc */ 170 kvm_write_c0_guest_epc(cop0, arch->pc); 171 kvm_set_c0_guest_status(cop0, ST0_EXL); 172 173 if (cause & CAUSEF_BD) 174 kvm_set_c0_guest_cause(cop0, CAUSEF_BD); 175 else 176 kvm_clear_c0_guest_cause(cop0, CAUSEF_BD); 177 178 kvm_debug("Delivering INT @ pc %#lx\n", arch->pc); 179 180 } else 181 kvm_err("Trying to deliver interrupt when EXL is already set\n"); 182 183 kvm_change_c0_guest_cause(cop0, CAUSEF_EXCCODE, 184 (exccode << CAUSEB_EXCCODE)); 185 186 /* XXXSL Set PC to the interrupt exception entry point */ 187 if (kvm_read_c0_guest_cause(cop0) & CAUSEF_IV) 188 arch->pc = KVM_GUEST_KSEG0 + 0x200; 189 else 190 arch->pc = KVM_GUEST_KSEG0 + 0x180; 191 192 clear_bit(priority, &vcpu->arch.pending_exceptions); 193 } 194 195 return allowed; 196} 197 198int 199kvm_mips_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority, 200 uint32_t cause) 201{ 202 return 1; 203} 204 205void kvm_mips_deliver_interrupts(struct kvm_vcpu *vcpu, uint32_t cause) 206{ 207 unsigned long *pending = &vcpu->arch.pending_exceptions; 208 unsigned long *pending_clr = &vcpu->arch.pending_exceptions_clr; 209 unsigned int priority; 210 211 if (!(*pending) && !(*pending_clr)) 212 return; 213 214 priority = __ffs(*pending_clr); 215 while (priority <= MIPS_EXC_MAX) { 216 if (kvm_mips_callbacks->irq_clear(vcpu, priority, cause)) { 217 if (!KVM_MIPS_IRQ_CLEAR_ALL_AT_ONCE) 218 break; 219 } 220 221 priority = find_next_bit(pending_clr, 222 BITS_PER_BYTE * sizeof(*pending_clr), 223 priority + 1); 224 } 225 226 priority = __ffs(*pending); 227 while (priority <= MIPS_EXC_MAX) { 228 if (kvm_mips_callbacks->irq_deliver(vcpu, priority, cause)) { 229 if (!KVM_MIPS_IRQ_DELIVER_ALL_AT_ONCE) 230 break; 231 } 232 233 priority = find_next_bit(pending, 234 BITS_PER_BYTE * sizeof(*pending), 235 priority + 1); 236 } 237 238} 239 240int kvm_mips_pending_timer(struct kvm_vcpu *vcpu) 241{ 242 return test_bit(MIPS_EXC_INT_TIMER, &vcpu->arch.pending_exceptions); 243}