1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 */ 5 6#include <linux/errno.h> 7#include <linux/err.h> 8#include <linux/vmalloc.h> 9#include <linux/fs.h> 10#include <asm/page.h> 11#include <asm/cacheflush.h> 12#include "kvmcpu.h" 13#include <linux/kvm_host.h> 14#include "kvm_compat.h" 15 16static u32 int_to_coreint[LOONGARCH_EXC_MAX] = { 17 [LARCH_INT_TIMER] = CPU_TIMER, 18 [LARCH_INT_IPI] = CPU_IPI, 19 [LARCH_INT_SIP0] = CPU_SIP0, 20 [LARCH_INT_SIP1] = CPU_SIP1, 21 [LARCH_INT_IP0] = CPU_IP0, 22 [LARCH_INT_IP1] = CPU_IP1, 23 [LARCH_INT_IP2] = CPU_IP2, 24 [LARCH_INT_IP3] = CPU_IP3, 25 [LARCH_INT_IP4] = CPU_IP4, 26 [LARCH_INT_IP5] = CPU_IP5, 27 [LARCH_INT_IP6] = CPU_IP6, 28 [LARCH_INT_IP7] = CPU_IP7, 29}; 30 31static int _kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority) 32{ 33 unsigned int irq = 0; 34 35 clear_bit(priority, &vcpu->arch.irq_pending); 36 if (priority < LOONGARCH_EXC_MAX) 37 irq = int_to_coreint[priority]; 38 39 switch (priority) { 40 case LARCH_INT_TIMER: 41 case LARCH_INT_IPI: 42 case LARCH_INT_SIP0: 43 case LARCH_INT_SIP1: 44 kvm_set_gcsr_estat(irq); 45 break; 46 47 case LARCH_INT_IP0: 48 case LARCH_INT_IP1: 49 case LARCH_INT_IP2: 50 case LARCH_INT_IP3: 51 case LARCH_INT_IP4: 52 case LARCH_INT_IP5: 53 case LARCH_INT_IP6: 54 case LARCH_INT_IP7: 55 kvm_set_csr_gintc(irq); 56 break; 57 58 default: 59 break; 60 } 61 62 return 1; 63} 64 65static int _kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority) 66{ 67 unsigned int irq = 0; 68 69 clear_bit(priority, &vcpu->arch.irq_clear); 70 if (priority < LOONGARCH_EXC_MAX) 71 irq = int_to_coreint[priority]; 72 73 switch (priority) { 74 case LARCH_INT_TIMER: 75 case LARCH_INT_IPI: 76 case LARCH_INT_SIP0: 77 case LARCH_INT_SIP1: 78 kvm_clear_gcsr_estat(irq); 79 break; 80 81 case LARCH_INT_IP0: 82 case LARCH_INT_IP1: 83 case LARCH_INT_IP2: 84 case LARCH_INT_IP3: 85 case LARCH_INT_IP4: 86 case LARCH_INT_IP5: 87 case LARCH_INT_IP6: 88 case LARCH_INT_IP7: 89 kvm_clear_csr_gintc(irq); 90 break; 91 92 default: 93 break; 94 } 95 96 return 1; 97} 98 99void _kvm_deliver_intr(struct kvm_vcpu *vcpu) 100{ 101 unsigned long *pending = &vcpu->arch.irq_pending; 102 unsigned long *pending_clr = &vcpu->arch.irq_clear; 103 unsigned int priority; 104 105 if (!(*pending) && !(*pending_clr)) 106 return; 107 108 if (*pending_clr) { 109 priority = __ffs(*pending_clr); 110 while (priority <= LOONGARCH_EXC_IPNUM) { 111 _kvm_irq_clear(vcpu, priority); 112 priority = find_next_bit(pending_clr, 113 BITS_PER_BYTE * sizeof(*pending_clr), 114 priority + 1); 115 } 116 } 117 118 if (*pending) { 119 priority = __ffs(*pending); 120 while (priority <= LOONGARCH_EXC_IPNUM) { 121 _kvm_irq_deliver(vcpu, priority); 122 priority = find_next_bit(pending, 123 BITS_PER_BYTE * sizeof(*pending), 124 priority + 1); 125 } 126 } 127 128} 129 130int _kvm_pending_timer(struct kvm_vcpu *vcpu) 131{ 132 return test_bit(LARCH_INT_TIMER, &vcpu->arch.irq_pending); 133} 134