Skip to content
Permalink
Browse files
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.

Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
  • Loading branch information
rosatomj authored and intel-lab-lkp committed Dec 7, 2021
1 parent b80bced commit a4580b9cbc02e756b893862d072f264af6f8d30d
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
@@ -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
@@ -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;

@@ -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;
@@ -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);
}
@@ -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 */

0 comments on commit a4580b9

Please sign in to comment.