KVM: s390: pci: do initial setup for AEN interpretation
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. Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com> Link: https://lore.kernel.org/r/20220606203325.110625-13-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
This commit is contained in:
parent
6438e30714
commit
98b1d33dac
|
@ -9,6 +9,7 @@
|
|||
#include <asm-generic/pci.h>
|
||||
#include <asm/pci_clp.h>
|
||||
#include <asm/pci_debug.h>
|
||||
#include <asm/pci_insn.h>
|
||||
#include <asm/sclp.h>
|
||||
|
||||
#define PCIBIOS_MIN_IO 0x1000
|
||||
|
@ -204,6 +205,9 @@ extern const struct attribute_group *zpci_attr_groups[];
|
|||
extern unsigned int s390_pci_force_floating __initdata;
|
||||
extern unsigned int s390_pci_no_rid;
|
||||
|
||||
extern union zpci_sic_iib *zpci_aipb;
|
||||
extern struct airq_iv *zpci_aif_sbv;
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Prototypes
|
||||
----------------------------------------------------------------------------- */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
@ -3328,6 +3329,11 @@ void kvm_s390_gib_destroy(void)
|
|||
{
|
||||
if (!gib)
|
||||
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);
|
||||
unregister_adapter_interrupt(&gib_alert_irq);
|
||||
free_page((unsigned long)gib);
|
||||
|
@ -3365,6 +3371,14 @@ int kvm_s390_gib_init(u8 nisc)
|
|||
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);
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <asm/fpu/api.h>
|
||||
#include "kvm-s390.h"
|
||||
#include "gaccess.h"
|
||||
#include "pci.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
@ -502,6 +503,14 @@ int kvm_arch_init(void *opaque)
|
|||
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);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
@ -516,6 +525,8 @@ int kvm_arch_init(void *opaque)
|
|||
void kvm_arch_exit(void)
|
||||
{
|
||||
kvm_s390_gib_destroy();
|
||||
if (kvm_s390_pci_interp_allowed())
|
||||
kvm_s390_pci_exit();
|
||||
debug_unregister(kvm_s390_dbf);
|
||||
debug_unregister(kvm_s390_dbf_uv);
|
||||
}
|
||||
|
|
|
@ -9,8 +9,149 @@
|
|||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/pci_insn.h>
|
||||
#include "pci.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void kvm_s390_pci_aen_exit(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kvm_zdev **gait_kzdev;
|
||||
|
||||
lockdep_assert_held(&aift->aift_lock);
|
||||
|
||||
/*
|
||||
* Contents of the aipb remain registered for the life of the host
|
||||
* kernel, the information preserved in zpci_aipb and zpci_aif_sbv
|
||||
* in case we insert the KVM module again later. Clear the AIFT
|
||||
* information and free anything not registered with underlying
|
||||
* firmware.
|
||||
*/
|
||||
spin_lock_irqsave(&aift->gait_lock, flags);
|
||||
gait_kzdev = aift->kzdev;
|
||||
aift->gait = NULL;
|
||||
aift->sbv = NULL;
|
||||
aift->kzdev = NULL;
|
||||
spin_unlock_irqrestore(&aift->gait_lock, flags);
|
||||
|
||||
kfree(gait_kzdev);
|
||||
}
|
||||
|
||||
static int zpci_setup_aipb(u8 nisc)
|
||||
{
|
||||
struct page *page;
|
||||
int size, rc;
|
||||
|
||||
zpci_aipb = kzalloc(sizeof(union zpci_sic_iib), GFP_KERNEL);
|
||||
if (!zpci_aipb)
|
||||
return -ENOMEM;
|
||||
|
||||
aift->sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, 0);
|
||||
if (!aift->sbv) {
|
||||
rc = -ENOMEM;
|
||||
goto free_aipb;
|
||||
}
|
||||
zpci_aif_sbv = aift->sbv;
|
||||
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);
|
||||
|
||||
zpci_aipb->aipb.faisb = virt_to_phys(aift->sbv->vector);
|
||||
zpci_aipb->aipb.gait = virt_to_phys(aift->gait);
|
||||
zpci_aipb->aipb.afi = nisc;
|
||||
zpci_aipb->aipb.faal = ZPCI_NR_DEVICES;
|
||||
|
||||
/* Setup Adapter Event Notification Interpretation */
|
||||
if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, zpci_aipb)) {
|
||||
rc = -EIO;
|
||||
goto free_gait;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_gait:
|
||||
free_pages((unsigned long)aift->gait, size);
|
||||
free_sbv:
|
||||
airq_iv_release(aift->sbv);
|
||||
zpci_aif_sbv = NULL;
|
||||
free_aipb:
|
||||
kfree(zpci_aipb);
|
||||
zpci_aipb = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int zpci_reset_aipb(u8 nisc)
|
||||
{
|
||||
/*
|
||||
* AEN registration can only happen once per system boot. If
|
||||
* an aipb already exists then AEN was already registered and
|
||||
* we can re-use the aipb contents. This can only happen if
|
||||
* the KVM module was removed and re-inserted. However, we must
|
||||
* ensure that the same forwarding ISC is used as this is assigned
|
||||
* during KVM module load.
|
||||
*/
|
||||
if (zpci_aipb->aipb.afi != nisc)
|
||||
return -EINVAL;
|
||||
|
||||
aift->sbv = zpci_aif_sbv;
|
||||
aift->gait = (struct zpci_gaite *)zpci_aipb->aipb.gait;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_s390_pci_aen_init(u8 nisc)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* If already enabled for AEN, bail out now */
|
||||
if (aift->gait || aift->sbv)
|
||||
return -EPERM;
|
||||
|
||||
mutex_lock(&aift->aift_lock);
|
||||
aift->kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev),
|
||||
GFP_KERNEL);
|
||||
if (!aift->kzdev) {
|
||||
rc = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!zpci_aipb)
|
||||
rc = zpci_setup_aipb(nisc);
|
||||
else
|
||||
rc = zpci_reset_aipb(nisc);
|
||||
if (rc)
|
||||
goto free_zdev;
|
||||
|
||||
/* Enable floating IRQs */
|
||||
if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) {
|
||||
rc = -EIO;
|
||||
kvm_s390_pci_aen_exit();
|
||||
}
|
||||
|
||||
goto unlock;
|
||||
|
||||
free_zdev:
|
||||
kfree(aift->kzdev);
|
||||
unlock:
|
||||
mutex_unlock(&aift->aift_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
|
||||
{
|
||||
struct kvm_zdev *kzdev;
|
||||
|
@ -34,3 +175,22 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
|
|||
zdev->kzdev = NULL;
|
||||
kfree(kzdev);
|
||||
}
|
||||
|
||||
int kvm_s390_pci_init(void)
|
||||
{
|
||||
aift = kzalloc(sizeof(struct zpci_aift), GFP_KERNEL);
|
||||
if (!aift)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&aift->gait_lock);
|
||||
mutex_init(&aift->aift_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_s390_pci_exit(void)
|
||||
{
|
||||
mutex_destroy(&aift->aift_lock);
|
||||
|
||||
kfree(aift);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,59 @@
|
|||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/airq.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
struct kvm_zdev {
|
||||
struct zpci_dev *zdev;
|
||||
struct kvm *kvm;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
int kvm_s390_pci_aen_init(u8 nisc);
|
||||
void kvm_s390_pci_aen_exit(void);
|
||||
|
||||
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);
|
|||
|
||||
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 *tmp, *zdev = NULL;
|
||||
|
|
Loading…
Reference in New Issue