// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017-2019, IBM Corporation.
*/
#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/file.h>
#include <asm/uaccess.h>
#include <asm/kvm_book3s.h>
#include <asm/kvm_ppc.h>
#include <asm/hvcall.h>
#include <asm/xive.h>
#include <asm/xive-regs.h>
#include <asm/debug.h>
#include <asm/debugfs.h>
#include <asm/opal.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include "book3s_xive.h"
static u8 xive_vm_esb_load(struct xive_irq_data *xd, u32 offset)
{
u64 val;
if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG)
offset |= offset << 4;
val = in_be64(xd->eoi_mmio + offset);
return (u8)val;
}
static void kvmppc_xive_native_cleanup_queue(struct kvm_vcpu *vcpu, int prio)
{
struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
struct xive_q *q = &xc->queues[prio];
xive_native_disable_queue(xc->vp_id, q, prio);
if (q->qpage) {
put_page(virt_to_page(q->qpage));
q->qpage = NULL;
}
}
void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu)
{
struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
int i;
if (!kvmppc_xive_enabled(vcpu))
return;
if (!xc)
return;
pr_devel("native_cleanup_vcpu(cpu=%d)\n", xc->server_num);
/* Ensure no interrupt is still routed to that VP */
xc->valid = false;
kvmppc_xive_disable_vcpu_interrupts(vcpu);
/* Free escalations */
for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
/* Free the escalation irq */
if (xc->esc_virq[i]) {
if (xc->xive->single_escalation)
xive_cleanup_single_escalation(vcpu, xc,
xc->esc_virq[i]);
free_irq(xc->esc_virq[i], vcpu);
irq_dispose_mapping(xc->esc_virq[i]);
kfree(xc->esc_virq_names[i]);
xc->esc_virq[i] = 0;
}
}
/* Disable the VP */
xive_native_disable_vp(xc->vp_id);
/* Clear the cam word so guest entry won't try to push context */
vcpu->arch.xive_cam_word = 0;
/* Free the queues */