162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kvm_host.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <asm/irq_remapping.h> 762306a36Sopenharmony_ci#include <asm/cpu.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "lapic.h" 1062306a36Sopenharmony_ci#include "irq.h" 1162306a36Sopenharmony_ci#include "posted_intr.h" 1262306a36Sopenharmony_ci#include "trace.h" 1362306a36Sopenharmony_ci#include "vmx.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * Maintain a per-CPU list of vCPUs that need to be awakened by wakeup_handler() 1762306a36Sopenharmony_ci * when a WAKEUP_VECTOR interrupted is posted. vCPUs are added to the list when 1862306a36Sopenharmony_ci * the vCPU is scheduled out and is blocking (e.g. in HLT) with IRQs enabled. 1962306a36Sopenharmony_ci * The vCPUs posted interrupt descriptor is updated at the same time to set its 2062306a36Sopenharmony_ci * notification vector to WAKEUP_VECTOR, so that posted interrupt from devices 2162306a36Sopenharmony_ci * wake the target vCPUs. vCPUs are removed from the list and the notification 2262306a36Sopenharmony_ci * vector is reset when the vCPU is scheduled in. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct list_head, wakeup_vcpus_on_cpu); 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Protect the per-CPU list with a per-CPU spinlock to handle task migration. 2762306a36Sopenharmony_ci * When a blocking vCPU is awakened _and_ migrated to a different pCPU, the 2862306a36Sopenharmony_ci * ->sched_in() path will need to take the vCPU off the list of the _previous_ 2962306a36Sopenharmony_ci * CPU. IRQs must be disabled when taking this lock, otherwise deadlock will 3062306a36Sopenharmony_ci * occur if a wakeup IRQ arrives and attempts to acquire the lock. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic DEFINE_PER_CPU(raw_spinlock_t, wakeup_vcpus_on_cpu_lock); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline struct pi_desc *vcpu_to_pi_desc(struct kvm_vcpu *vcpu) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return &(to_vmx(vcpu)->pi_desc); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int pi_try_set_control(struct pi_desc *pi_desc, u64 *pold, u64 new) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * PID.ON can be set at any time by a different vCPU or by hardware, 4362306a36Sopenharmony_ci * e.g. a device. PID.control must be written atomically, and the 4462306a36Sopenharmony_ci * update must be retried with a fresh snapshot an ON change causes 4562306a36Sopenharmony_ci * the cmpxchg to fail. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci if (!try_cmpxchg64(&pi_desc->control, pold, new)) 4862306a36Sopenharmony_ci return -EBUSY; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_civoid vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); 5662306a36Sopenharmony_ci struct vcpu_vmx *vmx = to_vmx(vcpu); 5762306a36Sopenharmony_ci struct pi_desc old, new; 5862306a36Sopenharmony_ci unsigned long flags; 5962306a36Sopenharmony_ci unsigned int dest; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* 6262306a36Sopenharmony_ci * To simplify hot-plug and dynamic toggling of APICv, keep PI.NDST and 6362306a36Sopenharmony_ci * PI.SN up-to-date even if there is no assigned device or if APICv is 6462306a36Sopenharmony_ci * deactivated due to a dynamic inhibit bit, e.g. for Hyper-V's SyncIC. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci if (!enable_apicv || !lapic_in_kernel(vcpu)) 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* 7062306a36Sopenharmony_ci * If the vCPU wasn't on the wakeup list and wasn't migrated, then the 7162306a36Sopenharmony_ci * full update can be skipped as neither the vector nor the destination 7262306a36Sopenharmony_ci * needs to be changed. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci if (pi_desc->nv != POSTED_INTR_WAKEUP_VECTOR && vcpu->cpu == cpu) { 7562306a36Sopenharmony_ci /* 7662306a36Sopenharmony_ci * Clear SN if it was set due to being preempted. Again, do 7762306a36Sopenharmony_ci * this even if there is no assigned device for simplicity. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci if (pi_test_and_clear_sn(pi_desc)) 8062306a36Sopenharmony_ci goto after_clear_sn; 8162306a36Sopenharmony_ci return; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci local_irq_save(flags); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * If the vCPU was waiting for wakeup, remove the vCPU from the wakeup 8862306a36Sopenharmony_ci * list of the _previous_ pCPU, which will not be the same as the 8962306a36Sopenharmony_ci * current pCPU if the task was migrated. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci if (pi_desc->nv == POSTED_INTR_WAKEUP_VECTOR) { 9262306a36Sopenharmony_ci raw_spin_lock(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu)); 9362306a36Sopenharmony_ci list_del(&vmx->pi_wakeup_list); 9462306a36Sopenharmony_ci raw_spin_unlock(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu)); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci dest = cpu_physical_id(cpu); 9862306a36Sopenharmony_ci if (!x2apic_mode) 9962306a36Sopenharmony_ci dest = (dest << 8) & 0xFF00; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci old.control = READ_ONCE(pi_desc->control); 10262306a36Sopenharmony_ci do { 10362306a36Sopenharmony_ci new.control = old.control; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* 10662306a36Sopenharmony_ci * Clear SN (as above) and refresh the destination APIC ID to 10762306a36Sopenharmony_ci * handle task migration (@cpu != vcpu->cpu). 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci new.ndst = dest; 11062306a36Sopenharmony_ci new.sn = 0; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * Restore the notification vector; in the blocking case, the 11462306a36Sopenharmony_ci * descriptor was modified on "put" to use the wakeup vector. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci new.nv = POSTED_INTR_VECTOR; 11762306a36Sopenharmony_ci } while (pi_try_set_control(pi_desc, &old.control, new.control)); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci local_irq_restore(flags); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciafter_clear_sn: 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* 12462306a36Sopenharmony_ci * Clear SN before reading the bitmap. The VT-d firmware 12562306a36Sopenharmony_ci * writes the bitmap and reads SN atomically (5.2.3 in the 12662306a36Sopenharmony_ci * spec), so it doesn't really have a memory barrier that 12762306a36Sopenharmony_ci * pairs with this, but we cannot do that and we need one. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci smp_mb__after_atomic(); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (!pi_is_pir_empty(pi_desc)) 13262306a36Sopenharmony_ci pi_set_on(pi_desc); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic bool vmx_can_use_vtd_pi(struct kvm *kvm) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return irqchip_in_kernel(kvm) && enable_apicv && 13862306a36Sopenharmony_ci kvm_arch_has_assigned_device(kvm) && 13962306a36Sopenharmony_ci irq_remapping_cap(IRQ_POSTING_CAP); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* 14362306a36Sopenharmony_ci * Put the vCPU on this pCPU's list of vCPUs that needs to be awakened and set 14462306a36Sopenharmony_ci * WAKEUP as the notification vector in the PI descriptor. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic void pi_enable_wakeup_handler(struct kvm_vcpu *vcpu) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); 14962306a36Sopenharmony_ci struct vcpu_vmx *vmx = to_vmx(vcpu); 15062306a36Sopenharmony_ci struct pi_desc old, new; 15162306a36Sopenharmony_ci unsigned long flags; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci local_irq_save(flags); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci raw_spin_lock(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu)); 15662306a36Sopenharmony_ci list_add_tail(&vmx->pi_wakeup_list, 15762306a36Sopenharmony_ci &per_cpu(wakeup_vcpus_on_cpu, vcpu->cpu)); 15862306a36Sopenharmony_ci raw_spin_unlock(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu)); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci WARN(pi_desc->sn, "PI descriptor SN field set before blocking"); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci old.control = READ_ONCE(pi_desc->control); 16362306a36Sopenharmony_ci do { 16462306a36Sopenharmony_ci /* set 'NV' to 'wakeup vector' */ 16562306a36Sopenharmony_ci new.control = old.control; 16662306a36Sopenharmony_ci new.nv = POSTED_INTR_WAKEUP_VECTOR; 16762306a36Sopenharmony_ci } while (pi_try_set_control(pi_desc, &old.control, new.control)); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * Send a wakeup IPI to this CPU if an interrupt may have been posted 17162306a36Sopenharmony_ci * before the notification vector was updated, in which case the IRQ 17262306a36Sopenharmony_ci * will arrive on the non-wakeup vector. An IPI is needed as calling 17362306a36Sopenharmony_ci * try_to_wake_up() from ->sched_out() isn't allowed (IRQs are not 17462306a36Sopenharmony_ci * enabled until it is safe to call try_to_wake_up() on the task being 17562306a36Sopenharmony_ci * scheduled out). 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci if (pi_test_on(&new)) 17862306a36Sopenharmony_ci __apic_send_IPI_self(POSTED_INTR_WAKEUP_VECTOR); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci local_irq_restore(flags); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic bool vmx_needs_pi_wakeup(struct kvm_vcpu *vcpu) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * The default posted interrupt vector does nothing when 18762306a36Sopenharmony_ci * invoked outside guest mode. Return whether a blocked vCPU 18862306a36Sopenharmony_ci * can be the target of posted interrupts, as is the case when 18962306a36Sopenharmony_ci * using either IPI virtualization or VT-d PI, so that the 19062306a36Sopenharmony_ci * notification vector is switched to the one that calls 19162306a36Sopenharmony_ci * back to the pi_wakeup_handler() function. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci return vmx_can_use_ipiv(vcpu) || vmx_can_use_vtd_pi(vcpu->kvm); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_civoid vmx_vcpu_pi_put(struct kvm_vcpu *vcpu) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!vmx_needs_pi_wakeup(vcpu)) 20162306a36Sopenharmony_ci return; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (kvm_vcpu_is_blocking(vcpu) && !vmx_interrupt_blocked(vcpu)) 20462306a36Sopenharmony_ci pi_enable_wakeup_handler(vcpu); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * Set SN when the vCPU is preempted. Note, the vCPU can both be seen 20862306a36Sopenharmony_ci * as blocking and preempted, e.g. if it's preempted between setting 20962306a36Sopenharmony_ci * its wait state and manually scheduling out. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci if (vcpu->preempted) 21262306a36Sopenharmony_ci pi_set_sn(pi_desc); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* 21662306a36Sopenharmony_ci * Handler for POSTED_INTERRUPT_WAKEUP_VECTOR. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_civoid pi_wakeup_handler(void) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci int cpu = smp_processor_id(); 22162306a36Sopenharmony_ci struct list_head *wakeup_list = &per_cpu(wakeup_vcpus_on_cpu, cpu); 22262306a36Sopenharmony_ci raw_spinlock_t *spinlock = &per_cpu(wakeup_vcpus_on_cpu_lock, cpu); 22362306a36Sopenharmony_ci struct vcpu_vmx *vmx; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci raw_spin_lock(spinlock); 22662306a36Sopenharmony_ci list_for_each_entry(vmx, wakeup_list, pi_wakeup_list) { 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (pi_test_on(&vmx->pi_desc)) 22962306a36Sopenharmony_ci kvm_vcpu_wake_up(&vmx->vcpu); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci raw_spin_unlock(spinlock); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_civoid __init pi_init_cpu(int cpu) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci INIT_LIST_HEAD(&per_cpu(wakeup_vcpus_on_cpu, cpu)); 23762306a36Sopenharmony_ci raw_spin_lock_init(&per_cpu(wakeup_vcpus_on_cpu_lock, cpu)); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cibool pi_has_pending_interrupt(struct kvm_vcpu *vcpu) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return pi_test_on(pi_desc) || 24562306a36Sopenharmony_ci (pi_test_sn(pi_desc) && !pi_is_pir_empty(pi_desc)); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/* 25062306a36Sopenharmony_ci * Bail out of the block loop if the VM has an assigned 25162306a36Sopenharmony_ci * device, but the blocking vCPU didn't reconfigure the 25262306a36Sopenharmony_ci * PI.NV to the wakeup vector, i.e. the assigned device 25362306a36Sopenharmony_ci * came along after the initial check in vmx_vcpu_pi_put(). 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_civoid vmx_pi_start_assignment(struct kvm *kvm) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci if (!irq_remapping_cap(IRQ_POSTING_CAP)) 25862306a36Sopenharmony_ci return; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci kvm_make_all_cpus_request(kvm, KVM_REQ_UNBLOCK); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* 26462306a36Sopenharmony_ci * vmx_pi_update_irte - set IRTE for Posted-Interrupts 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * @kvm: kvm 26762306a36Sopenharmony_ci * @host_irq: host irq of the interrupt 26862306a36Sopenharmony_ci * @guest_irq: gsi of the interrupt 26962306a36Sopenharmony_ci * @set: set or unset PI 27062306a36Sopenharmony_ci * returns 0 on success, < 0 on failure 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ciint vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, 27362306a36Sopenharmony_ci uint32_t guest_irq, bool set) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct kvm_kernel_irq_routing_entry *e; 27662306a36Sopenharmony_ci struct kvm_irq_routing_table *irq_rt; 27762306a36Sopenharmony_ci struct kvm_lapic_irq irq; 27862306a36Sopenharmony_ci struct kvm_vcpu *vcpu; 27962306a36Sopenharmony_ci struct vcpu_data vcpu_info; 28062306a36Sopenharmony_ci int idx, ret = 0; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (!vmx_can_use_vtd_pi(kvm)) 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci idx = srcu_read_lock(&kvm->irq_srcu); 28662306a36Sopenharmony_ci irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); 28762306a36Sopenharmony_ci if (guest_irq >= irq_rt->nr_rt_entries || 28862306a36Sopenharmony_ci hlist_empty(&irq_rt->map[guest_irq])) { 28962306a36Sopenharmony_ci pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n", 29062306a36Sopenharmony_ci guest_irq, irq_rt->nr_rt_entries); 29162306a36Sopenharmony_ci goto out; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) { 29562306a36Sopenharmony_ci if (e->type != KVM_IRQ_ROUTING_MSI) 29662306a36Sopenharmony_ci continue; 29762306a36Sopenharmony_ci /* 29862306a36Sopenharmony_ci * VT-d PI cannot support posting multicast/broadcast 29962306a36Sopenharmony_ci * interrupts to a vCPU, we still use interrupt remapping 30062306a36Sopenharmony_ci * for these kind of interrupts. 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * For lowest-priority interrupts, we only support 30362306a36Sopenharmony_ci * those with single CPU as the destination, e.g. user 30462306a36Sopenharmony_ci * configures the interrupts via /proc/irq or uses 30562306a36Sopenharmony_ci * irqbalance to make the interrupts single-CPU. 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * We will support full lowest-priority interrupt later. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * In addition, we can only inject generic interrupts using 31062306a36Sopenharmony_ci * the PI mechanism, refuse to route others through it. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci kvm_set_msi_irq(kvm, e, &irq); 31462306a36Sopenharmony_ci if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) || 31562306a36Sopenharmony_ci !kvm_irq_is_postable(&irq)) { 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * Make sure the IRTE is in remapped mode if 31862306a36Sopenharmony_ci * we don't handle it in posted mode. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci ret = irq_set_vcpu_affinity(host_irq, NULL); 32162306a36Sopenharmony_ci if (ret < 0) { 32262306a36Sopenharmony_ci printk(KERN_INFO 32362306a36Sopenharmony_ci "failed to back to remapped mode, irq: %u\n", 32462306a36Sopenharmony_ci host_irq); 32562306a36Sopenharmony_ci goto out; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci continue; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci vcpu_info.pi_desc_addr = __pa(vcpu_to_pi_desc(vcpu)); 33262306a36Sopenharmony_ci vcpu_info.vector = irq.vector; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci trace_kvm_pi_irte_update(host_irq, vcpu->vcpu_id, e->gsi, 33562306a36Sopenharmony_ci vcpu_info.vector, vcpu_info.pi_desc_addr, set); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (set) 33862306a36Sopenharmony_ci ret = irq_set_vcpu_affinity(host_irq, &vcpu_info); 33962306a36Sopenharmony_ci else 34062306a36Sopenharmony_ci ret = irq_set_vcpu_affinity(host_irq, NULL); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (ret < 0) { 34362306a36Sopenharmony_ci printk(KERN_INFO "%s: failed to update PI IRTE\n", 34462306a36Sopenharmony_ci __func__); 34562306a36Sopenharmony_ci goto out; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci ret = 0; 35062306a36Sopenharmony_ciout: 35162306a36Sopenharmony_ci srcu_read_unlock(&kvm->irq_srcu, idx); 35262306a36Sopenharmony_ci return ret; 35362306a36Sopenharmony_ci} 354