~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/loongarch/kvm/interrupt.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
  4  */
  5 
  6 #include <linux/err.h>
  7 #include <linux/errno.h>
  8 #include <asm/kvm_csr.h>
  9 #include <asm/kvm_vcpu.h>
 10 
 11 static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
 12         [INT_TI]        = CPU_TIMER,
 13         [INT_IPI]       = CPU_IPI,
 14         [INT_SWI0]      = CPU_SIP0,
 15         [INT_SWI1]      = CPU_SIP1,
 16         [INT_HWI0]      = CPU_IP0,
 17         [INT_HWI1]      = CPU_IP1,
 18         [INT_HWI2]      = CPU_IP2,
 19         [INT_HWI3]      = CPU_IP3,
 20         [INT_HWI4]      = CPU_IP4,
 21         [INT_HWI5]      = CPU_IP5,
 22         [INT_HWI6]      = CPU_IP6,
 23         [INT_HWI7]      = CPU_IP7,
 24 };
 25 
 26 static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
 27 {
 28         unsigned int irq = 0;
 29 
 30         clear_bit(priority, &vcpu->arch.irq_pending);
 31         if (priority < EXCCODE_INT_NUM)
 32                 irq = priority_to_irq[priority];
 33 
 34         switch (priority) {
 35         case INT_TI:
 36         case INT_IPI:
 37         case INT_SWI0:
 38         case INT_SWI1:
 39                 set_gcsr_estat(irq);
 40                 break;
 41 
 42         case INT_HWI0 ... INT_HWI7:
 43                 set_csr_gintc(irq);
 44                 break;
 45 
 46         default:
 47                 break;
 48         }
 49 
 50         return 1;
 51 }
 52 
 53 static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
 54 {
 55         unsigned int irq = 0;
 56 
 57         clear_bit(priority, &vcpu->arch.irq_clear);
 58         if (priority < EXCCODE_INT_NUM)
 59                 irq = priority_to_irq[priority];
 60 
 61         switch (priority) {
 62         case INT_TI:
 63         case INT_IPI:
 64         case INT_SWI0:
 65         case INT_SWI1:
 66                 clear_gcsr_estat(irq);
 67                 break;
 68 
 69         case INT_HWI0 ... INT_HWI7:
 70                 clear_csr_gintc(irq);
 71                 break;
 72 
 73         default:
 74                 break;
 75         }
 76 
 77         return 1;
 78 }
 79 
 80 void kvm_deliver_intr(struct kvm_vcpu *vcpu)
 81 {
 82         unsigned int priority;
 83         unsigned long *pending = &vcpu->arch.irq_pending;
 84         unsigned long *pending_clr = &vcpu->arch.irq_clear;
 85 
 86         if (!(*pending) && !(*pending_clr))
 87                 return;
 88 
 89         if (*pending_clr) {
 90                 priority = __ffs(*pending_clr);
 91                 while (priority <= INT_IPI) {
 92                         kvm_irq_clear(vcpu, priority);
 93                         priority = find_next_bit(pending_clr,
 94                                         BITS_PER_BYTE * sizeof(*pending_clr),
 95                                         priority + 1);
 96                 }
 97         }
 98 
 99         if (*pending) {
100                 priority = __ffs(*pending);
101                 while (priority <= INT_IPI) {
102                         kvm_irq_deliver(vcpu, priority);
103                         priority = find_next_bit(pending,
104                                         BITS_PER_BYTE * sizeof(*pending),
105                                         priority + 1);
106                 }
107         }
108 }
109 
110 int kvm_pending_timer(struct kvm_vcpu *vcpu)
111 {
112         return test_bit(INT_TI, &vcpu->arch.irq_pending);
113 }
114 
115 /*
116  * Only support illegal instruction or illegal Address Error exception,
117  * Other exceptions are injected by hardware in kvm mode
118  */
119 static void _kvm_deliver_exception(struct kvm_vcpu *vcpu,
120                                 unsigned int code, unsigned int subcode)
121 {
122         unsigned long val, vec_size;
123 
124         /*
125          * BADV is added for EXCCODE_ADE exception
126          *  Use PC register (GVA address) if it is instruction exeception
127          *  Else use BADV from host side (GPA address) for data exeception
128          */
129         if (code == EXCCODE_ADE) {
130                 if (subcode == EXSUBCODE_ADEF)
131                         val = vcpu->arch.pc;
132                 else
133                         val = vcpu->arch.badv;
134                 kvm_write_hw_gcsr(LOONGARCH_CSR_BADV, val);
135         }
136 
137         /* Set exception instruction */
138         kvm_write_hw_gcsr(LOONGARCH_CSR_BADI, vcpu->arch.badi);
139 
140         /*
141          * Save CRMD in PRMD
142          * Set IRQ disabled and PLV0 with CRMD
143          */
144         val = kvm_read_hw_gcsr(LOONGARCH_CSR_CRMD);
145         kvm_write_hw_gcsr(LOONGARCH_CSR_PRMD, val);
146         val = val & ~(CSR_CRMD_PLV | CSR_CRMD_IE);
147         kvm_write_hw_gcsr(LOONGARCH_CSR_CRMD, val);
148 
149         /* Set exception PC address */
150         kvm_write_hw_gcsr(LOONGARCH_CSR_ERA, vcpu->arch.pc);
151 
152         /*
153          * Set exception code
154          * Exception and interrupt can be inject at the same time
155          * Hardware will handle exception first and then extern interrupt
156          * Exception code is Ecode in ESTAT[16:21]
157          * Interrupt code in ESTAT[0:12]
158          */
159         val = kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT);
160         val = (val & ~CSR_ESTAT_EXC) | code;
161         kvm_write_hw_gcsr(LOONGARCH_CSR_ESTAT, val);
162 
163         /* Calculate expcetion entry address */
164         val = kvm_read_hw_gcsr(LOONGARCH_CSR_ECFG);
165         vec_size = (val & CSR_ECFG_VS) >> CSR_ECFG_VS_SHIFT;
166         if (vec_size)
167                 vec_size = (1 << vec_size) * 4;
168         val =  kvm_read_hw_gcsr(LOONGARCH_CSR_EENTRY);
169         vcpu->arch.pc = val + code * vec_size;
170 }
171 
172 void kvm_deliver_exception(struct kvm_vcpu *vcpu)
173 {
174         unsigned int code;
175         unsigned long *pending = &vcpu->arch.exception_pending;
176 
177         if (*pending) {
178                 code = __ffs(*pending);
179                 _kvm_deliver_exception(vcpu, code, vcpu->arch.esubcode);
180                 *pending = 0;
181                 vcpu->arch.esubcode = 0;
182         }
183 }
184 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php