Commit d41b5e01 authored by Christian Borntraeger's avatar Christian Borntraeger

Merge tag 'kvm-s390-pci-5.20' into kernelorgnext

KVM: s390/pci: enable zPCI for interpretive execution

Add the necessary code in s390 base, pci and KVM to enable interpretion
of PCI pasthru.
parents 4b88b1a5 4ac34b94
...@@ -5955,6 +5955,52 @@ KVM_PV_DUMP_CPU ...@@ -5955,6 +5955,52 @@ KVM_PV_DUMP_CPU
Provides encrypted dump data like register values. Provides encrypted dump data like register values.
The length of the returned data is provided by uv_info.guest_cpu_stor_len. The length of the returned data is provided by uv_info.guest_cpu_stor_len.
4.137 KVM_S390_ZPCI_OP
--------------------
:Capability: KVM_CAP_S390_ZPCI_OP
:Architectures: s390
:Type: vm ioctl
:Parameters: struct kvm_s390_zpci_op (in)
:Returns: 0 on success, <0 on error
Used to manage hardware-assisted virtualization features for zPCI devices.
Parameters are specified via the following structure::
struct kvm_s390_zpci_op {
/* in */
__u32 fh; /* target device */
__u8 op; /* operation to perform */
__u8 pad[3];
union {
/* for KVM_S390_ZPCIOP_REG_AEN */
struct {
__u64 ibv; /* Guest addr of interrupt bit vector */
__u64 sb; /* Guest addr of summary bit */
__u32 flags;
__u32 noi; /* Number of interrupts */
__u8 isc; /* Guest interrupt subclass */
__u8 sbo; /* Offset of guest summary bit vector */
__u16 pad;
} reg_aen;
__u64 reserved[8];
} u;
};
The type of operation is specified in the "op" field.
KVM_S390_ZPCIOP_REG_AEN is used to register the VM for adapter event
notification interpretation, which will allow firmware delivery of adapter
events directly to the vm, with KVM providing a backup delivery mechanism;
KVM_S390_ZPCIOP_DEREG_AEN is used to subsequently disable interpretation of
adapter event notifications.
The target zPCI function must also be specified via the "fh" field. For the
KVM_S390_ZPCIOP_REG_AEN operation, additional information to establish firmware
delivery must be provided via the "reg_aen" struct.
The "pad" and "reserved" fields may be used for future extensions and should be
set to 0s by userspace.
5. The kvm_run structure 5. The kvm_run structure
======================== ========================
......
...@@ -17453,6 +17453,7 @@ M: Eric Farman <farman@linux.ibm.com> ...@@ -17453,6 +17453,7 @@ M: Eric Farman <farman@linux.ibm.com>
L: linux-s390@vger.kernel.org L: linux-s390@vger.kernel.org
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
S: Supported S: Supported
F: arch/s390/kvm/pci*
F: drivers/vfio/pci/vfio_pci_zdev.c F: drivers/vfio/pci/vfio_pci_zdev.c
F: include/uapi/linux/vfio_zdev.h F: include/uapi/linux/vfio_zdev.h
......
...@@ -12,10 +12,11 @@ ...@@ -12,10 +12,11 @@
#include <linux/bit_spinlock.h> #include <linux/bit_spinlock.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <asm/tpi.h>
struct airq_struct { struct airq_struct {
struct hlist_node list; /* Handler queueing. */ struct hlist_node list; /* Handler queueing. */
void (*handler)(struct airq_struct *airq, bool floating); void (*handler)(struct airq_struct *airq, struct tpi_info *tpi_info);
u8 *lsi_ptr; /* Local-Summary-Indicator pointer */ u8 *lsi_ptr; /* Local-Summary-Indicator pointer */
u8 lsi_mask; /* Local-Summary-Indicator mask */ u8 lsi_mask; /* Local-Summary-Indicator mask */
u8 isc; /* Interrupt-subclass */ u8 isc; /* Interrupt-subclass */
...@@ -46,8 +47,10 @@ struct airq_iv { ...@@ -46,8 +47,10 @@ struct airq_iv {
#define AIRQ_IV_PTR 4 /* Allocate the ptr array */ #define AIRQ_IV_PTR 4 /* Allocate the ptr array */
#define AIRQ_IV_DATA 8 /* Allocate the data array */ #define AIRQ_IV_DATA 8 /* Allocate the data array */
#define AIRQ_IV_CACHELINE 16 /* Cacheline alignment for the vector */ #define AIRQ_IV_CACHELINE 16 /* Cacheline alignment for the vector */
#define AIRQ_IV_GUESTVEC 32 /* Vector is a pinned guest page */
struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags); struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags,
unsigned long *vec);
void airq_iv_release(struct airq_iv *iv); void airq_iv_release(struct airq_iv *iv);
unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num); unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num);
void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num); void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/kvm.h> #include <linux/kvm.h>
#include <linux/seqlock.h> #include <linux/seqlock.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/fpu/api.h> #include <asm/fpu/api.h>
...@@ -254,7 +255,10 @@ struct kvm_s390_sie_block { ...@@ -254,7 +255,10 @@ struct kvm_s390_sie_block {
#define ECB2_IEP 0x20 #define ECB2_IEP 0x20
#define ECB2_PFMFI 0x08 #define ECB2_PFMFI 0x08
#define ECB2_ESCA 0x04 #define ECB2_ESCA 0x04
#define ECB2_ZPCI_LSI 0x02
__u8 ecb2; /* 0x0062 */ __u8 ecb2; /* 0x0062 */
#define ECB3_AISI 0x20
#define ECB3_AISII 0x10
#define ECB3_DEA 0x08 #define ECB3_DEA 0x08
#define ECB3_AES 0x04 #define ECB3_AES 0x04
#define ECB3_RI 0x01 #define ECB3_RI 0x01
...@@ -759,6 +763,7 @@ struct kvm_vm_stat { ...@@ -759,6 +763,7 @@ struct kvm_vm_stat {
u64 inject_pfault_done; u64 inject_pfault_done;
u64 inject_service_signal; u64 inject_service_signal;
u64 inject_virtio; u64 inject_virtio;
u64 aen_forward;
}; };
struct kvm_arch_memory_slot { struct kvm_arch_memory_slot {
...@@ -940,6 +945,7 @@ struct kvm_arch{ ...@@ -940,6 +945,7 @@ struct kvm_arch{
int use_cmma; int use_cmma;
int use_pfmfi; int use_pfmfi;
int use_skf; int use_skf;
int use_zpci_interp;
int user_cpu_state_ctrl; int user_cpu_state_ctrl;
int user_sigp; int user_sigp;
int user_stsi; int user_stsi;
...@@ -963,6 +969,8 @@ struct kvm_arch{ ...@@ -963,6 +969,8 @@ struct kvm_arch{
DECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS); DECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS);
struct kvm_s390_gisa_interrupt gisa_int; struct kvm_s390_gisa_interrupt gisa_int;
struct kvm_s390_pv pv; struct kvm_s390_pv pv;
struct list_head kzdev_list;
spinlock_t kzdev_list_lock;
}; };
#define KVM_HVA_ERR_BAD (-1UL) #define KVM_HVA_ERR_BAD (-1UL)
...@@ -1013,4 +1021,19 @@ static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm, ...@@ -1013,4 +1021,19 @@ static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
#define __KVM_HAVE_ARCH_VM_FREE
void kvm_arch_free_vm(struct kvm *kvm);
#ifdef CONFIG_VFIO_PCI_ZDEV_KVM
int kvm_s390_pci_register_kvm(struct zpci_dev *zdev, struct kvm *kvm);
void kvm_s390_pci_unregister_kvm(struct zpci_dev *zdev);
#else
static inline int kvm_s390_pci_register_kvm(struct zpci_dev *dev,
struct kvm *kvm)
{
return -EPERM;
}
static inline void kvm_s390_pci_unregister_kvm(struct zpci_dev *dev) {}
#endif
#endif #endif
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <asm-generic/pci.h> #include <asm-generic/pci.h>
#include <asm/pci_clp.h> #include <asm/pci_clp.h>
#include <asm/pci_debug.h> #include <asm/pci_debug.h>
#include <asm/pci_insn.h>
#include <asm/sclp.h> #include <asm/sclp.h>
#define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_IO 0x1000
...@@ -97,6 +98,7 @@ struct zpci_bar_struct { ...@@ -97,6 +98,7 @@ struct zpci_bar_struct {
}; };
struct s390_domain; struct s390_domain;
struct kvm_zdev;
#define ZPCI_FUNCTIONS_PER_BUS 256 #define ZPCI_FUNCTIONS_PER_BUS 256
struct zpci_bus { struct zpci_bus {
...@@ -123,11 +125,14 @@ struct zpci_dev { ...@@ -123,11 +125,14 @@ struct zpci_dev {
enum zpci_state state; enum zpci_state state;
u32 fid; /* function ID, used by sclp */ u32 fid; /* function ID, used by sclp */
u32 fh; /* function handle, used by insn's */ u32 fh; /* function handle, used by insn's */
u32 gisa; /* GISA designation for passthrough */
u16 vfn; /* virtual function number */ u16 vfn; /* virtual function number */
u16 pchid; /* physical channel ID */ u16 pchid; /* physical channel ID */
u16 maxstbl; /* Maximum store block size */
u8 pfgid; /* function group ID */ u8 pfgid; /* function group ID */
u8 pft; /* pci function type */ u8 pft; /* pci function type */
u8 port; u8 port;
u8 dtsm; /* Supported DT mask */
u8 rid_available : 1; u8 rid_available : 1;
u8 has_hp_slot : 1; u8 has_hp_slot : 1;
u8 has_resources : 1; u8 has_resources : 1;
...@@ -186,7 +191,10 @@ struct zpci_dev { ...@@ -186,7 +191,10 @@ struct zpci_dev {
struct dentry *debugfs_dev; struct dentry *debugfs_dev;
/* IOMMU and passthrough */
struct s390_domain *s390_domain; /* s390 IOMMU domain data */ struct s390_domain *s390_domain; /* s390 IOMMU domain data */
struct kvm_zdev *kzdev;
struct mutex kzdev_lock;
}; };
static inline bool zdev_enabled(struct zpci_dev *zdev) static inline bool zdev_enabled(struct zpci_dev *zdev)
...@@ -198,6 +206,9 @@ extern const struct attribute_group *zpci_attr_groups[]; ...@@ -198,6 +206,9 @@ extern const struct attribute_group *zpci_attr_groups[];
extern unsigned int s390_pci_force_floating __initdata; extern unsigned int s390_pci_force_floating __initdata;
extern unsigned int s390_pci_no_rid; extern unsigned int s390_pci_no_rid;
extern union zpci_sic_iib *zpci_aipb;
extern struct airq_iv *zpci_aif_sbv;
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Prototypes Prototypes
----------------------------------------------------------------------------- */ ----------------------------------------------------------------------------- */
......
...@@ -153,9 +153,11 @@ struct clp_rsp_query_pci_grp { ...@@ -153,9 +153,11 @@ struct clp_rsp_query_pci_grp {
u8 : 6; u8 : 6;
u8 frame : 1; u8 frame : 1;
u8 refresh : 1; /* TLB refresh mode */ u8 refresh : 1; /* TLB refresh mode */
u16 reserved2; u16 : 3;
u16 maxstbl : 13; /* Maximum store block size */
u16 mui; u16 mui;
u16 : 16; u8 dtsm; /* Supported DT mask */
u8 reserved3;
u16 maxfaal; u16 maxfaal;
u16 : 4; u16 : 4;
u16 dnoi : 12; u16 dnoi : 12;
...@@ -173,7 +175,8 @@ struct clp_req_set_pci { ...@@ -173,7 +175,8 @@ struct clp_req_set_pci {
u16 reserved2; u16 reserved2;
u8 oc; /* operation controls */ u8 oc; /* operation controls */
u8 ndas; /* number of dma spaces */ u8 ndas; /* number of dma spaces */
u64 reserved3; u32 reserved3;
u32 gisa; /* GISA designation */
} __packed; } __packed;
/* Set PCI function response */ /* Set PCI function response */
......
...@@ -98,6 +98,15 @@ struct zpci_fib { ...@@ -98,6 +98,15 @@ struct zpci_fib {
u32 gd; u32 gd;
} __packed __aligned(8); } __packed __aligned(8);
/* Set Interruption Controls Operation Controls */
#define SIC_IRQ_MODE_ALL 0
#define SIC_IRQ_MODE_SINGLE 1
#define SIC_SET_AENI_CONTROLS 2
#define SIC_IRQ_MODE_DIRECT 4
#define SIC_IRQ_MODE_D_ALL 16
#define SIC_IRQ_MODE_D_SINGLE 17
#define SIC_IRQ_MODE_SET_CPU 18
/* directed interruption information block */ /* directed interruption information block */
struct zpci_diib { struct zpci_diib {
u32 : 1; u32 : 1;
...@@ -119,9 +128,20 @@ struct zpci_cdiib { ...@@ -119,9 +128,20 @@ struct zpci_cdiib {
u64 : 64; u64 : 64;
} __packed __aligned(8); } __packed __aligned(8);
/* adapter interruption parameters block */
struct zpci_aipb {
u64 faisb;
u64 gait;
u16 : 13;
u16 afi : 3;
u32 : 32;
u16 faal;
} __packed __aligned(8);
union zpci_sic_iib { union zpci_sic_iib {
struct zpci_diib diib; struct zpci_diib diib;
struct zpci_cdiib cdiib; struct zpci_cdiib cdiib;
struct zpci_aipb aipb;
}; };
DECLARE_STATIC_KEY_FALSE(have_mio); DECLARE_STATIC_KEY_FALSE(have_mio);
...@@ -134,13 +154,6 @@ int __zpci_store(u64 data, u64 req, u64 offset); ...@@ -134,13 +154,6 @@ int __zpci_store(u64 data, u64 req, u64 offset);
int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len); int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len);
int __zpci_store_block(const u64 *data, u64 req, u64 offset); int __zpci_store_block(const u64 *data, u64 req, u64 offset);
void zpci_barrier(void); void zpci_barrier(void);
int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib); int zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib);
static inline int zpci_set_irq_ctrl(u16 ctl, u8 isc)
{
union zpci_sic_iib iib = {{0}};
return __zpci_set_irq_ctrl(ctl, isc, &iib);
}
#endif #endif
...@@ -88,6 +88,10 @@ struct sclp_info { ...@@ -88,6 +88,10 @@ struct sclp_info {
unsigned char has_sipl : 1; unsigned char has_sipl : 1;
unsigned char has_dirq : 1; unsigned char has_dirq : 1;
unsigned char has_iplcc : 1; unsigned char has_iplcc : 1;
unsigned char has_zpci_lsi : 1;
unsigned char has_aisii : 1;
unsigned char has_aeni : 1;
unsigned char has_aisi : 1;
unsigned int ibc; unsigned int ibc;
unsigned int mtid; unsigned int mtid;
unsigned int mtid_cp; unsigned int mtid_cp;
......
...@@ -19,6 +19,19 @@ struct tpi_info { ...@@ -19,6 +19,19 @@ struct tpi_info {
u32 :12; u32 :12;
} __packed __aligned(4); } __packed __aligned(4);
/* I/O-Interruption Code as stored by TPI for an Adapter I/O */
struct tpi_adapter_info {
u32 aism:8;
u32 :22;
u32 error:1;
u32 forward:1;
u32 reserved;
u32 adapter_IO:1;
u32 directed_irq:1;
u32 isc:3;
u32 :27;
} __packed __aligned(4);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_TPI_H */ #endif /* _ASM_S390_TPI_H */
...@@ -10,4 +10,5 @@ ccflags-y := -Ivirt/kvm -Iarch/s390/kvm ...@@ -10,4 +10,5 @@ ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o
kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o
kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o
obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM) += kvm.o
...@@ -28,9 +28,11 @@ ...@@ -28,9 +28,11 @@
#include <asm/switch_to.h> #include <asm/switch_to.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/airq.h> #include <asm/airq.h>
#include <asm/tpi.h>
#include "kvm-s390.h" #include "kvm-s390.h"
#include "gaccess.h" #include "gaccess.h"
#include "trace-s390.h" #include "trace-s390.h"
#include "pci.h"
#define PFAULT_INIT 0x0600 #define PFAULT_INIT 0x0600
#define PFAULT_DONE 0x0680 #define PFAULT_DONE 0x0680
...@@ -3311,10 +3313,87 @@ int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc) ...@@ -3311,10 +3313,87 @@ int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc)
} }
EXPORT_SYMBOL_GPL(kvm_s390_gisc_unregister); EXPORT_SYMBOL_GPL(kvm_s390_gisc_unregister);
static void gib_alert_irq_handler(struct airq_struct *airq, bool floating) static void aen_host_forward(unsigned long si)
{ {
struct kvm_s390_gisa_interrupt *gi;
struct zpci_gaite *gaite;
struct kvm *kvm;
gaite = (struct zpci_gaite *)aift->gait +
(si * sizeof(struct zpci_gaite));
if (gaite->count == 0)
return;
if (gaite->aisb != 0)
set_bit_inv(gaite->aisbo, (unsigned long *)gaite->aisb);
kvm = kvm_s390_pci_si_to_kvm(aift, si);
if (!kvm)
return;
gi = &kvm->arch.gisa_int;
if (!(gi->origin->g1.simm & AIS_MODE_MASK(gaite->gisc)) ||
!(gi->origin->g1.nimm & AIS_MODE_MASK(gaite->gisc))) {
gisa_set_ipm_gisc(gi->origin, gaite->gisc);
if (hrtimer_active(&gi->timer))
hrtimer_cancel(&gi->timer);
hrtimer_start(&gi->timer, 0, HRTIMER_MODE_REL);
kvm->stat.aen_forward++;
}
}
static void aen_process_gait(u8 isc)
{
bool found = false, first = true;
union zpci_sic_iib iib = {{0}};
unsigned long si, flags;
spin_lock_irqsave(&aift->gait_lock, flags);
if (!aift->gait) {
spin_unlock_irqrestore(&aift->gait_lock, flags);
return;
}
for (si = 0;;) {
/* Scan adapter summary indicator bit vector */
si = airq_iv_scan(aift->sbv, si, airq_iv_end(aift->sbv));
if (si == -1UL) {
if (first || found) {
/* Re-enable interrupts. */
zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, isc,
&iib);
first = found = false;
} else {
/* Interrupts on and all bits processed */
break;
}
found = false;
si = 0;
/* Scan again after re-enabling interrupts */
continue;
}
found = true;
aen_host_forward(si);
}
spin_unlock_irqrestore(&aift->gait_lock, flags);
}
static void gib_alert_irq_handler(struct airq_struct *airq,
struct tpi_info *tpi_info)
{
struct tpi_adapter_info *info = (struct tpi_adapter_info *)tpi_info;
inc_irq_stat(IRQIO_GAL); inc_irq_stat(IRQIO_GAL);
if ((info->forward || info->error) &&
IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) {
aen_process_gait(info->isc);
if (info->aism != 0)
process_gib_alert_list();
} else {
process_gib_alert_list(); process_gib_alert_list();
}
} }
static struct airq_struct gib_alert_irq = { static struct airq_struct gib_alert_irq = {
...@@ -3326,6 +3405,11 @@ void kvm_s390_gib_destroy(void) ...@@ -3326,6 +3405,11 @@ void kvm_s390_gib_destroy(void)
{ {
if (!gib) if (!gib)
return; return;
if (kvm_s390_pci_interp_allowed() && aift) {
mutex_lock(&aift->aift_lock);
kvm_s390_pci_aen_exit();
mutex_unlock(&aift->aift_lock);
}
chsc_sgib(0); chsc_sgib(0);
unregister_adapter_interrupt(&gib_alert_irq); unregister_adapter_interrupt(&gib_alert_irq);
free_page((unsigned long)gib); free_page((unsigned long)gib);
...@@ -3363,6 +3447,14 @@ int kvm_s390_gib_init(u8 nisc) ...@@ -3363,6 +3447,14 @@ int kvm_s390_gib_init(u8 nisc)
goto out_unreg_gal; goto out_unreg_gal;
} }
if (kvm_s390_pci_interp_allowed()) {
if (kvm_s390_pci_aen_init(nisc)) {
pr_err("Initializing AEN for PCI failed\n");
rc = -EIO;
goto out_unreg_gal;
}
}
KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc); KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc);
goto out; goto out;
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <asm/fpu/api.h> #include <asm/fpu/api.h>
#include "kvm-s390.h" #include "kvm-s390.h"
#include "gaccess.h" #include "gaccess.h"
#include "pci.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include "trace.h" #include "trace.h"
...@@ -63,7 +64,8 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { ...@@ -63,7 +64,8 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
STATS_DESC_COUNTER(VM, inject_float_mchk), STATS_DESC_COUNTER(VM, inject_float_mchk),
STATS_DESC_COUNTER(VM, inject_pfault_done), STATS_DESC_COUNTER(VM, inject_pfault_done),
STATS_DESC_COUNTER(VM, inject_service_signal), STATS_DESC_COUNTER(VM, inject_service_signal),
STATS_DESC_COUNTER(VM, inject_virtio) STATS_DESC_COUNTER(VM, inject_virtio),
STATS_DESC_COUNTER(VM, aen_forward)
}; };
const struct kvm_stats_header kvm_vm_stats_header = { const struct kvm_stats_header kvm_vm_stats_header = {
...@@ -502,6 +504,14 @@ int kvm_arch_init(void *opaque) ...@@ -502,6 +504,14 @@ int kvm_arch_init(void *opaque)
goto out; goto out;
} }
if (kvm_s390_pci_interp_allowed()) {
rc = kvm_s390_pci_init();
if (rc) {
pr_err("Unable to allocate AIFT for PCI\n");
goto out;
}
}
rc = kvm_s390_gib_init(GAL_ISC); rc = kvm_s390_gib_init(GAL_ISC);
if (rc) if (rc)
goto out; goto out;
...@@ -516,6 +526,8 @@ int kvm_arch_init(void *opaque) ...@@ -516,6 +526,8 @@ int kvm_arch_init(void *opaque)
void kvm_arch_exit(void) void kvm_arch_exit(void)
{ {
kvm_s390_gib_destroy(); kvm_s390_gib_destroy();
if (kvm_s390_pci_interp_allowed())
kvm_s390_pci_exit();
debug_unregister(kvm_s390_dbf); debug_unregister(kvm_s390_dbf);
debug_unregister(kvm_s390_dbf_uv); debug_unregister(kvm_s390_dbf_uv);
} }
...@@ -626,6 +638,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) ...@@ -626,6 +638,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
} }
break; break;
} }
case KVM_CAP_S390_ZPCI_OP:
r = kvm_s390_pci_interp_allowed();
break;
default: default:
r = 0; r = 0;
} }
...@@ -1039,6 +1054,42 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) ...@@ -1039,6 +1054,42 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr)
return 0; return 0;
} }
static void kvm_s390_vcpu_pci_setup(struct kvm_vcpu *vcpu)
{
/* Only set the ECB bits after guest requests zPCI interpretation */
if (!vcpu->kvm->arch.use_zpci_interp)
return;
vcpu->arch.sie_block->ecb2 |= ECB2_ZPCI_LSI;
vcpu->arch.sie_block->ecb3 |= ECB3_AISII + ECB3_AISI;
}
void kvm_s390_vcpu_pci_enable_interp(struct kvm *kvm)
{
struct kvm_vcpu *vcpu;
unsigned long i;
lockdep_assert_held(&kvm->lock);
if (!kvm_s390_pci_interp_allowed())
return;
/*
* If host is configured for PCI and the necessary facilities are
* available, turn on interpretation for the life of this guest
*/
kvm->arch.use_zpci_interp = 1;
kvm_s390_vcpu_block_all(kvm);
kvm_for_each_vcpu(i, vcpu, kvm) {
kvm_s390_vcpu_pci_setup(vcpu);
kvm_s390_sync_request(KVM_REQ_VSIE_RESTART, vcpu);
}
kvm_s390_vcpu_unblock_all(kvm);
}
static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req) static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
{ {
unsigned long cx; unsigned long cx;
...@@ -2772,6 +2823,19 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -2772,6 +2823,19 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = -EFAULT; r = -EFAULT;
break; break;
} }
case KVM_S390_ZPCI_OP: {
struct kvm_s390_zpci_op args;
r = -EINVAL;
if (!IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM))
break;
if (copy_from_user(&args, argp, sizeof(args))) {
r = -EFAULT;
break;
}
r = kvm_s390_pci_zpci_op(kvm, &args);
break;
}
default: default:
r = -ENOTTY; r = -ENOTTY;
} }
...@@ -2933,6 +2997,14 @@ static void sca_dispose(struct kvm *kvm) ...@@ -2933,6 +2997,14 @@ static void sca_dispose(struct kvm *kvm)
kvm->arch.sca = NULL; kvm->arch.sca = NULL;
} }
void kvm_arch_free_vm(struct kvm *kvm)
{
if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM))
kvm_s390_pci_clear_list(kvm);
__kvm_arch_free_vm(kvm);
}
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{ {
gfp_t alloc_flags = GFP_KERNEL_ACCOUNT; gfp_t alloc_flags = GFP_KERNEL_ACCOUNT;
...@@ -3015,6 +3087,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -3015,6 +3087,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm_s390_crypto_init(kvm); kvm_s390_crypto_init(kvm);
if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) {
mutex_lock(&kvm->lock);
kvm_s390_pci_init_list(kvm);
kvm_s390_vcpu_pci_enable_interp(kvm);
mutex_unlock(&kvm->lock);
}
mutex_init(&kvm->arch.float_int.ais_lock); mutex_init(&kvm->arch.float_int.ais_lock);
spin_lock_init(&kvm->arch.float_int.lock); spin_lock_init(&kvm->arch.float_int.lock);
for (i = 0; i < FIRQ_LIST_COUNT; i++) for (i = 0; i < FIRQ_LIST_COUNT; i++)
...@@ -3513,6 +3592,8 @@ static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu) ...@@ -3513,6 +3592,8 @@ static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu)
kvm_s390_vcpu_crypto_setup(vcpu); kvm_s390_vcpu_crypto_setup(vcpu);
kvm_s390_vcpu_pci_setup(vcpu);
mutex_lock(&vcpu->kvm->lock); mutex_lock(&vcpu->kvm->lock);
if (kvm_s390_pv_is_protected(vcpu->kvm)) { if (kvm_s390_pv_is_protected(vcpu->kvm)) {
rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc); rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc);
......
...@@ -512,6 +512,16 @@ void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu, ...@@ -512,6 +512,16 @@ void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
*/ */
void kvm_s390_vcpu_crypto_reset_all(struct kvm *kvm); void kvm_s390_vcpu_crypto_reset_all(struct kvm *kvm);
/**
* kvm_s390_vcpu_pci_enable_interp
*
* Set the associated PCI attributes for each vcpu to allow for zPCI Load/Store
* interpretation as well as adapter interruption forwarding.
*
* @kvm: the KVM guest
*/
void kvm_s390_vcpu_pci_enable_interp(struct kvm *kvm);
/** /**
* diag9c_forwarding_hz * diag9c_forwarding_hz
* *
......
This diff is collapsed.
/* 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_host.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/kvm.h>
#include <linux/kvm_host.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 == 0 ||
aift->kzdev[si] == 0)
return 0;
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 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 */
...@@ -61,6 +61,12 @@ DEFINE_STATIC_KEY_FALSE(have_mio); ...@@ -61,6 +61,12 @@ DEFINE_STATIC_KEY_FALSE(have_mio);
static struct kmem_cache *zdev_fmb_cache; static struct kmem_cache *zdev_fmb_cache;
/* AEN structures that must be preserved over KVM module re-insertion */
union zpci_sic_iib *zpci_aipb;
EXPORT_SYMBOL_GPL(zpci_aipb);
struct airq_iv *zpci_aif_sbv;
EXPORT_SYMBOL_GPL(zpci_aif_sbv);
struct zpci_dev *get_zdev_by_fid(u32 fid) struct zpci_dev *get_zdev_by_fid(u32 fid)
{ {
struct zpci_dev *tmp, *zdev = NULL; struct zpci_dev *tmp, *zdev = NULL;
...@@ -120,11 +126,13 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, ...@@ -120,11 +126,13 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
fib.pba = base; fib.pba = base;
fib.pal = limit; fib.pal = limit;
fib.iota = iota | ZPCI_IOTA_RTTO_FLAG; fib.iota = iota | ZPCI_IOTA_RTTO_FLAG;
fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, &status); cc = zpci_mod_fc(req, &fib, &status);
if (cc) if (cc)
zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status); zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status);
return cc; return cc;
} }
EXPORT_SYMBOL_GPL(zpci_register_ioat);
/* Modify PCI: Unregister I/O address translation parameters */ /* Modify PCI: Unregister I/O address translation parameters */
int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
...@@ -133,6 +141,8 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) ...@@ -133,6 +141,8 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
struct zpci_fib fib = {0}; struct zpci_fib fib = {0};
u8 cc, status; u8 cc, status;
fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, &status); cc = zpci_mod_fc(req, &fib, &status);
if (cc) if (cc)
zpci_dbg(3, "unreg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status); zpci_dbg(3, "unreg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status);
...@@ -160,6 +170,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) ...@@ -160,6 +170,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
atomic64_set(&zdev->unmapped_pages, 0); atomic64_set(&zdev->unmapped_pages, 0);
fib.fmb_addr = virt_to_phys(zdev->fmb); fib.fmb_addr = virt_to_phys(zdev->fmb);
fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, &status); cc = zpci_mod_fc(req, &fib, &status);
if (cc) { if (cc) {
kmem_cache_free(zdev_fmb_cache, zdev->fmb); kmem_cache_free(zdev_fmb_cache, zdev->fmb);
...@@ -178,6 +189,8 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev) ...@@ -178,6 +189,8 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
if (!zdev->fmb) if (!zdev->fmb)
return -EINVAL; return -EINVAL;
fib.gd = zdev->gisa;
/* Function measurement is disabled if fmb address is zero */ /* Function measurement is disabled if fmb address is zero */
cc = zpci_mod_fc(req, &fib, &status); cc = zpci_mod_fc(req, &fib, &status);
if (cc == 3) /* Function already gone. */ if (cc == 3) /* Function already gone. */
...@@ -700,6 +713,7 @@ int zpci_enable_device(struct zpci_dev *zdev) ...@@ -700,6 +713,7 @@ int zpci_enable_device(struct zpci_dev *zdev)
zpci_update_fh(zdev, fh); zpci_update_fh(zdev, fh);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(zpci_enable_device);
int zpci_disable_device(struct zpci_dev *zdev) int zpci_disable_device(struct zpci_dev *zdev)
{ {
...@@ -723,6 +737,7 @@ int zpci_disable_device(struct zpci_dev *zdev) ...@@ -723,6 +737,7 @@ int zpci_disable_device(struct zpci_dev *zdev)
} }
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(zpci_disable_device);
/** /**
* zpci_hot_reset_device - perform a reset of the given zPCI function * zpci_hot_reset_device - perform a reset of the given zPCI function
...@@ -816,6 +831,7 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state) ...@@ -816,6 +831,7 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
kref_init(&zdev->kref); kref_init(&zdev->kref);
mutex_init(&zdev->lock); mutex_init(&zdev->lock);
mutex_init(&zdev->kzdev_lock);
rc = zpci_init_iommu(zdev); rc = zpci_init_iommu(zdev);
if (rc) if (rc)
......
...@@ -106,6 +106,8 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev, ...@@ -106,6 +106,8 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
zdev->max_msi = response->noi; zdev->max_msi = response->noi;
zdev->fmb_update = response->mui; zdev->fmb_update = response->mui;
zdev->version = response->version; zdev->version = response->version;
zdev->maxstbl = response->maxstbl;
zdev->dtsm = response->dtsm;
switch (response->version) { switch (response->version) {
case 1: case 1:
...@@ -229,12 +231,16 @@ static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 comma ...@@ -229,12 +231,16 @@ static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 comma
{ {
struct clp_req_rsp_set_pci *rrb; struct clp_req_rsp_set_pci *rrb;
int rc, retries = 100; int rc, retries = 100;
u32 gisa = 0;
*fh = 0; *fh = 0;
rrb = clp_alloc_block(GFP_KERNEL); rrb = clp_alloc_block(GFP_KERNEL);
if (!rrb) if (!rrb)
return -ENOMEM; return -ENOMEM;
if (command != CLP_SET_DISABLE_PCI_FN)
gisa = zdev->gisa;
do { do {
memset(rrb, 0, sizeof(*rrb)); memset(rrb, 0, sizeof(*rrb));
rrb->request.hdr.len = sizeof(rrb->request); rrb->request.hdr.len = sizeof(rrb->request);
...@@ -243,6 +249,7 @@ static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 comma ...@@ -243,6 +249,7 @@ static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 comma
rrb->request.fh = zdev->fh; rrb->request.fh = zdev->fh;
rrb->request.oc = command; rrb->request.oc = command;
rrb->request.ndas = nr_dma_as; rrb->request.ndas = nr_dma_as;
rrb->request.gisa = gisa;
rc = clp_req(rrb, CLP_LPS_PCI); rc = clp_req(rrb, CLP_LPS_PCI);
if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) { if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) {
......
...@@ -92,6 +92,7 @@ u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status) ...@@ -92,6 +92,7 @@ u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status)
return cc; return cc;
} }
EXPORT_SYMBOL_GPL(zpci_mod_fc);
/* Refresh PCI Translations */ /* Refresh PCI Translations */
static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
...@@ -138,7 +139,7 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range) ...@@ -138,7 +139,7 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
} }
/* Set Interruption Controls */ /* Set Interruption Controls */
int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) int zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib)
{ {
if (!test_facility(72)) if (!test_facility(72))
return -EIO; return -EIO;
...@@ -149,6 +150,7 @@ int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) ...@@ -149,6 +150,7 @@ int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(zpci_set_irq_ctrl);
/* PCI Load */ /* PCI Load */
static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status) static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status)
......
...@@ -11,16 +11,10 @@ ...@@ -11,16 +11,10 @@
#include <asm/isc.h> #include <asm/isc.h>
#include <asm/airq.h> #include <asm/airq.h>
#include <asm/tpi.h>
static enum {FLOATING, DIRECTED} irq_delivery; static enum {FLOATING, DIRECTED} irq_delivery;
#define SIC_IRQ_MODE_ALL 0
#define SIC_IRQ_MODE_SINGLE 1
#define SIC_IRQ_MODE_DIRECT 4
#define SIC_IRQ_MODE_D_ALL 16
#define SIC_IRQ_MODE_D_SINGLE 17
#define SIC_IRQ_MODE_SET_CPU 18
/* /*
* summary bit vector * summary bit vector
* FLOATING - summary bit per function * FLOATING - summary bit per function
...@@ -49,6 +43,7 @@ static int zpci_set_airq(struct zpci_dev *zdev) ...@@ -49,6 +43,7 @@ static int zpci_set_airq(struct zpci_dev *zdev)
fib.fmt0.aibvo = 0; /* each zdev has its own interrupt vector */ fib.fmt0.aibvo = 0; /* each zdev has its own interrupt vector */
fib.fmt0.aisb = virt_to_phys(zpci_sbv->vector) + (zdev->aisb / 64) * 8; fib.fmt0.aisb = virt_to_phys(zpci_sbv->vector) + (zdev->aisb / 64) * 8;
fib.fmt0.aisbo = zdev->aisb & 63; fib.fmt0.aisbo = zdev->aisb & 63;
fib.gd = zdev->gisa;
return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
} }
...@@ -60,6 +55,8 @@ static int zpci_clear_airq(struct zpci_dev *zdev) ...@@ -60,6 +55,8 @@ static int zpci_clear_airq(struct zpci_dev *zdev)
struct zpci_fib fib = {0}; struct zpci_fib fib = {0};
u8 cc, status; u8 cc, status;
fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, &status); cc = zpci_mod_fc(req, &fib, &status);
if (cc == 3 || (cc == 1 && status == 24)) if (cc == 3 || (cc == 1 && status == 24))
/* Function already gone or IRQs already deregistered. */ /* Function already gone or IRQs already deregistered. */
...@@ -78,6 +75,7 @@ static int zpci_set_directed_irq(struct zpci_dev *zdev) ...@@ -78,6 +75,7 @@ static int zpci_set_directed_irq(struct zpci_dev *zdev)
fib.fmt = 1; fib.fmt = 1;
fib.fmt1.noi = zdev->msi_nr_irqs; fib.fmt1.noi = zdev->msi_nr_irqs;
fib.fmt1.dibvo = zdev->msi_first_bit; fib.fmt1.dibvo = zdev->msi_first_bit;
fib.gd = zdev->gisa;
return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
} }
...@@ -90,6 +88,7 @@ static int zpci_clear_directed_irq(struct zpci_dev *zdev) ...@@ -90,6 +88,7 @@ static int zpci_clear_directed_irq(struct zpci_dev *zdev)
u8 cc, status; u8 cc, status;
fib.fmt = 1; fib.fmt = 1;
fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, &status); cc = zpci_mod_fc(req, &fib, &status);
if (cc == 3 || (cc == 1 && status == 24)) if (cc == 3 || (cc == 1 && status == 24))
/* Function already gone or IRQs already deregistered. */ /* Function already gone or IRQs already deregistered. */
...@@ -153,6 +152,7 @@ static struct irq_chip zpci_irq_chip = { ...@@ -153,6 +152,7 @@ static struct irq_chip zpci_irq_chip = {
static void zpci_handle_cpu_local_irq(bool rescan) static void zpci_handle_cpu_local_irq(bool rescan)
{ {
struct airq_iv *dibv = zpci_ibv[smp_processor_id()]; struct airq_iv *dibv = zpci_ibv[smp_processor_id()];
union zpci_sic_iib iib = {{0}};
unsigned long bit; unsigned long bit;
int irqs_on = 0; int irqs_on = 0;
...@@ -164,7 +164,7 @@ static void zpci_handle_cpu_local_irq(bool rescan) ...@@ -164,7 +164,7 @@ static void zpci_handle_cpu_local_irq(bool rescan)
/* End of second scan with interrupts on. */ /* End of second scan with interrupts on. */
break; break;
/* First scan complete, reenable interrupts. */ /* First scan complete, reenable interrupts. */
if (zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC)) if (zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC, &iib))
break; break;
bit = 0; bit = 0;
continue; continue;
...@@ -192,6 +192,7 @@ static void zpci_handle_remote_irq(void *data) ...@@ -192,6 +192,7 @@ static void zpci_handle_remote_irq(void *data)
static void zpci_handle_fallback_irq(void) static void zpci_handle_fallback_irq(void)
{ {
struct cpu_irq_data *cpu_data; struct cpu_irq_data *cpu_data;
union zpci_sic_iib iib = {{0}};
unsigned long cpu; unsigned long cpu;
int irqs_on = 0; int irqs_on = 0;
...@@ -202,7 +203,7 @@ static void zpci_handle_fallback_irq(void) ...@@ -202,7 +203,7 @@ static void zpci_handle_fallback_irq(void)
/* End of second scan with interrupts on. */ /* End of second scan with interrupts on. */
break; break;
/* First scan complete, reenable interrupts. */ /* First scan complete, reenable interrupts. */
if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC)) if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC, &iib))
break; break;
cpu = 0; cpu = 0;
continue; continue;
...@@ -216,8 +217,11 @@ static void zpci_handle_fallback_irq(void) ...@@ -216,8 +217,11 @@ static void zpci_handle_fallback_irq(void)
} }
} }
static void zpci_directed_irq_handler(struct airq_struct *airq, bool floating) static void zpci_directed_irq_handler(struct airq_struct *airq,
struct tpi_info *tpi_info)
{ {
bool floating = !tpi_info->directed_irq;
if (floating) { if (floating) {
inc_irq_stat(IRQIO_PCF); inc_irq_stat(IRQIO_PCF);
zpci_handle_fallback_irq(); zpci_handle_fallback_irq();
...@@ -227,8 +231,10 @@ static void zpci_directed_irq_handler(struct airq_struct *airq, bool floating) ...@@ -227,8 +231,10 @@ static void zpci_directed_irq_handler(struct airq_struct *airq, bool floating)
} }
} }
static void zpci_floating_irq_handler(struct airq_struct *airq, bool floating) static void zpci_floating_irq_handler(struct airq_struct *airq,
struct tpi_info *tpi_info)
{ {
union zpci_sic_iib iib = {{0}};
unsigned long si, ai; unsigned long si, ai;
struct airq_iv *aibv; struct airq_iv *aibv;
int irqs_on = 0; int irqs_on = 0;
...@@ -242,7 +248,7 @@ static void zpci_floating_irq_handler(struct airq_struct *airq, bool floating) ...@@ -242,7 +248,7 @@ static void zpci_floating_irq_handler(struct airq_struct *airq, bool floating)
/* End of second scan with interrupts on. */ /* End of second scan with interrupts on. */
break; break;
/* First scan complete, reenable interrupts. */ /* First scan complete, reenable interrupts. */
if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC)) if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC, &iib))
break; break;
si = 0; si = 0;
continue; continue;
...@@ -291,7 +297,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) ...@@ -291,7 +297,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
zdev->aisb = bit; zdev->aisb = bit;
/* Create adapter interrupt vector */ /* Create adapter interrupt vector */
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK); zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK, NULL);
if (!zdev->aibv) if (!zdev->aibv)
return -ENOMEM; return -ENOMEM;
...@@ -402,11 +408,12 @@ static struct airq_struct zpci_airq = { ...@@ -402,11 +408,12 @@ static struct airq_struct zpci_airq = {
static void __init cpu_enable_directed_irq(void *unused) static void __init cpu_enable_directed_irq(void *unused)
{ {
union zpci_sic_iib iib = {{0}}; union zpci_sic_iib iib = {{0}};
union zpci_sic_iib ziib = {{0}};
iib.cdiib.dibv_addr = (u64) zpci_ibv[smp_processor_id()]->vector; iib.cdiib.dibv_addr = (u64) zpci_ibv[smp_processor_id()]->vector;
__zpci_set_irq_ctrl(SIC_IRQ_MODE_SET_CPU, 0, &iib); zpci_set_irq_ctrl(SIC_IRQ_MODE_SET_CPU, 0, &iib);
zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC); zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC, &ziib);
} }
static int __init zpci_directed_irq_init(void) static int __init zpci_directed_irq_init(void)
...@@ -414,14 +421,14 @@ static int __init zpci_directed_irq_init(void) ...@@ -414,14 +421,14 @@ static int __init zpci_directed_irq_init(void)
union zpci_sic_iib iib = {{0}}; union zpci_sic_iib iib = {{0}};
unsigned int cpu; unsigned int cpu;
zpci_sbv = airq_iv_create(num_possible_cpus(), 0); zpci_sbv = airq_iv_create(num_possible_cpus(), 0, NULL);
if (!zpci_sbv) if (!zpci_sbv)
return -ENOMEM; return -ENOMEM;
iib.diib.isc = PCI_ISC; iib.diib.isc = PCI_ISC;
iib.diib.nr_cpus = num_possible_cpus(); iib.diib.nr_cpus = num_possible_cpus();
iib.diib.disb_addr = virt_to_phys(zpci_sbv->vector); iib.diib.disb_addr = virt_to_phys(zpci_sbv->vector);
__zpci_set_irq_ctrl(SIC_IRQ_MODE_DIRECT, 0, &iib); zpci_set_irq_ctrl(SIC_IRQ_MODE_DIRECT, 0, &iib);
zpci_ibv = kcalloc(num_possible_cpus(), sizeof(*zpci_ibv), zpci_ibv = kcalloc(num_possible_cpus(), sizeof(*zpci_ibv),
GFP_KERNEL); GFP_KERNEL);
...@@ -436,7 +443,7 @@ static int __init zpci_directed_irq_init(void) ...@@ -436,7 +443,7 @@ static int __init zpci_directed_irq_init(void)
zpci_ibv[cpu] = airq_iv_create(cache_line_size() * BITS_PER_BYTE, zpci_ibv[cpu] = airq_iv_create(cache_line_size() * BITS_PER_BYTE,
AIRQ_IV_DATA | AIRQ_IV_DATA |
AIRQ_IV_CACHELINE | AIRQ_IV_CACHELINE |
(!cpu ? AIRQ_IV_ALLOC : 0)); (!cpu ? AIRQ_IV_ALLOC : 0), NULL);
if (!zpci_ibv[cpu]) if (!zpci_ibv[cpu])
return -ENOMEM; return -ENOMEM;
} }
...@@ -453,7 +460,7 @@ static int __init zpci_floating_irq_init(void) ...@@ -453,7 +460,7 @@ static int __init zpci_floating_irq_init(void)
if (!zpci_ibv) if (!zpci_ibv)
return -ENOMEM; return -ENOMEM;
zpci_sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC); zpci_sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, NULL);
if (!zpci_sbv) if (!zpci_sbv)
goto out_free; goto out_free;
...@@ -466,6 +473,7 @@ static int __init zpci_floating_irq_init(void) ...@@ -466,6 +473,7 @@ static int __init zpci_floating_irq_init(void)
int __init zpci_irq_init(void) int __init zpci_irq_init(void)
{ {
union zpci_sic_iib iib = {{0}};
int rc; int rc;
irq_delivery = sclp.has_dirq ? DIRECTED : FLOATING; irq_delivery = sclp.has_dirq ? DIRECTED : FLOATING;
...@@ -497,7 +505,7 @@ int __init zpci_irq_init(void) ...@@ -497,7 +505,7 @@ int __init zpci_irq_init(void)
* Enable floating IRQs (with suppression after one IRQ). When using * Enable floating IRQs (with suppression after one IRQ). When using
* directed IRQs this enables the fallback path. * directed IRQs this enables the fallback path.
*/ */
zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC); zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC, &iib);
return 0; return 0;
out_airq: out_airq:
......
...@@ -45,6 +45,10 @@ static void __init sclp_early_facilities_detect(void) ...@@ -45,6 +45,10 @@ static void __init sclp_early_facilities_detect(void)
sclp.has_gisaf = !!(sccb->fac118 & 0x08); sclp.has_gisaf = !!(sccb->fac118 & 0x08);
sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_hvs = !!(sccb->fac119 & 0x80);
sclp.has_kss = !!(sccb->fac98 & 0x01); sclp.has_kss = !!(sccb->fac98 & 0x01);
sclp.has_aisii = !!(sccb->fac118 & 0x40);
sclp.has_aeni = !!(sccb->fac118 & 0x20);
sclp.has_aisi = !!(sccb->fac118 & 0x10);
sclp.has_zpci_lsi = !!(sccb->fac118 & 0x01);
if (sccb->fac85 & 0x02) if (sccb->fac85 & 0x02)
S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
if (sccb->fac91 & 0x40) if (sccb->fac91 & 0x40)
......
...@@ -99,7 +99,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy) ...@@ -99,7 +99,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(airq, head, list) hlist_for_each_entry_rcu(airq, head, list)
if ((*airq->lsi_ptr & airq->lsi_mask) != 0) if ((*airq->lsi_ptr & airq->lsi_mask) != 0)
airq->handler(airq, !tpi_info->directed_irq); airq->handler(airq, tpi_info);
rcu_read_unlock(); rcu_read_unlock();
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -122,10 +122,12 @@ static inline unsigned long iv_size(unsigned long bits) ...@@ -122,10 +122,12 @@ static inline unsigned long iv_size(unsigned long bits)
* airq_iv_create - create an interrupt vector * airq_iv_create - create an interrupt vector
* @bits: number of bits in the interrupt vector * @bits: number of bits in the interrupt vector
* @flags: allocation flags * @flags: allocation flags
* @vec: pointer to pinned guest memory if AIRQ_IV_GUESTVEC
* *
* Returns a pointer to an interrupt vector structure * Returns a pointer to an interrupt vector structure
*/ */
struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags,
unsigned long *vec)
{ {
struct airq_iv *iv; struct airq_iv *iv;
unsigned long size; unsigned long size;
...@@ -146,6 +148,8 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) ...@@ -146,6 +148,8 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
&iv->vector_dma); &iv->vector_dma);
if (!iv->vector) if (!iv->vector)
goto out_free; goto out_free;
} else if (flags & AIRQ_IV_GUESTVEC) {
iv->vector = vec;
} else { } else {
iv->vector = cio_dma_zalloc(size); iv->vector = cio_dma_zalloc(size);
if (!iv->vector) if (!iv->vector)
...@@ -185,7 +189,7 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) ...@@ -185,7 +189,7 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
kfree(iv->avail); kfree(iv->avail);
if (iv->flags & AIRQ_IV_CACHELINE && iv->vector) if (iv->flags & AIRQ_IV_CACHELINE && iv->vector)
dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma);
else else if (!(iv->flags & AIRQ_IV_GUESTVEC))
cio_dma_free(iv->vector, size); cio_dma_free(iv->vector, size);
kfree(iv); kfree(iv);
out: out:
...@@ -204,7 +208,7 @@ void airq_iv_release(struct airq_iv *iv) ...@@ -204,7 +208,7 @@ void airq_iv_release(struct airq_iv *iv)
kfree(iv->bitlock); kfree(iv->bitlock);
if (iv->flags & AIRQ_IV_CACHELINE) if (iv->flags & AIRQ_IV_CACHELINE)
dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma);
else else if (!(iv->flags & AIRQ_IV_GUESTVEC))
cio_dma_free(iv->vector, iv_size(iv->bits)); cio_dma_free(iv->vector, iv_size(iv->bits));
kfree(iv->avail); kfree(iv->avail);
kfree(iv); kfree(iv);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <asm/qdio.h> #include <asm/qdio.h>
#include <asm/airq.h> #include <asm/airq.h>
#include <asm/isc.h> #include <asm/isc.h>
#include <asm/tpi.h>
#include "cio.h" #include "cio.h"
#include "ioasm.h" #include "ioasm.h"
...@@ -93,9 +94,10 @@ static inline u32 clear_shared_ind(void) ...@@ -93,9 +94,10 @@ static inline u32 clear_shared_ind(void)
/** /**
* tiqdio_thinint_handler - thin interrupt handler for qdio * tiqdio_thinint_handler - thin interrupt handler for qdio
* @airq: pointer to adapter interrupt descriptor * @airq: pointer to adapter interrupt descriptor
* @floating: flag to recognize floating vs. directed interrupts (unused) * @tpi_info: interrupt information (e.g. floating vs directed -- unused)
*/ */
static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating) static void tiqdio_thinint_handler(struct airq_struct *airq,
struct tpi_info *tpi_info)
{ {
u64 irq_time = S390_lowcore.int_clock; u64 irq_time = S390_lowcore.int_clock;
u32 si_used = clear_shared_ind(); u32 si_used = clear_shared_ind();
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/airq.h> #include <asm/airq.h>
#include <asm/tpi.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <asm/isc.h> #include <asm/isc.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
...@@ -131,7 +132,8 @@ static int ap_max_adapter_id = 63; ...@@ -131,7 +132,8 @@ static int ap_max_adapter_id = 63;
static struct bus_type ap_bus_type; static struct bus_type ap_bus_type;
/* Adapter interrupt definitions */ /* Adapter interrupt definitions */
static void ap_interrupt_handler(struct airq_struct *airq, bool floating); static void ap_interrupt_handler(struct airq_struct *airq,
struct tpi_info *tpi_info);
static bool ap_irq_flag; static bool ap_irq_flag;
...@@ -452,9 +454,10 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) ...@@ -452,9 +454,10 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused)
/** /**
* ap_interrupt_handler() - Schedule ap_tasklet on interrupt * ap_interrupt_handler() - Schedule ap_tasklet on interrupt
* @airq: pointer to adapter interrupt descriptor * @airq: pointer to adapter interrupt descriptor
* @floating: ignored * @tpi_info: ignored
*/ */
static void ap_interrupt_handler(struct airq_struct *airq, bool floating) static void ap_interrupt_handler(struct airq_struct *airq,
struct tpi_info *tpi_info)
{ {
inc_irq_stat(IRQIO_APB); inc_irq_stat(IRQIO_APB);
tasklet_schedule(&ap_tasklet); tasklet_schedule(&ap_tasklet);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/virtio-ccw.h> #include <asm/virtio-ccw.h>
#include <asm/isc.h> #include <asm/isc.h>
#include <asm/airq.h> #include <asm/airq.h>
#include <asm/tpi.h>
/* /*
* virtio related functions * virtio related functions
...@@ -204,7 +205,8 @@ static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info) ...@@ -204,7 +205,8 @@ static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info)
write_unlock_irqrestore(&info->lock, flags); write_unlock_irqrestore(&info->lock, flags);
} }
static void virtio_airq_handler(struct airq_struct *airq, bool floating) static void virtio_airq_handler(struct airq_struct *airq,
struct tpi_info *tpi_info)
{ {
struct airq_info *info = container_of(airq, struct airq_info, airq); struct airq_info *info = container_of(airq, struct airq_info, airq);
unsigned long ai; unsigned long ai;
...@@ -240,7 +242,7 @@ static struct airq_info *new_airq_info(int index) ...@@ -240,7 +242,7 @@ static struct airq_info *new_airq_info(int index)
return NULL; return NULL;
rwlock_init(&info->lock); rwlock_init(&info->lock);
info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR
| AIRQ_IV_CACHELINE); | AIRQ_IV_CACHELINE, NULL);
if (!info->aiv) { if (!info->aiv) {
kfree(info); kfree(info);
return NULL; return NULL;
......
...@@ -44,6 +44,17 @@ config VFIO_PCI_IGD ...@@ -44,6 +44,17 @@ config VFIO_PCI_IGD
To enable Intel IGD assignment through vfio-pci, say Y. To enable Intel IGD assignment through vfio-pci, say Y.
endif endif
config VFIO_PCI_ZDEV_KVM
bool "VFIO PCI extensions for s390x KVM passthrough"
depends on S390 && KVM
default y
help
Support s390x-specific extensions to enable support for enhancements
to KVM passthrough capabilities, such as interpretive execution of
zPCI instructions.
To enable s390x KVM vfio-pci extensions, say Y.
source "drivers/vfio/pci/mlx5/Kconfig" source "drivers/vfio/pci/mlx5/Kconfig"
source "drivers/vfio/pci/hisilicon/Kconfig" source "drivers/vfio/pci/hisilicon/Kconfig"
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
vfio-pci-core-$(CONFIG_S390) += vfio_pci_zdev.o vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o
obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
vfio-pci-y := vfio_pci.o vfio-pci-y := vfio_pci.o
......
...@@ -316,10 +316,14 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) ...@@ -316,10 +316,14 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
pci_write_config_word(pdev, PCI_COMMAND, cmd); pci_write_config_word(pdev, PCI_COMMAND, cmd);
} }
ret = vfio_config_init(vdev); ret = vfio_pci_zdev_open_device(vdev);
if (ret) if (ret)
goto out_free_state; goto out_free_state;
ret = vfio_config_init(vdev);
if (ret)
goto out_free_zdev;
msix_pos = pdev->msix_cap; msix_pos = pdev->msix_cap;
if (msix_pos) { if (msix_pos) {
u16 flags; u16 flags;
...@@ -340,6 +344,8 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) ...@@ -340,6 +344,8 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
return 0; return 0;
out_free_zdev:
vfio_pci_zdev_close_device(vdev);
out_free_state: out_free_state:
kfree(vdev->pci_saved_state); kfree(vdev->pci_saved_state);
vdev->pci_saved_state = NULL; vdev->pci_saved_state = NULL;
...@@ -418,6 +424,8 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) ...@@ -418,6 +424,8 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev)
vdev->needs_reset = true; vdev->needs_reset = true;
vfio_pci_zdev_close_device(vdev);
/* /*
* If we have saved state, restore it. If we can reset the device, * If we have saved state, restore it. If we can reset the device,
* even better. Resetting with current state seems better than * even better. Resetting with current state seems better than
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/vfio.h> #include <linux/vfio.h>
#include <linux/vfio_zdev.h> #include <linux/vfio_zdev.h>
#include <linux/kvm_host.h>
#include <asm/pci_clp.h> #include <asm/pci_clp.h>
#include <asm/pci_io.h> #include <asm/pci_io.h>
...@@ -23,14 +24,15 @@ static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) ...@@ -23,14 +24,15 @@ static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
{ {
struct vfio_device_info_cap_zpci_base cap = { struct vfio_device_info_cap_zpci_base cap = {
.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE, .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE,
.header.version = 1, .header.version = 2,
.start_dma = zdev->start_dma, .start_dma = zdev->start_dma,
.end_dma = zdev->end_dma, .end_dma = zdev->end_dma,
.pchid = zdev->pchid, .pchid = zdev->pchid,
.vfn = zdev->vfn, .vfn = zdev->vfn,
.fmb_length = zdev->fmb_length, .fmb_length = zdev->fmb_length,
.pft = zdev->pft, .pft = zdev->pft,
.gid = zdev->pfgid .gid = zdev->pfgid,
.fh = zdev->fh
}; };
return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
...@@ -43,14 +45,16 @@ static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) ...@@ -43,14 +45,16 @@ static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
{ {
struct vfio_device_info_cap_zpci_group cap = { struct vfio_device_info_cap_zpci_group cap = {
.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP, .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP,
.header.version = 1, .header.version = 2,
.dasm = zdev->dma_mask, .dasm = zdev->dma_mask,
.msi_addr = zdev->msi_addr, .msi_addr = zdev->msi_addr,
.flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH, .flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH,
.mui = zdev->fmb_update, .mui = zdev->fmb_update,
.noi = zdev->max_msi, .noi = zdev->max_msi,
.maxstbl = ZPCI_MAX_WRITE_SIZE, .maxstbl = ZPCI_MAX_WRITE_SIZE,
.version = zdev->version .version = zdev->version,
.reserved = 0,
.imaxstbl = zdev->maxstbl
}; };
return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
...@@ -136,3 +140,26 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, ...@@ -136,3 +140,26 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,
return ret; return ret;
} }
int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)
{
struct zpci_dev *zdev = to_zpci(vdev->pdev);
if (!zdev)
return -ENODEV;
if (!vdev->vdev.kvm)
return 0;
return kvm_s390_pci_register_kvm(zdev, vdev->vdev.kvm);
}
void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)
{
struct zpci_dev *zdev = to_zpci(vdev->pdev);
if (!zdev || !vdev->vdev.kvm)
return;
kvm_s390_pci_unregister_kvm(zdev);
}
...@@ -24,7 +24,8 @@ struct user_struct { ...@@ -24,7 +24,8 @@ struct user_struct {
kuid_t uid; kuid_t uid;
#if defined(CONFIG_PERF_EVENTS) || defined(CONFIG_BPF_SYSCALL) || \ #if defined(CONFIG_PERF_EVENTS) || defined(CONFIG_BPF_SYSCALL) || \
defined(CONFIG_NET) || defined(CONFIG_IO_URING) defined(CONFIG_NET) || defined(CONFIG_IO_URING) || \
defined(CONFIG_VFIO_PCI_ZDEV_KVM)
atomic_long_t locked_vm; atomic_long_t locked_vm;
#endif #endif
#ifdef CONFIG_WATCH_QUEUE #ifdef CONFIG_WATCH_QUEUE
......
...@@ -206,15 +206,25 @@ static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev) ...@@ -206,15 +206,25 @@ static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev)
} }
#endif #endif
#ifdef CONFIG_S390 #ifdef CONFIG_VFIO_PCI_ZDEV_KVM
extern int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, extern int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,
struct vfio_info_cap *caps); struct vfio_info_cap *caps);
int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev);
void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev);
#else #else
static inline int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, static inline int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,
struct vfio_info_cap *caps) struct vfio_info_cap *caps)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)
{
return 0;
}
static inline void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)
{}
#endif #endif
/* Will be exported for vfio pci drivers usage */ /* Will be exported for vfio pci drivers usage */
......
...@@ -1167,6 +1167,7 @@ struct kvm_ppc_resize_hpt { ...@@ -1167,6 +1167,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 #define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218
#define KVM_CAP_X86_NOTIFY_VMEXIT 219 #define KVM_CAP_X86_NOTIFY_VMEXIT 219
#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220 #define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
#define KVM_CAP_S390_ZPCI_OP 221
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
...@@ -2186,4 +2187,34 @@ struct kvm_stats_desc { ...@@ -2186,4 +2187,34 @@ struct kvm_stats_desc {
#define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0) #define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0)
#define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1) #define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1)
/* Available with KVM_CAP_S390_ZPCI_OP */
#define KVM_S390_ZPCI_OP _IOW(KVMIO, 0xd1, struct kvm_s390_zpci_op)
struct kvm_s390_zpci_op {
/* in */
__u32 fh; /* target device */
__u8 op; /* operation to perform */
__u8 pad[3];
union {
/* for KVM_S390_ZPCIOP_REG_AEN */
struct {
__u64 ibv; /* Guest addr of interrupt bit vector */
__u64 sb; /* Guest addr of summary bit */
__u32 flags;
__u32 noi; /* Number of interrupts */
__u8 isc; /* Guest interrupt subclass */
__u8 sbo; /* Offset of guest summary bit vector */
__u16 pad;
} reg_aen;
__u64 reserved[8];
} u;
};
/* types for kvm_s390_zpci_op->op */
#define KVM_S390_ZPCIOP_REG_AEN 0
#define KVM_S390_ZPCIOP_DEREG_AEN 1
/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0)
#endif /* __LINUX_KVM_H */ #endif /* __LINUX_KVM_H */
...@@ -29,6 +29,9 @@ struct vfio_device_info_cap_zpci_base { ...@@ -29,6 +29,9 @@ struct vfio_device_info_cap_zpci_base {
__u16 fmb_length; /* Measurement Block Length (in bytes) */ __u16 fmb_length; /* Measurement Block Length (in bytes) */
__u8 pft; /* PCI Function Type */ __u8 pft; /* PCI Function Type */
__u8 gid; /* PCI function group ID */ __u8 gid; /* PCI function group ID */
/* End of version 1 */
__u32 fh; /* PCI function handle */
/* End of version 2 */
}; };
/** /**
...@@ -47,6 +50,10 @@ struct vfio_device_info_cap_zpci_group { ...@@ -47,6 +50,10 @@ struct vfio_device_info_cap_zpci_group {
__u16 noi; /* Maximum number of MSIs */ __u16 noi; /* Maximum number of MSIs */
__u16 maxstbl; /* Maximum Store Block Length */ __u16 maxstbl; /* Maximum Store Block Length */
__u8 version; /* Supported PCI Version */ __u8 version; /* Supported PCI Version */
/* End of version 1 */
__u8 reserved;
__u16 imaxstbl; /* Maximum Interpreted Store Block Length */
/* End of version 2 */
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment