root/arch/s390/kvm/pci.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * s390 kvm PCI passthrough support
 *
 * Copyright IBM Corp. 2022
 *
 *    Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
 */

#ifndef __KVM_S390_PCI_H
#define __KVM_S390_PCI_H

#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <asm/airq.h>
#include <asm/cpu.h>

struct kvm_zdev {
        struct zpci_dev *zdev;
        struct kvm *kvm;
        struct zpci_fib fib;
        struct list_head entry;
};

struct zpci_gaite {
        u32 gisa;
        u8 gisc;
        u8 count;
        u8 reserved;
        u8 aisbo;
        u64 aisb;
};

struct zpci_aift {
        struct zpci_gaite *gait;
        struct airq_iv *sbv;
        struct kvm_zdev **kzdev;
        spinlock_t gait_lock; /* Protects the gait, used during AEN forward */
        struct mutex aift_lock; /* Protects the other structures in aift */
};

extern struct zpci_aift *aift;

static inline struct kvm *kvm_s390_pci_si_to_kvm(struct zpci_aift *aift,
                                                 unsigned long si)
{
        if (!IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM) || !aift->kzdev ||
            !aift->kzdev[si])
                return NULL;
        return aift->kzdev[si]->kvm;
};

int kvm_s390_pci_aen_init(u8 nisc);
void kvm_s390_pci_aen_exit(void);

void kvm_s390_pci_init_list(struct kvm *kvm);
void kvm_s390_pci_clear_list(struct kvm *kvm);

int kvm_s390_pci_zpci_op(struct kvm *kvm, struct kvm_s390_zpci_op *args);

int __init kvm_s390_pci_init(void);
void kvm_s390_pci_exit(void);

static inline bool kvm_s390_pci_interp_allowed(void)
{
        struct cpuid cpu_id;

        get_cpu_id(&cpu_id);
        switch (cpu_id.machine) {
        case 0x2817:
        case 0x2818:
        case 0x2827:
        case 0x2828:
        case 0x2964:
        case 0x2965:
                /* No SHM on certain machines */
                return false;
        default:
                return (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM) &&
                        sclp.has_zpci_lsi && sclp.has_aeni && sclp.has_aisi &&
                        sclp.has_aisii);
        }
}

#endif /* __KVM_S390_PCI_H */