diff mbox series

[14/32] KVM: s390: pci: do initial setup for AEN interpretation

Message ID 20211207205743.150299-15-mjrosato@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series KVM: s390: enable zPCI for interpretive execution | expand

Commit Message

Matthew Rosato Dec. 7, 2021, 8:57 p.m. UTC
Initial setup for Adapter Event Notification Interpretation for zPCI
passthrough devices.  Specifically, allocate a structure for forwarding of
adapter events and pass the address of this structure to firmware.

Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
---
 arch/s390/include/asm/pci_insn.h |  12 ++++
 arch/s390/kvm/interrupt.c        |  17 +++++
 arch/s390/kvm/kvm-s390.c         |   3 +
 arch/s390/kvm/pci.c              | 113 +++++++++++++++++++++++++++++++
 arch/s390/kvm/pci.h              |  42 ++++++++++++
 5 files changed, 187 insertions(+)
 create mode 100644 arch/s390/kvm/pci.h

Comments

Christian Borntraeger Dec. 9, 2021, 7:54 p.m. UTC | #1
Am 07.12.21 um 21:57 schrieb Matthew Rosato:
> Initial setup for Adapter Event Notification Interpretation for zPCI
> passthrough devices.  Specifically, allocate a structure for forwarding of
> adapter events and pass the address of this structure to firmware.
> 
> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
> ---
>   arch/s390/include/asm/pci_insn.h |  12 ++++
>   arch/s390/kvm/interrupt.c        |  17 +++++
>   arch/s390/kvm/kvm-s390.c         |   3 +
>   arch/s390/kvm/pci.c              | 113 +++++++++++++++++++++++++++++++
>   arch/s390/kvm/pci.h              |  42 ++++++++++++
>   5 files changed, 187 insertions(+)
>   create mode 100644 arch/s390/kvm/pci.h
> 
> diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h
> index 5331082fa516..e5f57cfe1d45 100644
> --- a/arch/s390/include/asm/pci_insn.h
> +++ b/arch/s390/include/asm/pci_insn.h
> @@ -101,6 +101,7 @@ struct zpci_fib {
>   /* 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
> @@ -127,9 +128,20 @@ struct zpci_cdiib {
>   	u64 : 64;
>   } __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 {
>   	struct zpci_diib diib;
>   	struct zpci_cdiib cdiib;
> +	struct zpci_aipb aipb;
>   };
>   
>   DECLARE_STATIC_KEY_FALSE(have_mio);
> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
> index f9b872e358c6..4efe0e95a40f 100644
> --- a/arch/s390/kvm/interrupt.c
> +++ b/arch/s390/kvm/interrupt.c
> @@ -32,6 +32,7 @@
>   #include "kvm-s390.h"
>   #include "gaccess.h"
>   #include "trace-s390.h"
> +#include "pci.h"
>   
>   #define PFAULT_INIT 0x0600
>   #define PFAULT_DONE 0x0680
> @@ -3276,8 +3277,16 @@ static struct airq_struct gib_alert_irq = {
>   
>   void kvm_s390_gib_destroy(void)
>   {
> +	struct zpci_aift *aift;
> +
>   	if (!gib)
>   		return;
> +	aift = kvm_s390_pci_get_aift();
> +	if (aift) {
> +		mutex_lock(&aift->lock)

aift is a static variable and later patches seem to access that directly without the wrapper.
Can we get rid of kvm_s390_pci_get_aift?
;
> +		kvm_s390_pci_aen_exit();
> +		mutex_unlock(&aift->lock);
> +	}
>   	chsc_sgib(0);
>   	unregister_adapter_interrupt(&gib_alert_irq);
>   	free_page((unsigned long)gib);
> @@ -3315,6 +3324,14 @@ int kvm_s390_gib_init(u8 nisc)
>   		goto out_unreg_gal;
>   	}
>   
> +	if (IS_ENABLED(CONFIG_PCI) && sclp.has_aeni) {
> +		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);
>   	goto out;
>   
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 14a18ba5ff2c..9cd3c8eb59e8 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -48,6 +48,7 @@
>   #include <asm/fpu/api.h>
>   #include "kvm-s390.h"
>   #include "gaccess.h"
> +#include "pci.h"
>   
>   #define CREATE_TRACE_POINTS
>   #include "trace.h"
> @@ -503,6 +504,8 @@ int kvm_arch_init(void *opaque)
>   		goto out;
>   	}
>   
> +	kvm_s390_pci_init();
> +
>   	rc = kvm_s390_gib_init(GAL_ISC);
>   	if (rc)
>   		goto out;
> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
> index ecfc458a5b39..f0e5386ff943 100644
> --- a/arch/s390/kvm/pci.c
> +++ b/arch/s390/kvm/pci.c
> @@ -10,6 +10,113 @@
>   #include <linux/kvm_host.h>
>   #include <linux/pci.h>
>   #include <asm/kvm_pci.h>
> +#include "pci.h"
> +
> +static struct zpci_aift aift;

see below.
> +
> +static inline int __set_irq_noiib(u16 ctl, u8 isc)
> +{
> +	union zpci_sic_iib iib = {{0}};
> +
> +	return zpci_set_irq_ctrl(ctl, isc, &iib);
> +}
> +
> +struct zpci_aift *kvm_s390_pci_get_aift(void)
> +{
> +	return &aift;
> +}
> +
> +/* Caller must hold the aift lock before calling this function */
> +void kvm_s390_pci_aen_exit(void)
> +{
> +	struct zpci_gaite *gait;
> +	unsigned long flags;
> +	struct airq_iv *sbv;
> +	struct kvm_zdev **gait_kzdev;
> +	int size;
> +
> +	/* Clear the GAIT and forwarding summary vector */
> +	__set_irq_noiib(SIC_SET_AENI_CONTROLS, 0);
> +
> +	spin_lock_irqsave(&aift.gait_lock, flags);
> +	gait = aift.gait;
> +	sbv = aift.sbv;
> +	gait_kzdev = aift.kzdev;
> +	aift.gait = 0;
> +	aift.sbv = 0;
> +	aift.kzdev = 0;
> +	spin_unlock_irqrestore(&aift.gait_lock, flags);
> +
> +	if (sbv)
> +		airq_iv_release(sbv);
> +	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
> +				    sizeof(struct zpci_gaite)));
> +	free_pages((unsigned long)gait, size);
> +	kfree(gait_kzdev);
> +}
> +
> +int kvm_s390_pci_aen_init(u8 nisc)
> +{
> +	union zpci_sic_iib iib = {{0}};
> +	struct page *page;
> +	int rc = 0, size;
> +
> +	/* If already enabled for AEN, bail out now */
> +	if (aift.gait || aift.sbv)
> +		return -EPERM;
> +
> +	mutex_lock(&aift.lock);
> +	aift.kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev),
> +			     GFP_KERNEL);
> +	if (!aift.kzdev) {
> +		rc = -ENOMEM;
> +		goto unlock;
> +	}
> +	aift.sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, 0);
> +	if (!aift.sbv) {
> +		rc = -ENOMEM;
> +		goto free_zdev;
> +	}
> +	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
> +				    sizeof(struct zpci_gaite)));
> +	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, size);
> +	if (!page) {
> +		rc = -ENOMEM;
> +		goto free_sbv;
> +	}
> +	aift.gait = (struct zpci_gaite *)page_to_phys(page);
> +
> +	iib.aipb.faisb = (u64)aift.sbv->vector;
> +	iib.aipb.gait = (u64)aift.gait;
> +	iib.aipb.afi = nisc;
> +	iib.aipb.faal = ZPCI_NR_DEVICES;
> +
> +	/* Setup Adapter Event Notification Interpretation */
> +	if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, &iib)) {
> +		rc = -EIO;
> +		goto free_gait;
> +	}
> +
> +	/* Enable floating IRQs */
> +	if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) {
> +		rc = -EIO;
> +		kvm_s390_pci_aen_exit();
> +	}
> +
> +	goto unlock;
> +
> +free_gait:
> +	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
> +				    sizeof(struct zpci_gaite)));
> +	free_pages((unsigned long)aift.gait, size);
> +free_sbv:
> +	airq_iv_release(aift.sbv);
> +free_zdev:
> +	kfree(aift.kzdev);
> +unlock:
> +	mutex_unlock(&aift.lock);
> +	return rc;
> +}
>   
>   int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
>   {
> @@ -55,3 +162,9 @@ int kvm_s390_pci_attach_kvm(struct zpci_dev *zdev, struct kvm *kvm)
>   	return 0;
>   }
>   EXPORT_SYMBOL_GPL(kvm_s390_pci_attach_kvm);
> +
> +void kvm_s390_pci_init(void)
> +{
> +	spin_lock_init(&aift.gait_lock);
> +	mutex_init(&aift.lock);
> +}

Can we maybe use designated initializer for the static definition of aift, e.g. something
like
static struct zpci_aift aift = {
	.gait_lock = __SPIN_LOCK_UNLOCKED(aift.gait_lock),
	.lock	= __MUTEX_INITIALIZER(aift.lock),
}
and get rid of the init function?


> diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h
> new file mode 100644
> index 000000000000..74b06d39be3b
> --- /dev/null
> +++ b/arch/s390/kvm/pci.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * s390 kvm PCI passthrough support
> + *
> + * Copyright IBM Corp. 2021
> + *
> + *    Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
> + */
> +
> +#ifndef __KVM_S390_PCI_H
> +#define __KVM_S390_PCI_H
> +
> +#include <linux/pci.h>
> +#include <linux/mutex.h>
> +#include <asm/airq.h>
> +#include <asm/kvm_pci.h>
> +
> +struct zpci_gaite {
> +	unsigned int gisa;

since we use u8 below, what about u32
> +	u8 gisc;
> +	u8 count;
> +	u8 reserved;
> +	u8 aisbo;
> +	unsigned long aisb;

and u64 ?
> +};
> +
> +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 lock; /* Protects the other structures in aift */
> +};
> +
> +struct zpci_aift *kvm_s390_pci_get_aift(void);
> +
> +int kvm_s390_pci_aen_init(u8 nisc);
> +void kvm_s390_pci_aen_exit(void);
> +
> +void kvm_s390_pci_init(void);
> +
> +#endif /* __KVM_S390_PCI_H */
>
Matthew Rosato Dec. 9, 2021, 8:20 p.m. UTC | #2
On 12/9/21 2:54 PM, Christian Borntraeger wrote:
> Am 07.12.21 um 21:57 schrieb Matthew Rosato:
>> Initial setup for Adapter Event Notification Interpretation for zPCI
>> passthrough devices.  Specifically, allocate a structure for 
>> forwarding of
>> adapter events and pass the address of this structure to firmware.
>>
>> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
>> ---
>>   arch/s390/include/asm/pci_insn.h |  12 ++++
>>   arch/s390/kvm/interrupt.c        |  17 +++++
>>   arch/s390/kvm/kvm-s390.c         |   3 +
>>   arch/s390/kvm/pci.c              | 113 +++++++++++++++++++++++++++++++
>>   arch/s390/kvm/pci.h              |  42 ++++++++++++
>>   5 files changed, 187 insertions(+)
>>   create mode 100644 arch/s390/kvm/pci.h
>>
>> diff --git a/arch/s390/include/asm/pci_insn.h 
>> b/arch/s390/include/asm/pci_insn.h
>> index 5331082fa516..e5f57cfe1d45 100644
>> --- a/arch/s390/include/asm/pci_insn.h
>> +++ b/arch/s390/include/asm/pci_insn.h
>> @@ -101,6 +101,7 @@ struct zpci_fib {
>>   /* 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
>> @@ -127,9 +128,20 @@ struct zpci_cdiib {
>>       u64 : 64;
>>   } __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 {
>>       struct zpci_diib diib;
>>       struct zpci_cdiib cdiib;
>> +    struct zpci_aipb aipb;
>>   };
>>   DECLARE_STATIC_KEY_FALSE(have_mio);
>> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
>> index f9b872e358c6..4efe0e95a40f 100644
>> --- a/arch/s390/kvm/interrupt.c
>> +++ b/arch/s390/kvm/interrupt.c
>> @@ -32,6 +32,7 @@
>>   #include "kvm-s390.h"
>>   #include "gaccess.h"
>>   #include "trace-s390.h"
>> +#include "pci.h"
>>   #define PFAULT_INIT 0x0600
>>   #define PFAULT_DONE 0x0680
>> @@ -3276,8 +3277,16 @@ static struct airq_struct gib_alert_irq = {
>>   void kvm_s390_gib_destroy(void)
>>   {
>> +    struct zpci_aift *aift;
>> +
>>       if (!gib)
>>           return;
>> +    aift = kvm_s390_pci_get_aift();
>> +    if (aift) {
>> +        mutex_lock(&aift->lock)
> 
> aift is a static variable and later patches seem to access that directly 
> without the wrapper.
> Can we get rid of kvm_s390_pci_get_aift?

kvm/interrupt.c must also access it when handling AEN forwarding (next 
patch)

> ;
>> +        kvm_s390_pci_aen_exit();
>> +        mutex_unlock(&aift->lock);
>> +    }
>>       chsc_sgib(0);
>>       unregister_adapter_interrupt(&gib_alert_irq);
>>       free_page((unsigned long)gib);
>> @@ -3315,6 +3324,14 @@ int kvm_s390_gib_init(u8 nisc)
>>           goto out_unreg_gal;
>>       }
>> +    if (IS_ENABLED(CONFIG_PCI) && sclp.has_aeni) {
>> +        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);
>>       goto out;
>> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
>> index 14a18ba5ff2c..9cd3c8eb59e8 100644
>> --- a/arch/s390/kvm/kvm-s390.c
>> +++ b/arch/s390/kvm/kvm-s390.c
>> @@ -48,6 +48,7 @@
>>   #include <asm/fpu/api.h>
>>   #include "kvm-s390.h"
>>   #include "gaccess.h"
>> +#include "pci.h"
>>   #define CREATE_TRACE_POINTS
>>   #include "trace.h"
>> @@ -503,6 +504,8 @@ int kvm_arch_init(void *opaque)
>>           goto out;
>>       }
>> +    kvm_s390_pci_init();
>> +
>>       rc = kvm_s390_gib_init(GAL_ISC);
>>       if (rc)
>>           goto out;
>> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
>> index ecfc458a5b39..f0e5386ff943 100644
>> --- a/arch/s390/kvm/pci.c
>> +++ b/arch/s390/kvm/pci.c
>> @@ -10,6 +10,113 @@
>>   #include <linux/kvm_host.h>
>>   #include <linux/pci.h>
>>   #include <asm/kvm_pci.h>
>> +#include "pci.h"
>> +
>> +static struct zpci_aift aift;
> 
> see below.
>> +
>> +static inline int __set_irq_noiib(u16 ctl, u8 isc)
>> +{
>> +    union zpci_sic_iib iib = {{0}};
>> +
>> +    return zpci_set_irq_ctrl(ctl, isc, &iib);
>> +}
>> +
>> +struct zpci_aift *kvm_s390_pci_get_aift(void)
>> +{
>> +    return &aift;
>> +}
>> +
>> +/* Caller must hold the aift lock before calling this function */
>> +void kvm_s390_pci_aen_exit(void)
>> +{
>> +    struct zpci_gaite *gait;
>> +    unsigned long flags;
>> +    struct airq_iv *sbv;
>> +    struct kvm_zdev **gait_kzdev;
>> +    int size;
>> +
>> +    /* Clear the GAIT and forwarding summary vector */
>> +    __set_irq_noiib(SIC_SET_AENI_CONTROLS, 0);
>> +
>> +    spin_lock_irqsave(&aift.gait_lock, flags);
>> +    gait = aift.gait;
>> +    sbv = aift.sbv;
>> +    gait_kzdev = aift.kzdev;
>> +    aift.gait = 0;
>> +    aift.sbv = 0;
>> +    aift.kzdev = 0;
>> +    spin_unlock_irqrestore(&aift.gait_lock, flags);
>> +
>> +    if (sbv)
>> +        airq_iv_release(sbv);
>> +    size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
>> +                    sizeof(struct zpci_gaite)));
>> +    free_pages((unsigned long)gait, size);
>> +    kfree(gait_kzdev);
>> +}
>> +
>> +int kvm_s390_pci_aen_init(u8 nisc)
>> +{
>> +    union zpci_sic_iib iib = {{0}};
>> +    struct page *page;
>> +    int rc = 0, size;
>> +
>> +    /* If already enabled for AEN, bail out now */
>> +    if (aift.gait || aift.sbv)
>> +        return -EPERM;
>> +
>> +    mutex_lock(&aift.lock);
>> +    aift.kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev),
>> +                 GFP_KERNEL);
>> +    if (!aift.kzdev) {
>> +        rc = -ENOMEM;
>> +        goto unlock;
>> +    }
>> +    aift.sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, 0);
>> +    if (!aift.sbv) {
>> +        rc = -ENOMEM;
>> +        goto free_zdev;
>> +    }
>> +    size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
>> +                    sizeof(struct zpci_gaite)));
>> +    page = alloc_pages(GFP_KERNEL | __GFP_ZERO, size);
>> +    if (!page) {
>> +        rc = -ENOMEM;
>> +        goto free_sbv;
>> +    }
>> +    aift.gait = (struct zpci_gaite *)page_to_phys(page);
>> +
>> +    iib.aipb.faisb = (u64)aift.sbv->vector;
>> +    iib.aipb.gait = (u64)aift.gait;
>> +    iib.aipb.afi = nisc;
>> +    iib.aipb.faal = ZPCI_NR_DEVICES;
>> +
>> +    /* Setup Adapter Event Notification Interpretation */
>> +    if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, &iib)) {
>> +        rc = -EIO;
>> +        goto free_gait;
>> +    }
>> +
>> +    /* Enable floating IRQs */
>> +    if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) {
>> +        rc = -EIO;
>> +        kvm_s390_pci_aen_exit();
>> +    }
>> +
>> +    goto unlock;
>> +
>> +free_gait:
>> +    size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
>> +                    sizeof(struct zpci_gaite)));
>> +    free_pages((unsigned long)aift.gait, size);
>> +free_sbv:
>> +    airq_iv_release(aift.sbv);
>> +free_zdev:
>> +    kfree(aift.kzdev);
>> +unlock:
>> +    mutex_unlock(&aift.lock);
>> +    return rc;
>> +}
>>   int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
>>   {
>> @@ -55,3 +162,9 @@ int kvm_s390_pci_attach_kvm(struct zpci_dev *zdev, 
>> struct kvm *kvm)
>>       return 0;
>>   }
>>   EXPORT_SYMBOL_GPL(kvm_s390_pci_attach_kvm);
>> +
>> +void kvm_s390_pci_init(void)
>> +{
>> +    spin_lock_init(&aift.gait_lock);
>> +    mutex_init(&aift.lock);
>> +}
> 
> Can we maybe use designated initializer for the static definition of 
> aift, e.g. something
> like
> static struct zpci_aift aift = {
>      .gait_lock = __SPIN_LOCK_UNLOCKED(aift.gait_lock),
>      .lock    = __MUTEX_INITIALIZER(aift.lock),
> }
> and get rid of the init function? >

Maybe -- I can certainly do the above, but I do add a call to 
zpci_get_mdd() in the init function (patch 23), so if I want to in patch 
23 instead add .mdd = zpci_get_mdd() to this designated initializer I'd 
have to re-work zpci_get_mdd (patch 12) to return the mdd rather than 
the CLP LIST PCI return code.  We want at least a warning if we're 
setting a 0 for mdd because the CLP failed for some bizarre reason.

I guess one option would be to move the WARN_ON into the zpci_get_mdd() 
function itself and then now we can do

u32 zpci_get_mdd(void);

Niklas, what do you think?

> 
>> diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h
>> new file mode 100644
>> index 000000000000..74b06d39be3b
>> --- /dev/null
>> +++ b/arch/s390/kvm/pci.h
>> @@ -0,0 +1,42 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * s390 kvm PCI passthrough support
>> + *
>> + * Copyright IBM Corp. 2021
>> + *
>> + *    Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
>> + */
>> +
>> +#ifndef __KVM_S390_PCI_H
>> +#define __KVM_S390_PCI_H
>> +
>> +#include <linux/pci.h>
>> +#include <linux/mutex.h>
>> +#include <asm/airq.h>
>> +#include <asm/kvm_pci.h>
>> +
>> +struct zpci_gaite {
>> +    unsigned int gisa;
> 
> since we use u8 below, what about u32
>> +    u8 gisc;
>> +    u8 count;
>> +    u8 reserved;
>> +    u8 aisbo;
>> +    unsigned long aisb;
> 
> and u64 ?
>> +};
>> +
>> +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 lock; /* Protects the other structures in aift */
>> +};
>> +
>> +struct zpci_aift *kvm_s390_pci_get_aift(void);
>> +
>> +int kvm_s390_pci_aen_init(u8 nisc);
>> +void kvm_s390_pci_aen_exit(void);
>> +
>> +void kvm_s390_pci_init(void);
>> +
>> +#endif /* __KVM_S390_PCI_H */
>>
Christian Borntraeger Dec. 9, 2021, 8:23 p.m. UTC | #3
Am 09.12.21 um 21:20 schrieb Matthew Rosato:
> On 12/9/21 2:54 PM, Christian Borntraeger wrote:
>> Am 07.12.21 um 21:57 schrieb Matthew Rosato:
>>> Initial setup for Adapter Event Notification Interpretation for zPCI
>>> passthrough devices.  Specifically, allocate a structure for forwarding of
>>> adapter events and pass the address of this structure to firmware.
>>>
>>> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
>>> ---
>>>   arch/s390/include/asm/pci_insn.h |  12 ++++
>>>   arch/s390/kvm/interrupt.c        |  17 +++++
>>>   arch/s390/kvm/kvm-s390.c         |   3 +
>>>   arch/s390/kvm/pci.c              | 113 +++++++++++++++++++++++++++++++
>>>   arch/s390/kvm/pci.h              |  42 ++++++++++++
>>>   5 files changed, 187 insertions(+)
>>>   create mode 100644 arch/s390/kvm/pci.h
>>>
>>> diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h
>>> index 5331082fa516..e5f57cfe1d45 100644
>>> --- a/arch/s390/include/asm/pci_insn.h
>>> +++ b/arch/s390/include/asm/pci_insn.h
>>> @@ -101,6 +101,7 @@ struct zpci_fib {
>>>   /* 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
>>> @@ -127,9 +128,20 @@ struct zpci_cdiib {
>>>       u64 : 64;
>>>   } __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 {
>>>       struct zpci_diib diib;
>>>       struct zpci_cdiib cdiib;
>>> +    struct zpci_aipb aipb;
>>>   };
>>>   DECLARE_STATIC_KEY_FALSE(have_mio);
>>> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
>>> index f9b872e358c6..4efe0e95a40f 100644
>>> --- a/arch/s390/kvm/interrupt.c
>>> +++ b/arch/s390/kvm/interrupt.c
>>> @@ -32,6 +32,7 @@
>>>   #include "kvm-s390.h"
>>>   #include "gaccess.h"
>>>   #include "trace-s390.h"
>>> +#include "pci.h"
>>>   #define PFAULT_INIT 0x0600
>>>   #define PFAULT_DONE 0x0680
>>> @@ -3276,8 +3277,16 @@ static struct airq_struct gib_alert_irq = {
>>>   void kvm_s390_gib_destroy(void)
>>>   {
>>> +    struct zpci_aift *aift;
>>> +
>>>       if (!gib)
>>>           return;
>>> +    aift = kvm_s390_pci_get_aift();
>>> +    if (aift) {
>>> +        mutex_lock(&aift->lock)
>>
>> aift is a static variable and later patches seem to access that directly without the wrapper.
>> Can we get rid of kvm_s390_pci_get_aift?
> 
> kvm/interrupt.c must also access it when handling AEN forwarding (next patch)

So maybe just make it non-static and declare it in the header file?
[...]

>> Can we maybe use designated initializer for the static definition of aift, e.g. something
>> like
>> static struct zpci_aift aift = {
>>      .gait_lock = __SPIN_LOCK_UNLOCKED(aift.gait_lock),
>>      .lock    = __MUTEX_INITIALIZER(aift.lock),
>> }
>> and get rid of the init function? >
> 
> Maybe -- I can certainly do the above, but I do add a call to zpci_get_mdd() in the init function (patch 23), so if I want to in patch 23 instead add .mdd = zpci_get_mdd() to this designated initializer I'd have to re-work zpci_get_mdd (patch 12) to return the mdd rather than the CLP LIST PCI return code.  We want at least a warning if we're setting a 0 for mdd because the CLP failed for some bizarre reason.
> 
> I guess one option would be to move the WARN_ON into the zpci_get_mdd() function itself and then now we can do

So maybe leave this as is.
> 
> u32 zpci_get_mdd(void);
> 
> Niklas, what do you think?
>
Niklas Schnelle Dec. 10, 2021, 8:36 a.m. UTC | #4
On Thu, 2021-12-09 at 15:20 -0500, Matthew Rosato wrote:
> On 12/9/21 2:54 PM, Christian Borntraeger wrote:
> > Am 07.12.21 um 21:57 schrieb Matthew Rosato:
> > > Initial setup for Adapter Event Notification Interpretation for zPCI
> > > passthrough devices.  Specifically, allocate a structure for 
> > > forwarding of
> > > adapter events and pass the address of this structure to firmware.
> > > 
> > > Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
> > > ---
> > >   arch/s390/include/asm/pci_insn.h |  12 ++++
> > >   arch/s390/kvm/interrupt.c        |  17 +++++
> > >   arch/s390/kvm/kvm-s390.c         |   3 +
> > >   arch/s390/kvm/pci.c              | 113 +++++++++++++++++++++++++++++++
> > >   arch/s390/kvm/pci.h              |  42 ++++++++++++
> > >   5 files changed, 187 insertions(+)
> > >   create mode 100644 arch/s390/kvm/pci.h
> > > 
---8<---
> > >   int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
> > >   {
> > > @@ -55,3 +162,9 @@ int kvm_s390_pci_attach_kvm(struct zpci_dev *zdev, 
> > > struct kvm *kvm)
> > >       return 0;
> > >   }
> > >   EXPORT_SYMBOL_GPL(kvm_s390_pci_attach_kvm);
> > > +
> > > +void kvm_s390_pci_init(void)
> > > +{
> > > +    spin_lock_init(&aift.gait_lock);
> > > +    mutex_init(&aift.lock);
> > > +}
> > 
> > Can we maybe use designated initializer for the static definition of 
> > aift, e.g. something
> > like
> > static struct zpci_aift aift = {
> >      .gait_lock = __SPIN_LOCK_UNLOCKED(aift.gait_lock),
> >      .lock    = __MUTEX_INITIALIZER(aift.lock),
> > }
> > and get rid of the init function? >
> 
> Maybe -- I can certainly do the above, but I do add a call to 
> zpci_get_mdd() in the init function (patch 23), so if I want to in patch 
> 23 instead add .mdd = zpci_get_mdd() to this designated initializer I'd 
> have to re-work zpci_get_mdd (patch 12) to return the mdd rather than 
> the CLP LIST PCI return code.  We want at least a warning if we're 
> setting a 0 for mdd because the CLP failed for some bizarre reason.
> 
> I guess one option would be to move the WARN_ON into the zpci_get_mdd() 
> function itself and then now we can do

Hmm, if we do change zpci_get_mdd() which I'm generally fine with I
feel like the initializer would be weird mix of truly static lock
initialization and a function that actually does a CLP.
I'm also a little worried about initialization order if kvm is built-
in. The CLP should work even with PCI not initialized but what if for
example the facility isn't even there?

Also if you do change zpci_get-mdd() I'd prefer a pr_err() instead of a
WARN_ON(), no reason to crash the system for this if it runs with
panic-on-warn. So I think overall keeping it as is makes more sense.
Pierre Morel Dec. 10, 2021, 9:54 a.m. UTC | #5
On 12/7/21 21:57, Matthew Rosato wrote:
> Initial setup for Adapter Event Notification Interpretation for zPCI
> passthrough devices.  Specifically, allocate a structure for forwarding of
> adapter events and pass the address of this structure to firmware.
> 
> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
> ---
>   arch/s390/include/asm/pci_insn.h |  12 ++++
>   arch/s390/kvm/interrupt.c        |  17 +++++
>   arch/s390/kvm/kvm-s390.c         |   3 +
>   arch/s390/kvm/pci.c              | 113 +++++++++++++++++++++++++++++++
>   arch/s390/kvm/pci.h              |  42 ++++++++++++
>   5 files changed, 187 insertions(+)
>   create mode 100644 arch/s390/kvm/pci.h
> 
> diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h
> index 5331082fa516..e5f57cfe1d45 100644
> --- a/arch/s390/include/asm/pci_insn.h
> +++ b/arch/s390/include/asm/pci_insn.h
> @@ -101,6 +101,7 @@ struct zpci_fib {
>   /* 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
> @@ -127,9 +128,20 @@ struct zpci_cdiib {
>   	u64 : 64;
>   } __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 {
>   	struct zpci_diib diib;
>   	struct zpci_cdiib cdiib;
> +	struct zpci_aipb aipb;
>   };
>   
>   DECLARE_STATIC_KEY_FALSE(have_mio);
> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
> index f9b872e358c6..4efe0e95a40f 100644
> --- a/arch/s390/kvm/interrupt.c
> +++ b/arch/s390/kvm/interrupt.c
> @@ -32,6 +32,7 @@
>   #include "kvm-s390.h"
>   #include "gaccess.h"
>   #include "trace-s390.h"
> +#include "pci.h"
>   
>   #define PFAULT_INIT 0x0600
>   #define PFAULT_DONE 0x0680
> @@ -3276,8 +3277,16 @@ static struct airq_struct gib_alert_irq = {
>   
>   void kvm_s390_gib_destroy(void)
>   {
> +	struct zpci_aift *aift;
> +
>   	if (!gib)
>   		return;
> +	aift = kvm_s390_pci_get_aift();
> +	if (aift) {
> +		mutex_lock(&aift->lock);
> +		kvm_s390_pci_aen_exit();

Shouldn't we check for CONFIG_PCI and sclp.gas_aeni here as in gib_init ?

> +		mutex_unlock(&aift->lock);
> +	}
>   	chsc_sgib(0);
>   	unregister_adapter_interrupt(&gib_alert_irq);
>   	free_page((unsigned long)gib);
> @@ -3315,6 +3324,14 @@ int kvm_s390_gib_init(u8 nisc)
>   		goto out_unreg_gal;
>   	}
>   
> +	if (IS_ENABLED(CONFIG_PCI) && sclp.has_aeni) {
> +		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);
>   	goto out;
>   
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 14a18ba5ff2c..9cd3c8eb59e8 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -48,6 +48,7 @@
>   #include <asm/fpu/api.h>
>   #include "kvm-s390.h"
>   #include "gaccess.h"
> +#include "pci.h"
>   
>   #define CREATE_TRACE_POINTS
>   #include "trace.h"
> @@ -503,6 +504,8 @@ int kvm_arch_init(void *opaque)
>   		goto out;
>   	}
>   
> +	kvm_s390_pci_init();
> +
>   	rc = kvm_s390_gib_init(GAL_ISC);
>   	if (rc)
>   		goto out;
> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
> index ecfc458a5b39..f0e5386ff943 100644
> --- a/arch/s390/kvm/pci.c
> +++ b/arch/s390/kvm/pci.c
> @@ -10,6 +10,113 @@
>   #include <linux/kvm_host.h>
>   #include <linux/pci.h>
>   #include <asm/kvm_pci.h>
> +#include "pci.h"
> +
> +static struct zpci_aift aift;
> +
> +static inline int __set_irq_noiib(u16 ctl, u8 isc)
> +{
> +	union zpci_sic_iib iib = {{0}};
> +
> +	return zpci_set_irq_ctrl(ctl, isc, &iib);
> +}
> +
> +struct zpci_aift *kvm_s390_pci_get_aift(void)
> +{
> +	return &aift;
> +}
> +
> +/* Caller must hold the aift lock before calling this function */
> +void kvm_s390_pci_aen_exit(void)
> +{
> +	struct zpci_gaite *gait;
> +	unsigned long flags;
> +	struct airq_iv *sbv;
> +	struct kvm_zdev **gait_kzdev;
> +	int size;
> +
> +	/* Clear the GAIT and forwarding summary vector */
> +	__set_irq_noiib(SIC_SET_AENI_CONTROLS, 0);

Why don't we use the PCI ISC here?

...snip...
Pierre Morel Dec. 10, 2021, 10:55 a.m. UTC | #6
On 12/10/21 10:54, Pierre Morel wrote:
> 
> 
> On 12/7/21 21:57, Matthew Rosato wrote:
>> Initial setup for Adapter Event Notification Interpretation for zPCI
>> passthrough devices.  Specifically, allocate a structure for 
>> forwarding of
>> adapter events and pass the address of this structure to firmware.
>>
>> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
>> ---
>>   arch/s390/include/asm/pci_insn.h |  12 ++++
>>   arch/s390/kvm/interrupt.c        |  17 +++++
>>   arch/s390/kvm/kvm-s390.c         |   3 +
>>   arch/s390/kvm/pci.c              | 113 +++++++++++++++++++++++++++++++
>>   arch/s390/kvm/pci.h              |  42 ++++++++++++
>>   5 files changed, 187 insertions(+)
>>   create mode 100644 arch/s390/kvm/pci.h
>>
>> diff --git a/arch/s390/include/asm/pci_insn.h 
>> b/arch/s390/include/asm/pci_insn.h
>> index 5331082fa516..e5f57cfe1d45 100644
>> --- a/arch/s390/include/asm/pci_insn.h
>> +++ b/arch/s390/include/asm/pci_insn.h
>> @@ -101,6 +101,7 @@ struct zpci_fib {
>>   /* 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
>> @@ -127,9 +128,20 @@ struct zpci_cdiib {
>>       u64 : 64;
>>   } __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 {
>>       struct zpci_diib diib;
>>       struct zpci_cdiib cdiib;
>> +    struct zpci_aipb aipb;
>>   };
>>   DECLARE_STATIC_KEY_FALSE(have_mio);
>> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
>> index f9b872e358c6..4efe0e95a40f 100644
>> --- a/arch/s390/kvm/interrupt.c
>> +++ b/arch/s390/kvm/interrupt.c
>> @@ -32,6 +32,7 @@
>>   #include "kvm-s390.h"
>>   #include "gaccess.h"
>>   #include "trace-s390.h"
>> +#include "pci.h"
>>   #define PFAULT_INIT 0x0600
>>   #define PFAULT_DONE 0x0680
>> @@ -3276,8 +3277,16 @@ static struct airq_struct gib_alert_irq = {
>>   void kvm_s390_gib_destroy(void)
>>   {
>> +    struct zpci_aift *aift;
>> +
>>       if (!gib)
>>           return;
>> +    aift = kvm_s390_pci_get_aift();
>> +    if (aift) {
>> +        mutex_lock(&aift->lock);
>> +        kvm_s390_pci_aen_exit();
> 
> Shouldn't we check for CONFIG_PCI and sclp.gas_aeni here as in gib_init ?
> 
>> +        mutex_unlock(&aift->lock);
>> +    }
>>       chsc_sgib(0);
>>       unregister_adapter_interrupt(&gib_alert_irq);
>>       free_page((unsigned long)gib);
>> @@ -3315,6 +3324,14 @@ int kvm_s390_gib_init(u8 nisc)
>>           goto out_unreg_gal;
>>       }
>> +    if (IS_ENABLED(CONFIG_PCI) && sclp.has_aeni) {
>> +        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);
>>       goto out;
>> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
>> index 14a18ba5ff2c..9cd3c8eb59e8 100644
>> --- a/arch/s390/kvm/kvm-s390.c
>> +++ b/arch/s390/kvm/kvm-s390.c
>> @@ -48,6 +48,7 @@
>>   #include <asm/fpu/api.h>
>>   #include "kvm-s390.h"
>>   #include "gaccess.h"
>> +#include "pci.h"
>>   #define CREATE_TRACE_POINTS
>>   #include "trace.h"
>> @@ -503,6 +504,8 @@ int kvm_arch_init(void *opaque)
>>           goto out;
>>       }
>> +    kvm_s390_pci_init();
>> +
>>       rc = kvm_s390_gib_init(GAL_ISC);
>>       if (rc)
>>           goto out;
>> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
>> index ecfc458a5b39..f0e5386ff943 100644
>> --- a/arch/s390/kvm/pci.c
>> +++ b/arch/s390/kvm/pci.c
>> @@ -10,6 +10,113 @@
>>   #include <linux/kvm_host.h>
>>   #include <linux/pci.h>
>>   #include <asm/kvm_pci.h>
>> +#include "pci.h"
>> +
>> +static struct zpci_aift aift;
>> +
>> +static inline int __set_irq_noiib(u16 ctl, u8 isc)
>> +{
>> +    union zpci_sic_iib iib = {{0}};
>> +
>> +    return zpci_set_irq_ctrl(ctl, isc, &iib);
>> +}
>> +
>> +struct zpci_aift *kvm_s390_pci_get_aift(void)
>> +{
>> +    return &aift;
>> +}
>> +
>> +/* Caller must hold the aift lock before calling this function */
>> +void kvm_s390_pci_aen_exit(void)
>> +{
>> +    struct zpci_gaite *gait;
>> +    unsigned long flags;
>> +    struct airq_iv *sbv;
>> +    struct kvm_zdev **gait_kzdev;
>> +    int size;
>> +
>> +    /* Clear the GAIT and forwarding summary vector */
>> +    __set_irq_noiib(SIC_SET_AENI_CONTROLS, 0);
> 
> Why don't we use the PCI ISC here?

hum OK, sorry, isc is ignored for SIC_SET_AENI_CONTROLS

> 
> ...snip...
>
diff mbox series

Patch

diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h
index 5331082fa516..e5f57cfe1d45 100644
--- a/arch/s390/include/asm/pci_insn.h
+++ b/arch/s390/include/asm/pci_insn.h
@@ -101,6 +101,7 @@  struct zpci_fib {
 /* 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
@@ -127,9 +128,20 @@  struct zpci_cdiib {
 	u64 : 64;
 } __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 {
 	struct zpci_diib diib;
 	struct zpci_cdiib cdiib;
+	struct zpci_aipb aipb;
 };
 
 DECLARE_STATIC_KEY_FALSE(have_mio);
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index f9b872e358c6..4efe0e95a40f 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -32,6 +32,7 @@ 
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "trace-s390.h"
+#include "pci.h"
 
 #define PFAULT_INIT 0x0600
 #define PFAULT_DONE 0x0680
@@ -3276,8 +3277,16 @@  static struct airq_struct gib_alert_irq = {
 
 void kvm_s390_gib_destroy(void)
 {
+	struct zpci_aift *aift;
+
 	if (!gib)
 		return;
+	aift = kvm_s390_pci_get_aift();
+	if (aift) {
+		mutex_lock(&aift->lock);
+		kvm_s390_pci_aen_exit();
+		mutex_unlock(&aift->lock);
+	}
 	chsc_sgib(0);
 	unregister_adapter_interrupt(&gib_alert_irq);
 	free_page((unsigned long)gib);
@@ -3315,6 +3324,14 @@  int kvm_s390_gib_init(u8 nisc)
 		goto out_unreg_gal;
 	}
 
+	if (IS_ENABLED(CONFIG_PCI) && sclp.has_aeni) {
+		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);
 	goto out;
 
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 14a18ba5ff2c..9cd3c8eb59e8 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -48,6 +48,7 @@ 
 #include <asm/fpu/api.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
+#include "pci.h"
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -503,6 +504,8 @@  int kvm_arch_init(void *opaque)
 		goto out;
 	}
 
+	kvm_s390_pci_init();
+
 	rc = kvm_s390_gib_init(GAL_ISC);
 	if (rc)
 		goto out;
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index ecfc458a5b39..f0e5386ff943 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -10,6 +10,113 @@ 
 #include <linux/kvm_host.h>
 #include <linux/pci.h>
 #include <asm/kvm_pci.h>
+#include "pci.h"
+
+static struct zpci_aift aift;
+
+static inline int __set_irq_noiib(u16 ctl, u8 isc)
+{
+	union zpci_sic_iib iib = {{0}};
+
+	return zpci_set_irq_ctrl(ctl, isc, &iib);
+}
+
+struct zpci_aift *kvm_s390_pci_get_aift(void)
+{
+	return &aift;
+}
+
+/* Caller must hold the aift lock before calling this function */
+void kvm_s390_pci_aen_exit(void)
+{
+	struct zpci_gaite *gait;
+	unsigned long flags;
+	struct airq_iv *sbv;
+	struct kvm_zdev **gait_kzdev;
+	int size;
+
+	/* Clear the GAIT and forwarding summary vector */
+	__set_irq_noiib(SIC_SET_AENI_CONTROLS, 0);
+
+	spin_lock_irqsave(&aift.gait_lock, flags);
+	gait = aift.gait;
+	sbv = aift.sbv;
+	gait_kzdev = aift.kzdev;
+	aift.gait = 0;
+	aift.sbv = 0;
+	aift.kzdev = 0;
+	spin_unlock_irqrestore(&aift.gait_lock, flags);
+
+	if (sbv)
+		airq_iv_release(sbv);
+	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
+				    sizeof(struct zpci_gaite)));
+	free_pages((unsigned long)gait, size);
+	kfree(gait_kzdev);
+}
+
+int kvm_s390_pci_aen_init(u8 nisc)
+{
+	union zpci_sic_iib iib = {{0}};
+	struct page *page;
+	int rc = 0, size;
+
+	/* If already enabled for AEN, bail out now */
+	if (aift.gait || aift.sbv)
+		return -EPERM;
+
+	mutex_lock(&aift.lock);
+	aift.kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev),
+			     GFP_KERNEL);
+	if (!aift.kzdev) {
+		rc = -ENOMEM;
+		goto unlock;
+	}
+	aift.sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, 0);
+	if (!aift.sbv) {
+		rc = -ENOMEM;
+		goto free_zdev;
+	}
+	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
+				    sizeof(struct zpci_gaite)));
+	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, size);
+	if (!page) {
+		rc = -ENOMEM;
+		goto free_sbv;
+	}
+	aift.gait = (struct zpci_gaite *)page_to_phys(page);
+
+	iib.aipb.faisb = (u64)aift.sbv->vector;
+	iib.aipb.gait = (u64)aift.gait;
+	iib.aipb.afi = nisc;
+	iib.aipb.faal = ZPCI_NR_DEVICES;
+
+	/* Setup Adapter Event Notification Interpretation */
+	if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, &iib)) {
+		rc = -EIO;
+		goto free_gait;
+	}
+
+	/* Enable floating IRQs */
+	if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) {
+		rc = -EIO;
+		kvm_s390_pci_aen_exit();
+	}
+
+	goto unlock;
+
+free_gait:
+	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
+				    sizeof(struct zpci_gaite)));
+	free_pages((unsigned long)aift.gait, size);
+free_sbv:
+	airq_iv_release(aift.sbv);
+free_zdev:
+	kfree(aift.kzdev);
+unlock:
+	mutex_unlock(&aift.lock);
+	return rc;
+}
 
 int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
 {
@@ -55,3 +162,9 @@  int kvm_s390_pci_attach_kvm(struct zpci_dev *zdev, struct kvm *kvm)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_s390_pci_attach_kvm);
+
+void kvm_s390_pci_init(void)
+{
+	spin_lock_init(&aift.gait_lock);
+	mutex_init(&aift.lock);
+}
diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h
new file mode 100644
index 000000000000..74b06d39be3b
--- /dev/null
+++ b/arch/s390/kvm/pci.h
@@ -0,0 +1,42 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * s390 kvm PCI passthrough support
+ *
+ * Copyright IBM Corp. 2021
+ *
+ *    Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
+ */
+
+#ifndef __KVM_S390_PCI_H
+#define __KVM_S390_PCI_H
+
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <asm/airq.h>
+#include <asm/kvm_pci.h>
+
+struct zpci_gaite {
+	unsigned int gisa;
+	u8 gisc;
+	u8 count;
+	u8 reserved;
+	u8 aisbo;
+	unsigned long 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 lock; /* Protects the other structures in aift */
+};
+
+struct zpci_aift *kvm_s390_pci_get_aift(void);
+
+int kvm_s390_pci_aen_init(u8 nisc);
+void kvm_s390_pci_aen_exit(void);
+
+void kvm_s390_pci_init(void);
+
+#endif /* __KVM_S390_PCI_H */