cregit-Linux how code gets into the kernel

Release 4.14 arch/powerpc/kvm/book3s_xive.c

Directory: arch/powerpc/kvm
/*
 * Copyright 2017 Benjamin Herrenschmidt, IBM Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2, as
 * published by the Free Software Foundation.
 */


#define pr_fmt(fmt) "xive-kvm: " fmt

#include <linux/kernel.h>
#include <linux/kvm_host.h>
#include <linux/err.h>
#include <linux/gfp.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/percpu.h>
#include <linux/cpumask.h>
#include <asm/uaccess.h>
#include <asm/kvm_book3s.h>
#include <asm/kvm_ppc.h>
#include <asm/hvcall.h>
#include <asm/xics.h>
#include <asm/xive.h>
#include <asm/xive-regs.h>
#include <asm/debug.h>
#include <asm/debugfs.h>
#include <asm/time.h>
#include <asm/opal.h>

#include <linux/debugfs.h>
#include <linux/seq_file.h>

#include "book3s_xive.h"


/*
 * Virtual mode variants of the hcalls for use on radix/radix
 * with AIL. They require the VCPU's VP to be "pushed"
 *
 * We still instanciate them here because we use some of the
 * generated utility functions as well in this file.
 */

#define XIVE_RUNTIME_CHECKS

#define X_PFX xive_vm_

#define X_STATIC static

#define X_STAT_PFX stat_vm_

#define __x_tima		xive_tima

#define __x_eoi_page(xd)	((void __iomem *)((xd)->eoi_mmio))

#define __x_trig_page(xd)	((void __iomem *)((xd)->trig_mmio))

#define __x_writeb	__raw_writeb

#define __x_readw	__raw_readw

#define __x_readq	__raw_readq

#define __x_writeq	__raw_writeq

#include "book3s_xive_template.c"

/*
 * We leave a gap of a couple of interrupts in the queue to
 * account for the IPI and additional safety guard.
 */

#define XIVE_Q_GAP	2

/*
 * This is a simple trigger for a generic XIVE IRQ. This must
 * only be called for interrupts that support a trigger page
 */

static bool xive_irq_trigger(struct xive_irq_data *xd) { /* This should be only for MSIs */ if (WARN_ON(xd->flags & XIVE_IRQ_FLAG_LSI)) return false; /* Those interrupts should always have a trigger page */ if (WARN_ON(!xd->trig_mmio)) return false; out_be64(xd->trig_mmio, 0); return true; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt52100.00%1100.00%
Total52100.00%1100.00%


static irqreturn_t xive_esc_irq(int irq, void *data) { struct kvm_vcpu *vcpu = data; /* We use the existing H_PROD mechanism to wake up the target */ vcpu->arch.prodded = 1; smp_mb(); if (vcpu->arch.ceded) kvmppc_fast_vcpu_kick(vcpu); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt48100.00%1100.00%
Total48100.00%1100.00%


static int xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio) { struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; struct xive_q *q = &xc->queues[prio]; char *name = NULL; int rc; /* Already there ? */ if (xc->esc_virq[prio]) return 0; /* Hook up the escalation interrupt */ xc->esc_virq[prio] = irq_create_mapping(NULL, q->esc_irq); if (!xc->esc_virq[prio]) { pr_err("Failed to map escalation interrupt for queue %d of VCPU %d\n", prio, xc->server_num); return -EIO; } /* * Future improvement: start with them disabled * and handle DD2 and later scheme of merged escalation * interrupts */ name = kasprintf(GFP_KERNEL, "kvm-%d-%d-%d", vcpu->kvm->arch.lpid, xc->server_num, prio); if (!name) { pr_err("Failed to allocate escalation irq name for queue %d of VCPU %d\n", prio, xc->server_num); rc = -ENOMEM; goto error; } rc = request_irq(xc->esc_virq[prio], xive_esc_irq, IRQF_NO_THREAD, name, vcpu); if (rc) { pr_err("Failed to request escalation interrupt for queue %d of VCPU %d\n", prio, xc->server_num); goto error; } xc->esc_virq_names[prio] = name; return 0; error: irq_dispose_mapping(xc->esc_virq[prio]); xc->esc_virq[prio] = 0; kfree(name); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt235100.00%1100.00%
Total235100.00%1100.00%


static int xive_provision_queue(struct kvm_vcpu *vcpu, u8 prio) { struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; struct kvmppc_xive *xive = xc->xive; struct xive_q *q = &xc->queues[prio]; void *qpage; int rc; if (WARN_ON(q->qpage)) return 0; /* Allocate the queue and retrieve infos on current node for now */ qpage = (__be32 *)__get_free_pages(GFP_KERNEL, xive->q_page_order); if (!qpage) { pr_err("Failed to allocate queue %d for VCPU %d\n", prio, xc->server_num); return -ENOMEM;; } memset(qpage, 0, 1 << xive->q_order); /* * Reconfigure the queue. This will set q->qpage only once the * queue is fully configured. This is a requirement for prio 0 * as we will stop doing EOIs for every IPI as soon as we observe * qpage being non-NULL, and instead will only EOI when we receive * corresponding queue 0 entries */ rc = xive_native_configure_queue(xc->vp_id, q, prio, qpage, xive->q_order, true); if (rc) pr_err("Failed to configure queue %d for VCPU %d\n", prio, xc->server_num); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt158100.00%1100.00%
Total158100.00%1100.00%

/* Called with kvm_lock held */
static int xive_check_provisioning(struct kvm *kvm, u8 prio) { struct kvmppc_xive *xive = kvm->arch.xive; struct kvm_vcpu *vcpu; int i, rc; lockdep_assert_held(&kvm->lock); /* Already provisioned ? */ if (xive->qmap & (1 << prio)) return 0; pr_devel("Provisioning prio... %d\n", prio); /* Provision each VCPU and enable escalations */ kvm_for_each_vcpu(i, vcpu, kvm) { if (!vcpu->arch.xive_vcpu) continue; rc = xive_provision_queue(vcpu, prio); if (rc == 0) xive_attach_escalation(vcpu, prio); if (rc) return rc; } /* Order previous stores and mark it as provisioned */ mb(); xive->qmap |= (1 << prio); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt133100.00%1100.00%
Total133100.00%1100.00%


static void xive_inc_q_pending(struct kvm *kvm, u32 server, u8 prio) { struct kvm_vcpu *vcpu; struct kvmppc_xive_vcpu *xc; struct xive_q *q; /* Locate target server */ vcpu = kvmppc_xive_find_server(kvm, server); if (!vcpu) { pr_warn("%s: Can't find server %d\n", __func__, server); return; } xc = vcpu->arch.xive_vcpu; if (WARN_ON(!xc)) return; q = &xc->queues[prio]; atomic_inc(&q->pending_count); }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt94100.00%1100.00%
Total94100.00%1100.00%


static int xive_try_pick_queue(struct kvm_vcpu *vcpu, u8 prio) { struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; struct xive_q *q; u32 max; if (WARN_ON(!xc)) return -ENXIO; if (!xc->valid) return -ENXIO; q = &xc->queues[prio]; if (WARN_ON(!q->qpage)) return -ENXIO; /* Calculate max number of interrupts in that queue. */ max = (q->msk + 1) - XIVE_Q_GAP; return atomic_add_unless(&q->count, 1, max) ? 0 : -EBUSY; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt111100.00%1100.00%
Total111100.00%1100.00%


static int xive_select_target(struct kvm *kvm, u32 *server, u8 prio) { struct kvm_vcpu *vcpu; int i, rc; /* Locate target server */ vcpu = kvmppc_xive_find_server(kvm, *server); if (!vcpu) { pr_devel("Can't find server %d\n", *server); return -EINVAL; } pr_devel("Finding irq target on 0x%x/%d...\n", *server, prio); /* Try pick it */ rc = xive_try_pick_queue(vcpu, prio); if (rc == 0) return rc; pr_devel(" .. failed, looking up candidate...\n"); /* Failed, pick another VCPU */ kvm_for_each_vcpu(i, vcpu, kvm) { if (!vcpu->arch.xive_vcpu) continue; rc = xive_try_pick_queue(vcpu, prio); if (rc == 0) { *server = vcpu->arch.xive_vcpu->server_num; pr_devel(" found on 0x%x/%d\n", *server, prio); return rc; } } pr_devel(" no available target !\n"); /* No available target ! */ return -EBUSY; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt164100.00%1100.00%
Total164100.00%1100.00%


static u8 xive_lock_and_mask(struct kvmppc_xive *xive, struct kvmppc_xive_src_block *sb, struct kvmppc_xive_irq_state *state) { struct xive_irq_data *xd; u32 hw_num; u8 old_prio; u64 val; /* * Take the lock, set masked, try again if racing * with H_EOI */ for (;;) { arch_spin_lock(&sb->lock); old_prio = state->guest_priority; state->guest_priority = MASKED; mb(); if (!state->in_eoi) break; state->guest_priority = old_prio; arch_spin_unlock(&sb->lock); } /* No change ? Bail */ if (old_prio == MASKED) return old_prio; /* Get the right irq */ kvmppc_xive_select_irq(state, &hw_num, &xd); /* * If the interrupt is marked as needing masking via * firmware, we do it here. Firmware masking however * is "lossy", it won't return the old p and q bits * and won't set the interrupt to a state where it will * record queued ones. If this is an issue we should do * lazy masking instead. * * For now, we work around this in unmask by forcing * an interrupt whenever we unmask a non-LSI via FW * (if ever). */ if (xd->flags & OPAL_XIVE_IRQ_MASK_VIA_FW) { xive_native_configure_irq(hw_num, xive->vp_base + state->act_server, MASKED, state->number); /* set old_p so we can track if an H_EOI was done */ state->old_p = true; state->old_q = false; } else { /* Set PQ to 10, return old P and old Q and remember them */ val = xive_vm_esb_load(xd, XIVE_ESB_SET_PQ_10); state->old_p = !!(val & 2); state->old_q = !!(val & 1); /* * Synchronize hardware to sensure the queues are updated * when masking */ xive_native_sync_source(hw_num); } return old_prio; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt199100.00%1100.00%
Total199100.00%1100.00%


static void xive_lock_for_unmask(struct kvmppc_xive_src_block *sb, struct kvmppc_xive_irq_state *state) { /* * Take the lock try again if racing with H_EOI */ for (;;) { arch_spin_lock(&sb->lock); if (!state->in_eoi) break; arch_spin_unlock(&sb->lock); } }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt48100.00%1100.00%
Total48100.00%1100.00%


static void xive_finish_unmask(struct kvmppc_xive *xive, struct kvmppc_xive_src_block *sb, struct kvmppc_xive_irq_state *state, u8 prio) { struct xive_irq_data *xd; u32 hw_num; /* If we aren't changing a thing, move on */ if (state->guest_priority != MASKED) goto bail; /* Get the right irq */ kvmppc_xive_select_irq(state, &hw_num, &xd); /* * See command in xive_lock_and_mask() concerning masking * via firmware. */ if (xd->flags & OPAL_XIVE_IRQ_MASK_VIA_FW) { xive_native_configure_irq(hw_num, xive->vp_base + state->act_server, state->act_priority, state->number); /* If an EOI is needed, do it here */ if (!state->old_p) xive_vm_source_eoi(hw_num, xd); /* If this is not an LSI, force a trigger */ if (!(xd->flags & OPAL_XIVE_IRQ_LSI)) xive_irq_trigger(xd); goto bail; } /* Old Q set, set PQ to 11 */ if (state->old_q) xive_vm_esb_load(xd, XIVE_ESB_SET_PQ_11); /* * If not old P, then perform an "effective" EOI, * on the source. This will handle the cases where * FW EOI is needed. */ if (!state->old_p) xive_vm_source_eoi(hw_num, xd); /* Synchronize ordering and mark unmasked */ mb(); bail: state->guest_priority = prio; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt164100.00%1100.00%
Total164100.00%1100.00%

/* * Target an interrupt to a given server/prio, this will fallback * to another server if necessary and perform the HW targetting * updates as needed * * NOTE: Must be called with the state lock held */
static int xive_target_interrupt(struct kvm *kvm, struct kvmppc_xive_irq_state *state, u32 server, u8 prio) { struct kvmppc_xive *xive = kvm->arch.xive; u32 hw_num; int rc; /* * This will return a tentative server and actual * priority. The count for that new target will have * already been incremented. */ rc = xive_select_target(kvm, &server, prio); /* * We failed to find a target ? Not much we can do * at least until we support the GIQ. */ if (rc) return rc; /* * Increment the old queue pending count if there * was one so that the old queue count gets adjusted later * when observed to be empty. */ if (state->act_priority != MASKED) xive_inc_q_pending(kvm, state->act_server, state->act_priority); /* * Update state and HW */ state->act_priority = prio; state->act_server = server; /* Get the right irq */ kvmppc_xive_select_irq(state, &hw_num, NULL); return xive_native_configure_irq(hw_num, xive->vp_base + server, prio, state->number); }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt124100.00%1100.00%
Total124100.00%1100.00%

/* * Targetting rules: In order to avoid losing track of * pending interrupts accross mask and unmask, which would * allow queue overflows, we implement the following rules: * * - Unless it was never enabled (or we run out of capacity) * an interrupt is always targetted at a valid server/queue * pair even when "masked" by the guest. This pair tends to * be the last one used but it can be changed under some * circumstances. That allows us to separate targetting * from masking, we only handle accounting during (re)targetting, * this also allows us to let an interrupt drain into its target * queue after masking, avoiding complex schemes to remove * interrupts out of remote processor queues. * * - When masking, we set PQ to 10 and save the previous value * of P and Q. * * - When unmasking, if saved Q was set, we set PQ to 11 * otherwise we leave PQ to the HW state which will be either * 10 if nothing happened or 11 if the interrupt fired while * masked. Effectively we are OR'ing the previous Q into the * HW Q. * * Then if saved P is clear, we do an effective EOI (Q->P->Trigger) * which will unmask the interrupt and shoot a new one if Q was * set. * * Otherwise (saved P is set) we leave PQ unchanged (so 10 or 11, * effectively meaning an H_EOI from the guest is still expected * for that interrupt). * * - If H_EOI occurs while masked, we clear the saved P. * * - When changing target, we account on the new target and * increment a separate "pending" counter on the old one. * This pending counter will be used to decrement the old * target's count when its queue has been observed empty. */
int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) { struct kvmppc_xive *xive = kvm->arch.xive; struct kvmppc_xive_src_block *sb; struct kvmppc_xive_irq_state *state; u8 new_act_prio; int rc = 0; u16 idx; if (!xive) return -ENODEV; pr_devel("set_xive ! irq 0x%x server 0x%x prio %d\n", irq, server, priority); /* First, check provisioning of queues */ if (priority != MASKED) rc = xive_check_provisioning(xive->kvm, xive_prio_from_guest(priority)); if (rc) { pr_devel(" provisioning failure %d !\n", rc); return rc; } sb = kvmppc_xive_find_source(xive, irq, &idx); if (!sb) return -EINVAL; state = &sb->irq_state[idx]; /* * We first handle masking/unmasking since the locking * might need to be retried due to EOIs, we'll handle * targetting changes later. These functions will return * with the SB lock held. * * xive_lock_and_mask() will also set state->guest_priority * but won't otherwise change other fields of the state. * * xive_lock_for_unmask will not actually unmask, this will * be done later by xive_finish_unmask() once the targetting * has been done, so we don't try to unmask an interrupt * that hasn't yet been targetted. */ if (priority == MASKED) xive_lock_and_mask(xive, sb, state); else xive_lock_for_unmask(sb, state); /* * Then we handle targetting. * * First calculate a new "actual priority" */ new_act_prio = state->act_priority; if (priority != MASKED) new_act_prio = xive_prio_from_guest(priority); pr_devel(" new_act_prio=%x act_server=%x act_prio=%x\n", new_act_prio, state->act_server, state->act_priority); /* * Then check if we actually need to change anything, * * The condition for re-targetting the interrupt is that * we have a valid new priority (new_act_prio is not 0xff) * and either the server or the priority changed. * * Note: If act_priority was ff and the new priority is * also ff, we don't do anything and leave the interrupt * untargetted. An attempt of doing an int_on on an * untargetted interrupt will fail. If that is a problem * we could initialize interrupts with valid default */ if (new_act_prio != MASKED && (state->act_server != server || state->act_priority != new_act_prio)) rc = xive_target_interrupt(kvm, state, server, new_act_prio); /* * Perform the final unmasking of the interrupt source * if necessary */ if (priority != MASKED) xive_finish_unmask(xive, sb, state, priority); /* * Finally Update saved_priority to match. Only int_on/off * set this field to a different value. */ state->saved_priority = priority; arch_spin_unlock(&sb->lock); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt268100.00%1100.00%
Total268100.00%1100.00%


int kvmppc_xive_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority) { struct kvmppc_xive *xive = kvm->arch.xive; struct kvmppc_xive_src_block *sb; struct kvmppc_xive_irq_state *state; u16 idx; if (!xive) return -ENODEV; sb = kvmppc_xive_find_source(xive, irq, &idx); if (!sb) return -EINVAL; state = &sb->irq_state[idx]; arch_spin_lock(&sb->lock); *server = state->act_server; *priority = state->guest_priority; arch_spin_unlock(&sb->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt11799.15%150.00%
Sam Bobroff10.85%150.00%
Total118100.00%2100.00%


int kvmppc_xive_int_on(struct kvm *kvm, u32 irq) { struct kvmppc_xive *xive = kvm->arch.xive; struct kvmppc_xive_src_block *sb; struct kvmppc_xive_irq_state *state; u16 idx; if (!xive) return -ENODEV; sb = kvmppc_xive_find_source(xive, irq, &idx); if (!sb) return -EINVAL; state = &sb->irq_state[idx]; pr_devel("int_on(irq=0x%x)\n", irq); /* * Check if interrupt was not targetted */ if (state->act_priority == MASKED) { pr_devel("int_on on untargetted interrupt\n"); return -EINVAL; } /* If saved_priority is 0xff, do nothing */ if (state->saved_priority == MASKED) return 0; /* * Lock and unmask it. */ xive_lock_for_unmask(sb, state); xive_finish_unmask(xive, sb, state, state->saved_priority); arch_spin_unlock(&sb->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt148100.00%1100.00%
Total148100.00%1100.00%


int kvmppc_xive_int_off(struct kvm *kvm, u32 irq) { struct kvmppc_xive *xive = kvm->arch.xive; struct kvmppc_xive_src_block *sb; struct kvmppc_xive_irq_state *state; u16 idx; if (!xive) return -ENODEV; sb = kvmppc_xive_find_source(xive, irq, &idx); if (!sb) return -EINVAL; state = &sb->irq_state[idx]; pr_devel("int_off(irq=0x%x)\n", irq); /* * Lock and mask */ state->saved_priority = xive_lock_and_mask(xive, sb, state); arch_spin_unlock(&sb->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt109100.00%1100.00%
Total109100.00%1100.00%


static bool xive_restore_pending_irq(struct kvmppc_xive *xive, u32 irq) { struct kvmppc_xive_src_block *sb; struct kvmppc_xive_irq_state *state; u16 idx; sb = kvmppc_xive_find_source(xive, irq, &idx); if (!sb) return false; state = &sb->irq_state[idx]; if (!state->valid) return false; /* * Trigger the IPI. This assumes we never restore a pass-through * interrupt which should be safe enough */ xive_irq_trigger(&state->ipi_data); return true; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt79100.00%1100.00%
Total79100.00%1100.00%


u64 kvmppc_xive_get_icp(struct kvm_vcpu *vcpu) { struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; if (!xc) return 0; /* Return the per-cpu state for state saving/migration */ return (u64)xc->cppr << KVM_REG_PPC_ICP_CPPR_SHIFT | (u64)xc->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt49100.00%1100.00%
Total49100.00%1100.00%


int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval) { struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; struct kvmppc_xive *xive = vcpu->kvm->arch.xive; u8 cppr, mfrr; u32 xisr; if (!xc || !xive) return -ENOENT; /* Grab individual state fields. We don't use pending_pri */ cppr = icpval >> KVM_REG_PPC_ICP_CPPR_SHIFT; xisr = (icpval >> KVM_REG_PPC_ICP_XISR_SHIFT) & KVM_REG_PPC_ICP_XISR_MASK; mfrr = icpval >> KVM_REG_PPC_ICP_MFRR_SHIFT; pr_devel("set_icp vcpu %d cppr=0x%x mfrr=0x%x xisr=0x%x\n", xc->server_num, cppr, mfrr, xisr); /* * We can't update the state of a "pushed" VCPU, but that * shouldn't happen. */ if (WARN_ON(vcpu->arch.xive_pushed)) return -EIO; /* Update VCPU HW saved state */ vcpu->arch.xive_saved_state.cppr = cppr; xc->hw_cppr = xc->cppr = cppr; /* * Update MFRR state. If it's not 0xff, we mark the VCPU as * having a pending MFRR change, which will re-evaluate the * target. The VCPU will thus potentially get a spurious * interrupt but that's not a big deal. */ xc->mfrr = mfrr; if (mfrr < cppr) xive_irq_trigger(&xc->vp_ipi_data); /* * Now saved XIRR is "interesting". It means there's something in * the legacy "1 element" queue... for an IPI we simply ignore it, * as the MFRR restore will handle that. For anything else we need * to force a resend of the source. * However the source may not have been setup yet. If that's the * case, we keep that info and increment a counter in the xive to * tell subsequent xive_set_source() to go look. */ if (xisr > XICS_IPI && !xive_restore_pending_irq(xive, xisr)) { xc->delayed_irq = xisr; xive->delayed_irqs++; pr_devel(" xisr restore delayed\n"); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt189100.00%1100.00%
Total189100.00%1100.00%


int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq, struct irq_desc *host_desc) { struct kvmppc_xive *xive = kvm->arch.xive; struct kvmppc_xive_src_block *sb; struct kvmppc_xive_irq_state *state; struct irq_data *host_data = irq_desc_get_irq_data(host_desc); unsigned int host_irq = irq_desc_get_irq(host_desc); unsigned int hw_irq = (unsigned int)irqd_to_hwirq(host_data); u16 idx; u8 prio; int rc; if (!xive) return -ENODEV; pr_devel("set_mapped girq 0x%lx host HW irq 0x%x...\n",guest_irq, hw_irq); sb = kvmppc_xive_find_source(xive, guest_irq, &idx); if (!sb) return -EINVAL; state = &sb->irq_state[idx]; /* * Mark the passed-through interrupt as going to a VCPU, * this will prevent further EOIs and similar operations * from the XIVE code. It will also mask the interrupt * to either PQ=10 or 11 state, the latter if the interrupt * is pending. This will allow us to unmask or retrigger it * after routing it to the guest with a simple EOI. * * The "state" argument is a "token", all it needs is to be * non-NULL to switch to passed-through or NULL for the * other way around. We may not yet have an actual VCPU * target here and we don't really care. */ rc = irq_set_vcpu_affinity(host_irq, state); if (rc) { pr_err("Failed to set VCPU affinity for irq %d\n",