16438e307SMatthew Rosato // SPDX-License-Identifier: GPL-2.0
26438e307SMatthew Rosato /*
36438e307SMatthew Rosato * s390 kvm PCI passthrough support
46438e307SMatthew Rosato *
56438e307SMatthew Rosato * Copyright IBM Corp. 2022
66438e307SMatthew Rosato *
76438e307SMatthew Rosato * Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
86438e307SMatthew Rosato */
96438e307SMatthew Rosato
106438e307SMatthew Rosato #include <linux/kvm_host.h>
116438e307SMatthew Rosato #include <linux/pci.h>
1298b1d33dSMatthew Rosato #include <asm/pci.h>
1398b1d33dSMatthew Rosato #include <asm/pci_insn.h>
143c5a1b6fSMatthew Rosato #include <asm/pci_io.h>
1509340b2fSMatthew Rosato #include <asm/sclp.h>
166438e307SMatthew Rosato #include "pci.h"
1709340b2fSMatthew Rosato #include "kvm-s390.h"
186438e307SMatthew Rosato
1998b1d33dSMatthew Rosato struct zpci_aift *aift;
2098b1d33dSMatthew Rosato
__set_irq_noiib(u16 ctl,u8 isc)2198b1d33dSMatthew Rosato static inline int __set_irq_noiib(u16 ctl, u8 isc)
2298b1d33dSMatthew Rosato {
2398b1d33dSMatthew Rosato union zpci_sic_iib iib = {{0}};
2498b1d33dSMatthew Rosato
2598b1d33dSMatthew Rosato return zpci_set_irq_ctrl(ctl, isc, &iib);
2698b1d33dSMatthew Rosato }
2798b1d33dSMatthew Rosato
kvm_s390_pci_aen_exit(void)2898b1d33dSMatthew Rosato void kvm_s390_pci_aen_exit(void)
2998b1d33dSMatthew Rosato {
3098b1d33dSMatthew Rosato unsigned long flags;
3198b1d33dSMatthew Rosato struct kvm_zdev **gait_kzdev;
3298b1d33dSMatthew Rosato
3398b1d33dSMatthew Rosato lockdep_assert_held(&aift->aift_lock);
3498b1d33dSMatthew Rosato
3598b1d33dSMatthew Rosato /*
3698b1d33dSMatthew Rosato * Contents of the aipb remain registered for the life of the host
3798b1d33dSMatthew Rosato * kernel, the information preserved in zpci_aipb and zpci_aif_sbv
3898b1d33dSMatthew Rosato * in case we insert the KVM module again later. Clear the AIFT
3998b1d33dSMatthew Rosato * information and free anything not registered with underlying
4098b1d33dSMatthew Rosato * firmware.
4198b1d33dSMatthew Rosato */
4298b1d33dSMatthew Rosato spin_lock_irqsave(&aift->gait_lock, flags);
4398b1d33dSMatthew Rosato gait_kzdev = aift->kzdev;
4498b1d33dSMatthew Rosato aift->gait = NULL;
4598b1d33dSMatthew Rosato aift->sbv = NULL;
4698b1d33dSMatthew Rosato aift->kzdev = NULL;
4798b1d33dSMatthew Rosato spin_unlock_irqrestore(&aift->gait_lock, flags);
4898b1d33dSMatthew Rosato
4998b1d33dSMatthew Rosato kfree(gait_kzdev);
5098b1d33dSMatthew Rosato }
5198b1d33dSMatthew Rosato
zpci_setup_aipb(u8 nisc)5298b1d33dSMatthew Rosato static int zpci_setup_aipb(u8 nisc)
5398b1d33dSMatthew Rosato {
5498b1d33dSMatthew Rosato struct page *page;
5598b1d33dSMatthew Rosato int size, rc;
5698b1d33dSMatthew Rosato
5798b1d33dSMatthew Rosato zpci_aipb = kzalloc(sizeof(union zpci_sic_iib), GFP_KERNEL);
5898b1d33dSMatthew Rosato if (!zpci_aipb)
5998b1d33dSMatthew Rosato return -ENOMEM;
6098b1d33dSMatthew Rosato
61e8c924a4SMatthew Rosato aift->sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, NULL);
6298b1d33dSMatthew Rosato if (!aift->sbv) {
6398b1d33dSMatthew Rosato rc = -ENOMEM;
6498b1d33dSMatthew Rosato goto free_aipb;
6598b1d33dSMatthew Rosato }
6698b1d33dSMatthew Rosato zpci_aif_sbv = aift->sbv;
6798b1d33dSMatthew Rosato size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
6898b1d33dSMatthew Rosato sizeof(struct zpci_gaite)));
6998b1d33dSMatthew Rosato page = alloc_pages(GFP_KERNEL | __GFP_ZERO, size);
7098b1d33dSMatthew Rosato if (!page) {
7198b1d33dSMatthew Rosato rc = -ENOMEM;
7298b1d33dSMatthew Rosato goto free_sbv;
7398b1d33dSMatthew Rosato }
7470ba8faeSMatthew Rosato aift->gait = (struct zpci_gaite *)page_to_virt(page);
7598b1d33dSMatthew Rosato
7698b1d33dSMatthew Rosato zpci_aipb->aipb.faisb = virt_to_phys(aift->sbv->vector);
7798b1d33dSMatthew Rosato zpci_aipb->aipb.gait = virt_to_phys(aift->gait);
7898b1d33dSMatthew Rosato zpci_aipb->aipb.afi = nisc;
7998b1d33dSMatthew Rosato zpci_aipb->aipb.faal = ZPCI_NR_DEVICES;
8098b1d33dSMatthew Rosato
8198b1d33dSMatthew Rosato /* Setup Adapter Event Notification Interpretation */
8298b1d33dSMatthew Rosato if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, zpci_aipb)) {
8398b1d33dSMatthew Rosato rc = -EIO;
8498b1d33dSMatthew Rosato goto free_gait;
8598b1d33dSMatthew Rosato }
8698b1d33dSMatthew Rosato
8798b1d33dSMatthew Rosato return 0;
8898b1d33dSMatthew Rosato
8998b1d33dSMatthew Rosato free_gait:
9098b1d33dSMatthew Rosato free_pages((unsigned long)aift->gait, size);
9198b1d33dSMatthew Rosato free_sbv:
9298b1d33dSMatthew Rosato airq_iv_release(aift->sbv);
9398b1d33dSMatthew Rosato zpci_aif_sbv = NULL;
9498b1d33dSMatthew Rosato free_aipb:
9598b1d33dSMatthew Rosato kfree(zpci_aipb);
9698b1d33dSMatthew Rosato zpci_aipb = NULL;
9798b1d33dSMatthew Rosato
9898b1d33dSMatthew Rosato return rc;
9998b1d33dSMatthew Rosato }
10098b1d33dSMatthew Rosato
zpci_reset_aipb(u8 nisc)10198b1d33dSMatthew Rosato static int zpci_reset_aipb(u8 nisc)
10298b1d33dSMatthew Rosato {
10398b1d33dSMatthew Rosato /*
10498b1d33dSMatthew Rosato * AEN registration can only happen once per system boot. If
10598b1d33dSMatthew Rosato * an aipb already exists then AEN was already registered and
10698b1d33dSMatthew Rosato * we can re-use the aipb contents. This can only happen if
10798b1d33dSMatthew Rosato * the KVM module was removed and re-inserted. However, we must
10898b1d33dSMatthew Rosato * ensure that the same forwarding ISC is used as this is assigned
10998b1d33dSMatthew Rosato * during KVM module load.
11098b1d33dSMatthew Rosato */
11198b1d33dSMatthew Rosato if (zpci_aipb->aipb.afi != nisc)
11298b1d33dSMatthew Rosato return -EINVAL;
11398b1d33dSMatthew Rosato
11498b1d33dSMatthew Rosato aift->sbv = zpci_aif_sbv;
115*8a46df7cSNico Boehr aift->gait = phys_to_virt(zpci_aipb->aipb.gait);
11698b1d33dSMatthew Rosato
11798b1d33dSMatthew Rosato return 0;
11898b1d33dSMatthew Rosato }
11998b1d33dSMatthew Rosato
kvm_s390_pci_aen_init(u8 nisc)12098b1d33dSMatthew Rosato int kvm_s390_pci_aen_init(u8 nisc)
12198b1d33dSMatthew Rosato {
12298b1d33dSMatthew Rosato int rc = 0;
12398b1d33dSMatthew Rosato
12498b1d33dSMatthew Rosato /* If already enabled for AEN, bail out now */
12598b1d33dSMatthew Rosato if (aift->gait || aift->sbv)
12698b1d33dSMatthew Rosato return -EPERM;
12798b1d33dSMatthew Rosato
12898b1d33dSMatthew Rosato mutex_lock(&aift->aift_lock);
129b6662e37SRafael Mendonca aift->kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev *),
13098b1d33dSMatthew Rosato GFP_KERNEL);
13198b1d33dSMatthew Rosato if (!aift->kzdev) {
13298b1d33dSMatthew Rosato rc = -ENOMEM;
13398b1d33dSMatthew Rosato goto unlock;
13498b1d33dSMatthew Rosato }
13598b1d33dSMatthew Rosato
13698b1d33dSMatthew Rosato if (!zpci_aipb)
13798b1d33dSMatthew Rosato rc = zpci_setup_aipb(nisc);
13898b1d33dSMatthew Rosato else
13998b1d33dSMatthew Rosato rc = zpci_reset_aipb(nisc);
14098b1d33dSMatthew Rosato if (rc)
14198b1d33dSMatthew Rosato goto free_zdev;
14298b1d33dSMatthew Rosato
14398b1d33dSMatthew Rosato /* Enable floating IRQs */
14498b1d33dSMatthew Rosato if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) {
14598b1d33dSMatthew Rosato rc = -EIO;
14698b1d33dSMatthew Rosato kvm_s390_pci_aen_exit();
14798b1d33dSMatthew Rosato }
14898b1d33dSMatthew Rosato
14998b1d33dSMatthew Rosato goto unlock;
15098b1d33dSMatthew Rosato
15198b1d33dSMatthew Rosato free_zdev:
15298b1d33dSMatthew Rosato kfree(aift->kzdev);
15398b1d33dSMatthew Rosato unlock:
15498b1d33dSMatthew Rosato mutex_unlock(&aift->aift_lock);
15598b1d33dSMatthew Rosato return rc;
15698b1d33dSMatthew Rosato }
15798b1d33dSMatthew Rosato
1583c5a1b6fSMatthew Rosato /* Modify PCI: Register floating adapter interruption forwarding */
kvm_zpci_set_airq(struct zpci_dev * zdev)1593c5a1b6fSMatthew Rosato static int kvm_zpci_set_airq(struct zpci_dev *zdev)
1603c5a1b6fSMatthew Rosato {
1613c5a1b6fSMatthew Rosato u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT);
1623c5a1b6fSMatthew Rosato struct zpci_fib fib = {};
1633c5a1b6fSMatthew Rosato u8 status;
1643c5a1b6fSMatthew Rosato
1653c5a1b6fSMatthew Rosato fib.fmt0.isc = zdev->kzdev->fib.fmt0.isc;
1663c5a1b6fSMatthew Rosato fib.fmt0.sum = 1; /* enable summary notifications */
1673c5a1b6fSMatthew Rosato fib.fmt0.noi = airq_iv_end(zdev->aibv);
1683c5a1b6fSMatthew Rosato fib.fmt0.aibv = virt_to_phys(zdev->aibv->vector);
1693c5a1b6fSMatthew Rosato fib.fmt0.aibvo = 0;
1703c5a1b6fSMatthew Rosato fib.fmt0.aisb = virt_to_phys(aift->sbv->vector + (zdev->aisb / 64) * 8);
1713c5a1b6fSMatthew Rosato fib.fmt0.aisbo = zdev->aisb & 63;
1723c5a1b6fSMatthew Rosato fib.gd = zdev->gisa;
1733c5a1b6fSMatthew Rosato
1743c5a1b6fSMatthew Rosato return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
1753c5a1b6fSMatthew Rosato }
1763c5a1b6fSMatthew Rosato
1773c5a1b6fSMatthew Rosato /* Modify PCI: Unregister floating adapter interruption forwarding */
kvm_zpci_clear_airq(struct zpci_dev * zdev)1783c5a1b6fSMatthew Rosato static int kvm_zpci_clear_airq(struct zpci_dev *zdev)
1793c5a1b6fSMatthew Rosato {
1803c5a1b6fSMatthew Rosato u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT);
1813c5a1b6fSMatthew Rosato struct zpci_fib fib = {};
1823c5a1b6fSMatthew Rosato u8 cc, status;
1833c5a1b6fSMatthew Rosato
1843c5a1b6fSMatthew Rosato fib.gd = zdev->gisa;
1853c5a1b6fSMatthew Rosato
1863c5a1b6fSMatthew Rosato cc = zpci_mod_fc(req, &fib, &status);
1873c5a1b6fSMatthew Rosato if (cc == 3 || (cc == 1 && status == 24))
1883c5a1b6fSMatthew Rosato /* Function already gone or IRQs already deregistered. */
1893c5a1b6fSMatthew Rosato cc = 0;
1903c5a1b6fSMatthew Rosato
1913c5a1b6fSMatthew Rosato return cc ? -EIO : 0;
1923c5a1b6fSMatthew Rosato }
1933c5a1b6fSMatthew Rosato
unaccount_mem(unsigned long nr_pages)1943c5a1b6fSMatthew Rosato static inline void unaccount_mem(unsigned long nr_pages)
1953c5a1b6fSMatthew Rosato {
1963c5a1b6fSMatthew Rosato struct user_struct *user = get_uid(current_user());
1973c5a1b6fSMatthew Rosato
1983c5a1b6fSMatthew Rosato if (user)
1993c5a1b6fSMatthew Rosato atomic_long_sub(nr_pages, &user->locked_vm);
2003c5a1b6fSMatthew Rosato if (current->mm)
2013c5a1b6fSMatthew Rosato atomic64_sub(nr_pages, ¤t->mm->pinned_vm);
2023c5a1b6fSMatthew Rosato }
2033c5a1b6fSMatthew Rosato
account_mem(unsigned long nr_pages)2043c5a1b6fSMatthew Rosato static inline int account_mem(unsigned long nr_pages)
2053c5a1b6fSMatthew Rosato {
2063c5a1b6fSMatthew Rosato struct user_struct *user = get_uid(current_user());
2073c5a1b6fSMatthew Rosato unsigned long page_limit, cur_pages, new_pages;
2083c5a1b6fSMatthew Rosato
2093c5a1b6fSMatthew Rosato page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
2103c5a1b6fSMatthew Rosato
2113c5a1b6fSMatthew Rosato do {
2123c5a1b6fSMatthew Rosato cur_pages = atomic_long_read(&user->locked_vm);
2133c5a1b6fSMatthew Rosato new_pages = cur_pages + nr_pages;
2143c5a1b6fSMatthew Rosato if (new_pages > page_limit)
2153c5a1b6fSMatthew Rosato return -ENOMEM;
2163c5a1b6fSMatthew Rosato } while (atomic_long_cmpxchg(&user->locked_vm, cur_pages,
2173c5a1b6fSMatthew Rosato new_pages) != cur_pages);
2183c5a1b6fSMatthew Rosato
2193c5a1b6fSMatthew Rosato atomic64_add(nr_pages, ¤t->mm->pinned_vm);
2203c5a1b6fSMatthew Rosato
2213c5a1b6fSMatthew Rosato return 0;
2223c5a1b6fSMatthew Rosato }
2233c5a1b6fSMatthew Rosato
kvm_s390_pci_aif_enable(struct zpci_dev * zdev,struct zpci_fib * fib,bool assist)2243c5a1b6fSMatthew Rosato static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
2253c5a1b6fSMatthew Rosato bool assist)
2263c5a1b6fSMatthew Rosato {
2273c5a1b6fSMatthew Rosato struct page *pages[1], *aibv_page, *aisb_page = NULL;
2283c5a1b6fSMatthew Rosato unsigned int msi_vecs, idx;
2293c5a1b6fSMatthew Rosato struct zpci_gaite *gaite;
2303c5a1b6fSMatthew Rosato unsigned long hva, bit;
2313c5a1b6fSMatthew Rosato struct kvm *kvm;
2323c5a1b6fSMatthew Rosato phys_addr_t gaddr;
2333c5a1b6fSMatthew Rosato int rc = 0, gisc, npages, pcount = 0;
2343c5a1b6fSMatthew Rosato
2353c5a1b6fSMatthew Rosato /*
2363c5a1b6fSMatthew Rosato * Interrupt forwarding is only applicable if the device is already
2373c5a1b6fSMatthew Rosato * enabled for interpretation
2383c5a1b6fSMatthew Rosato */
2393c5a1b6fSMatthew Rosato if (zdev->gisa == 0)
2403c5a1b6fSMatthew Rosato return -EINVAL;
2413c5a1b6fSMatthew Rosato
2423c5a1b6fSMatthew Rosato kvm = zdev->kzdev->kvm;
2433c5a1b6fSMatthew Rosato msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
2443c5a1b6fSMatthew Rosato
2453c5a1b6fSMatthew Rosato /* Get the associated forwarding ISC - if invalid, return the error */
2463c5a1b6fSMatthew Rosato gisc = kvm_s390_gisc_register(kvm, fib->fmt0.isc);
2473c5a1b6fSMatthew Rosato if (gisc < 0)
2483c5a1b6fSMatthew Rosato return gisc;
2493c5a1b6fSMatthew Rosato
2503c5a1b6fSMatthew Rosato /* Replace AIBV address */
2513c5a1b6fSMatthew Rosato idx = srcu_read_lock(&kvm->srcu);
2523c5a1b6fSMatthew Rosato hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
2533c5a1b6fSMatthew Rosato npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
2543c5a1b6fSMatthew Rosato srcu_read_unlock(&kvm->srcu, idx);
2553c5a1b6fSMatthew Rosato if (npages < 1) {
2563c5a1b6fSMatthew Rosato rc = -EIO;
2573c5a1b6fSMatthew Rosato goto out;
2583c5a1b6fSMatthew Rosato }
2593c5a1b6fSMatthew Rosato aibv_page = pages[0];
2603c5a1b6fSMatthew Rosato pcount++;
2613c5a1b6fSMatthew Rosato gaddr = page_to_phys(aibv_page) + (fib->fmt0.aibv & ~PAGE_MASK);
2623c5a1b6fSMatthew Rosato fib->fmt0.aibv = gaddr;
2633c5a1b6fSMatthew Rosato
2643c5a1b6fSMatthew Rosato /* Pin the guest AISB if one was specified */
2653c5a1b6fSMatthew Rosato if (fib->fmt0.sum == 1) {
2663c5a1b6fSMatthew Rosato idx = srcu_read_lock(&kvm->srcu);
2673c5a1b6fSMatthew Rosato hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb));
2683c5a1b6fSMatthew Rosato npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
2693c5a1b6fSMatthew Rosato pages);
2703c5a1b6fSMatthew Rosato srcu_read_unlock(&kvm->srcu, idx);
2713c5a1b6fSMatthew Rosato if (npages < 1) {
2723c5a1b6fSMatthew Rosato rc = -EIO;
2733c5a1b6fSMatthew Rosato goto unpin1;
2743c5a1b6fSMatthew Rosato }
2753c5a1b6fSMatthew Rosato aisb_page = pages[0];
2763c5a1b6fSMatthew Rosato pcount++;
2773c5a1b6fSMatthew Rosato }
2783c5a1b6fSMatthew Rosato
2793c5a1b6fSMatthew Rosato /* Account for pinned pages, roll back on failure */
2803c5a1b6fSMatthew Rosato if (account_mem(pcount))
2813c5a1b6fSMatthew Rosato goto unpin2;
2823c5a1b6fSMatthew Rosato
2833c5a1b6fSMatthew Rosato /* AISB must be allocated before we can fill in GAITE */
2843c5a1b6fSMatthew Rosato mutex_lock(&aift->aift_lock);
2853c5a1b6fSMatthew Rosato bit = airq_iv_alloc_bit(aift->sbv);
2863c5a1b6fSMatthew Rosato if (bit == -1UL)
2873c5a1b6fSMatthew Rosato goto unlock;
2883c5a1b6fSMatthew Rosato zdev->aisb = bit; /* store the summary bit number */
2893c5a1b6fSMatthew Rosato zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
2903c5a1b6fSMatthew Rosato AIRQ_IV_BITLOCK |
2913c5a1b6fSMatthew Rosato AIRQ_IV_GUESTVEC,
2923c5a1b6fSMatthew Rosato phys_to_virt(fib->fmt0.aibv));
2933c5a1b6fSMatthew Rosato
2943c5a1b6fSMatthew Rosato spin_lock_irq(&aift->gait_lock);
2953c5a1b6fSMatthew Rosato gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb *
2963c5a1b6fSMatthew Rosato sizeof(struct zpci_gaite));
2973c5a1b6fSMatthew Rosato
2983c5a1b6fSMatthew Rosato /* If assist not requested, host will get all alerts */
2993c5a1b6fSMatthew Rosato if (assist)
3003c5a1b6fSMatthew Rosato gaite->gisa = (u32)virt_to_phys(&kvm->arch.sie_page2->gisa);
3013c5a1b6fSMatthew Rosato else
3023c5a1b6fSMatthew Rosato gaite->gisa = 0;
3033c5a1b6fSMatthew Rosato
3043c5a1b6fSMatthew Rosato gaite->gisc = fib->fmt0.isc;
3053c5a1b6fSMatthew Rosato gaite->count++;
3063c5a1b6fSMatthew Rosato gaite->aisbo = fib->fmt0.aisbo;
3073c5a1b6fSMatthew Rosato gaite->aisb = virt_to_phys(page_address(aisb_page) + (fib->fmt0.aisb &
3083c5a1b6fSMatthew Rosato ~PAGE_MASK));
3093c5a1b6fSMatthew Rosato aift->kzdev[zdev->aisb] = zdev->kzdev;
3103c5a1b6fSMatthew Rosato spin_unlock_irq(&aift->gait_lock);
3113c5a1b6fSMatthew Rosato
3123c5a1b6fSMatthew Rosato /* Update guest FIB for re-issue */
3133c5a1b6fSMatthew Rosato fib->fmt0.aisbo = zdev->aisb & 63;
3143c5a1b6fSMatthew Rosato fib->fmt0.aisb = virt_to_phys(aift->sbv->vector + (zdev->aisb / 64) * 8);
3153c5a1b6fSMatthew Rosato fib->fmt0.isc = gisc;
3163c5a1b6fSMatthew Rosato
3173c5a1b6fSMatthew Rosato /* Save some guest fib values in the host for later use */
3183c5a1b6fSMatthew Rosato zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc;
3193c5a1b6fSMatthew Rosato zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv;
3203c5a1b6fSMatthew Rosato mutex_unlock(&aift->aift_lock);
3213c5a1b6fSMatthew Rosato
3223c5a1b6fSMatthew Rosato /* Issue the clp to setup the irq now */
3233c5a1b6fSMatthew Rosato rc = kvm_zpci_set_airq(zdev);
3243c5a1b6fSMatthew Rosato return rc;
3253c5a1b6fSMatthew Rosato
3263c5a1b6fSMatthew Rosato unlock:
3273c5a1b6fSMatthew Rosato mutex_unlock(&aift->aift_lock);
3283c5a1b6fSMatthew Rosato unpin2:
3293c5a1b6fSMatthew Rosato if (fib->fmt0.sum == 1)
3303c5a1b6fSMatthew Rosato unpin_user_page(aisb_page);
3313c5a1b6fSMatthew Rosato unpin1:
3323c5a1b6fSMatthew Rosato unpin_user_page(aibv_page);
3333c5a1b6fSMatthew Rosato out:
3343c5a1b6fSMatthew Rosato return rc;
3353c5a1b6fSMatthew Rosato }
3363c5a1b6fSMatthew Rosato
kvm_s390_pci_aif_disable(struct zpci_dev * zdev,bool force)3373c5a1b6fSMatthew Rosato static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force)
3383c5a1b6fSMatthew Rosato {
3393c5a1b6fSMatthew Rosato struct kvm_zdev *kzdev = zdev->kzdev;
3403c5a1b6fSMatthew Rosato struct zpci_gaite *gaite;
3413c5a1b6fSMatthew Rosato struct page *vpage = NULL, *spage = NULL;
3423c5a1b6fSMatthew Rosato int rc, pcount = 0;
3433c5a1b6fSMatthew Rosato u8 isc;
3443c5a1b6fSMatthew Rosato
3453c5a1b6fSMatthew Rosato if (zdev->gisa == 0)
3463c5a1b6fSMatthew Rosato return -EINVAL;
3473c5a1b6fSMatthew Rosato
3483c5a1b6fSMatthew Rosato mutex_lock(&aift->aift_lock);
3493c5a1b6fSMatthew Rosato
3503c5a1b6fSMatthew Rosato /*
3513c5a1b6fSMatthew Rosato * If the clear fails due to an error, leave now unless we know this
3523c5a1b6fSMatthew Rosato * device is about to go away (force) -- In that case clear the GAITE
3533c5a1b6fSMatthew Rosato * regardless.
3543c5a1b6fSMatthew Rosato */
3553c5a1b6fSMatthew Rosato rc = kvm_zpci_clear_airq(zdev);
3563c5a1b6fSMatthew Rosato if (rc && !force)
3573c5a1b6fSMatthew Rosato goto out;
3583c5a1b6fSMatthew Rosato
3593c5a1b6fSMatthew Rosato if (zdev->kzdev->fib.fmt0.aibv == 0)
3603c5a1b6fSMatthew Rosato goto out;
3613c5a1b6fSMatthew Rosato spin_lock_irq(&aift->gait_lock);
3623c5a1b6fSMatthew Rosato gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb *
3633c5a1b6fSMatthew Rosato sizeof(struct zpci_gaite));
3643c5a1b6fSMatthew Rosato isc = gaite->gisc;
3653c5a1b6fSMatthew Rosato gaite->count--;
3663c5a1b6fSMatthew Rosato if (gaite->count == 0) {
3673c5a1b6fSMatthew Rosato /* Release guest AIBV and AISB */
3683c5a1b6fSMatthew Rosato vpage = phys_to_page(kzdev->fib.fmt0.aibv);
3693c5a1b6fSMatthew Rosato if (gaite->aisb != 0)
3703c5a1b6fSMatthew Rosato spage = phys_to_page(gaite->aisb);
3713c5a1b6fSMatthew Rosato /* Clear the GAIT entry */
3723c5a1b6fSMatthew Rosato gaite->aisb = 0;
3733c5a1b6fSMatthew Rosato gaite->gisc = 0;
3743c5a1b6fSMatthew Rosato gaite->aisbo = 0;
3753c5a1b6fSMatthew Rosato gaite->gisa = 0;
376e8c924a4SMatthew Rosato aift->kzdev[zdev->aisb] = NULL;
3773c5a1b6fSMatthew Rosato /* Clear zdev info */
3783c5a1b6fSMatthew Rosato airq_iv_free_bit(aift->sbv, zdev->aisb);
3793c5a1b6fSMatthew Rosato airq_iv_release(zdev->aibv);
3803c5a1b6fSMatthew Rosato zdev->aisb = 0;
3813c5a1b6fSMatthew Rosato zdev->aibv = NULL;
3823c5a1b6fSMatthew Rosato }
3833c5a1b6fSMatthew Rosato spin_unlock_irq(&aift->gait_lock);
3843c5a1b6fSMatthew Rosato kvm_s390_gisc_unregister(kzdev->kvm, isc);
3853c5a1b6fSMatthew Rosato kzdev->fib.fmt0.isc = 0;
3863c5a1b6fSMatthew Rosato kzdev->fib.fmt0.aibv = 0;
3873c5a1b6fSMatthew Rosato
3883c5a1b6fSMatthew Rosato if (vpage) {
3893c5a1b6fSMatthew Rosato unpin_user_page(vpage);
3903c5a1b6fSMatthew Rosato pcount++;
3913c5a1b6fSMatthew Rosato }
3923c5a1b6fSMatthew Rosato if (spage) {
3933c5a1b6fSMatthew Rosato unpin_user_page(spage);
3943c5a1b6fSMatthew Rosato pcount++;
3953c5a1b6fSMatthew Rosato }
3963c5a1b6fSMatthew Rosato if (pcount > 0)
3973c5a1b6fSMatthew Rosato unaccount_mem(pcount);
3983c5a1b6fSMatthew Rosato out:
3993c5a1b6fSMatthew Rosato mutex_unlock(&aift->aift_lock);
4003c5a1b6fSMatthew Rosato
4013c5a1b6fSMatthew Rosato return rc;
4023c5a1b6fSMatthew Rosato }
4033c5a1b6fSMatthew Rosato
kvm_s390_pci_dev_open(struct zpci_dev * zdev)4046438e307SMatthew Rosato static int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
4056438e307SMatthew Rosato {
4066438e307SMatthew Rosato struct kvm_zdev *kzdev;
4076438e307SMatthew Rosato
4086438e307SMatthew Rosato kzdev = kzalloc(sizeof(struct kvm_zdev), GFP_KERNEL);
4096438e307SMatthew Rosato if (!kzdev)
4106438e307SMatthew Rosato return -ENOMEM;
4116438e307SMatthew Rosato
4126438e307SMatthew Rosato kzdev->zdev = zdev;
4136438e307SMatthew Rosato zdev->kzdev = kzdev;
4146438e307SMatthew Rosato
4156438e307SMatthew Rosato return 0;
4166438e307SMatthew Rosato }
4176438e307SMatthew Rosato
kvm_s390_pci_dev_release(struct zpci_dev * zdev)4186438e307SMatthew Rosato static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
4196438e307SMatthew Rosato {
4206438e307SMatthew Rosato struct kvm_zdev *kzdev;
4216438e307SMatthew Rosato
4226438e307SMatthew Rosato kzdev = zdev->kzdev;
4236438e307SMatthew Rosato WARN_ON(kzdev->zdev != zdev);
4246438e307SMatthew Rosato zdev->kzdev = NULL;
4256438e307SMatthew Rosato kfree(kzdev);
4266438e307SMatthew Rosato }
42798b1d33dSMatthew Rosato
42809340b2fSMatthew Rosato
42909340b2fSMatthew Rosato /*
43009340b2fSMatthew Rosato * Register device with the specified KVM. If interpretation facilities are
43109340b2fSMatthew Rosato * available, enable them and let userspace indicate whether or not they will
43209340b2fSMatthew Rosato * be used (specify SHM bit to disable).
43309340b2fSMatthew Rosato */
kvm_s390_pci_register_kvm(void * opaque,struct kvm * kvm)434ca922fecSPierre Morel static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
43509340b2fSMatthew Rosato {
436ca922fecSPierre Morel struct zpci_dev *zdev = opaque;
43759bbf596SNiklas Schnelle u8 status;
43809340b2fSMatthew Rosato int rc;
43909340b2fSMatthew Rosato
44009340b2fSMatthew Rosato if (!zdev)
44109340b2fSMatthew Rosato return -EINVAL;
44209340b2fSMatthew Rosato
44309340b2fSMatthew Rosato mutex_lock(&zdev->kzdev_lock);
44409340b2fSMatthew Rosato
44509340b2fSMatthew Rosato if (zdev->kzdev || zdev->gisa != 0 || !kvm) {
44609340b2fSMatthew Rosato mutex_unlock(&zdev->kzdev_lock);
44709340b2fSMatthew Rosato return -EINVAL;
44809340b2fSMatthew Rosato }
44909340b2fSMatthew Rosato
45009340b2fSMatthew Rosato kvm_get_kvm(kvm);
45109340b2fSMatthew Rosato
45209340b2fSMatthew Rosato mutex_lock(&kvm->lock);
45309340b2fSMatthew Rosato
45409340b2fSMatthew Rosato rc = kvm_s390_pci_dev_open(zdev);
45509340b2fSMatthew Rosato if (rc)
45609340b2fSMatthew Rosato goto err;
45709340b2fSMatthew Rosato
45809340b2fSMatthew Rosato /*
45909340b2fSMatthew Rosato * If interpretation facilities aren't available, add the device to
46009340b2fSMatthew Rosato * the kzdev list but don't enable for interpretation.
46109340b2fSMatthew Rosato */
46209340b2fSMatthew Rosato if (!kvm_s390_pci_interp_allowed())
46309340b2fSMatthew Rosato goto out;
46409340b2fSMatthew Rosato
46509340b2fSMatthew Rosato /*
46609340b2fSMatthew Rosato * If this is the first request to use an interpreted device, make the
46709340b2fSMatthew Rosato * necessary vcpu changes
46809340b2fSMatthew Rosato */
46909340b2fSMatthew Rosato if (!kvm->arch.use_zpci_interp)
47009340b2fSMatthew Rosato kvm_s390_vcpu_pci_enable_interp(kvm);
47109340b2fSMatthew Rosato
47209340b2fSMatthew Rosato if (zdev_enabled(zdev)) {
47309340b2fSMatthew Rosato rc = zpci_disable_device(zdev);
47409340b2fSMatthew Rosato if (rc)
47509340b2fSMatthew Rosato goto err;
47609340b2fSMatthew Rosato }
47709340b2fSMatthew Rosato
47809340b2fSMatthew Rosato /*
47909340b2fSMatthew Rosato * Store information about the identity of the kvm guest allowed to
48009340b2fSMatthew Rosato * access this device via interpretation to be used by host CLP
48109340b2fSMatthew Rosato */
48209340b2fSMatthew Rosato zdev->gisa = (u32)virt_to_phys(&kvm->arch.sie_page2->gisa);
48309340b2fSMatthew Rosato
48409340b2fSMatthew Rosato rc = zpci_enable_device(zdev);
48509340b2fSMatthew Rosato if (rc)
48609340b2fSMatthew Rosato goto clear_gisa;
48709340b2fSMatthew Rosato
48809340b2fSMatthew Rosato /* Re-register the IOMMU that was already created */
48909340b2fSMatthew Rosato rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
49059bbf596SNiklas Schnelle virt_to_phys(zdev->dma_table), &status);
49109340b2fSMatthew Rosato if (rc)
49209340b2fSMatthew Rosato goto clear_gisa;
49309340b2fSMatthew Rosato
49409340b2fSMatthew Rosato out:
49509340b2fSMatthew Rosato zdev->kzdev->kvm = kvm;
49609340b2fSMatthew Rosato
49709340b2fSMatthew Rosato spin_lock(&kvm->arch.kzdev_list_lock);
49809340b2fSMatthew Rosato list_add_tail(&zdev->kzdev->entry, &kvm->arch.kzdev_list);
49909340b2fSMatthew Rosato spin_unlock(&kvm->arch.kzdev_list_lock);
50009340b2fSMatthew Rosato
50109340b2fSMatthew Rosato mutex_unlock(&kvm->lock);
50209340b2fSMatthew Rosato mutex_unlock(&zdev->kzdev_lock);
50309340b2fSMatthew Rosato return 0;
50409340b2fSMatthew Rosato
50509340b2fSMatthew Rosato clear_gisa:
50609340b2fSMatthew Rosato zdev->gisa = 0;
50709340b2fSMatthew Rosato err:
50809340b2fSMatthew Rosato if (zdev->kzdev)
50909340b2fSMatthew Rosato kvm_s390_pci_dev_release(zdev);
51009340b2fSMatthew Rosato mutex_unlock(&kvm->lock);
51109340b2fSMatthew Rosato mutex_unlock(&zdev->kzdev_lock);
51209340b2fSMatthew Rosato kvm_put_kvm(kvm);
51309340b2fSMatthew Rosato return rc;
51409340b2fSMatthew Rosato }
51509340b2fSMatthew Rosato
kvm_s390_pci_unregister_kvm(void * opaque)516ca922fecSPierre Morel static void kvm_s390_pci_unregister_kvm(void *opaque)
51709340b2fSMatthew Rosato {
518ca922fecSPierre Morel struct zpci_dev *zdev = opaque;
51909340b2fSMatthew Rosato struct kvm *kvm;
52059bbf596SNiklas Schnelle u8 status;
52109340b2fSMatthew Rosato
52209340b2fSMatthew Rosato if (!zdev)
52309340b2fSMatthew Rosato return;
52409340b2fSMatthew Rosato
52509340b2fSMatthew Rosato mutex_lock(&zdev->kzdev_lock);
52609340b2fSMatthew Rosato
52709340b2fSMatthew Rosato if (WARN_ON(!zdev->kzdev)) {
52809340b2fSMatthew Rosato mutex_unlock(&zdev->kzdev_lock);
52909340b2fSMatthew Rosato return;
53009340b2fSMatthew Rosato }
53109340b2fSMatthew Rosato
53209340b2fSMatthew Rosato kvm = zdev->kzdev->kvm;
53309340b2fSMatthew Rosato mutex_lock(&kvm->lock);
53409340b2fSMatthew Rosato
53509340b2fSMatthew Rosato /*
53609340b2fSMatthew Rosato * A 0 gisa means interpretation was never enabled, just remove the
53709340b2fSMatthew Rosato * device from the list.
53809340b2fSMatthew Rosato */
53909340b2fSMatthew Rosato if (zdev->gisa == 0)
54009340b2fSMatthew Rosato goto out;
54109340b2fSMatthew Rosato
54209340b2fSMatthew Rosato /* Forwarding must be turned off before interpretation */
54309340b2fSMatthew Rosato if (zdev->kzdev->fib.fmt0.aibv != 0)
54409340b2fSMatthew Rosato kvm_s390_pci_aif_disable(zdev, true);
54509340b2fSMatthew Rosato
54609340b2fSMatthew Rosato /* Remove the host CLP guest designation */
54709340b2fSMatthew Rosato zdev->gisa = 0;
54809340b2fSMatthew Rosato
54909340b2fSMatthew Rosato if (zdev_enabled(zdev)) {
55009340b2fSMatthew Rosato if (zpci_disable_device(zdev))
55109340b2fSMatthew Rosato goto out;
55209340b2fSMatthew Rosato }
55309340b2fSMatthew Rosato
55409340b2fSMatthew Rosato if (zpci_enable_device(zdev))
55509340b2fSMatthew Rosato goto out;
55609340b2fSMatthew Rosato
55709340b2fSMatthew Rosato /* Re-register the IOMMU that was already created */
55809340b2fSMatthew Rosato zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
55959bbf596SNiklas Schnelle virt_to_phys(zdev->dma_table), &status);
56009340b2fSMatthew Rosato
56109340b2fSMatthew Rosato out:
56209340b2fSMatthew Rosato spin_lock(&kvm->arch.kzdev_list_lock);
56309340b2fSMatthew Rosato list_del(&zdev->kzdev->entry);
56409340b2fSMatthew Rosato spin_unlock(&kvm->arch.kzdev_list_lock);
56509340b2fSMatthew Rosato kvm_s390_pci_dev_release(zdev);
56609340b2fSMatthew Rosato
56709340b2fSMatthew Rosato mutex_unlock(&kvm->lock);
56809340b2fSMatthew Rosato mutex_unlock(&zdev->kzdev_lock);
56909340b2fSMatthew Rosato
57009340b2fSMatthew Rosato kvm_put_kvm(kvm);
57109340b2fSMatthew Rosato }
57209340b2fSMatthew Rosato
kvm_s390_pci_init_list(struct kvm * kvm)57309340b2fSMatthew Rosato void kvm_s390_pci_init_list(struct kvm *kvm)
57409340b2fSMatthew Rosato {
57509340b2fSMatthew Rosato spin_lock_init(&kvm->arch.kzdev_list_lock);
57609340b2fSMatthew Rosato INIT_LIST_HEAD(&kvm->arch.kzdev_list);
57709340b2fSMatthew Rosato }
57809340b2fSMatthew Rosato
kvm_s390_pci_clear_list(struct kvm * kvm)57909340b2fSMatthew Rosato void kvm_s390_pci_clear_list(struct kvm *kvm)
58009340b2fSMatthew Rosato {
58109340b2fSMatthew Rosato /*
58209340b2fSMatthew Rosato * This list should already be empty, either via vfio device closures
58309340b2fSMatthew Rosato * or kvm fd cleanup.
58409340b2fSMatthew Rosato */
58509340b2fSMatthew Rosato spin_lock(&kvm->arch.kzdev_list_lock);
58609340b2fSMatthew Rosato WARN_ON_ONCE(!list_empty(&kvm->arch.kzdev_list));
58709340b2fSMatthew Rosato spin_unlock(&kvm->arch.kzdev_list_lock);
58809340b2fSMatthew Rosato }
58909340b2fSMatthew Rosato
get_zdev_from_kvm_by_fh(struct kvm * kvm,u32 fh)590db1c875eSMatthew Rosato static struct zpci_dev *get_zdev_from_kvm_by_fh(struct kvm *kvm, u32 fh)
591db1c875eSMatthew Rosato {
592db1c875eSMatthew Rosato struct zpci_dev *zdev = NULL;
593db1c875eSMatthew Rosato struct kvm_zdev *kzdev;
594db1c875eSMatthew Rosato
595db1c875eSMatthew Rosato spin_lock(&kvm->arch.kzdev_list_lock);
596db1c875eSMatthew Rosato list_for_each_entry(kzdev, &kvm->arch.kzdev_list, entry) {
597db1c875eSMatthew Rosato if (kzdev->zdev->fh == fh) {
598db1c875eSMatthew Rosato zdev = kzdev->zdev;
599db1c875eSMatthew Rosato break;
600db1c875eSMatthew Rosato }
601db1c875eSMatthew Rosato }
602db1c875eSMatthew Rosato spin_unlock(&kvm->arch.kzdev_list_lock);
603db1c875eSMatthew Rosato
604db1c875eSMatthew Rosato return zdev;
605db1c875eSMatthew Rosato }
606db1c875eSMatthew Rosato
kvm_s390_pci_zpci_reg_aen(struct zpci_dev * zdev,struct kvm_s390_zpci_op * args)607db1c875eSMatthew Rosato static int kvm_s390_pci_zpci_reg_aen(struct zpci_dev *zdev,
608db1c875eSMatthew Rosato struct kvm_s390_zpci_op *args)
609db1c875eSMatthew Rosato {
610db1c875eSMatthew Rosato struct zpci_fib fib = {};
611db1c875eSMatthew Rosato bool hostflag;
612db1c875eSMatthew Rosato
613db1c875eSMatthew Rosato fib.fmt0.aibv = args->u.reg_aen.ibv;
614db1c875eSMatthew Rosato fib.fmt0.isc = args->u.reg_aen.isc;
615db1c875eSMatthew Rosato fib.fmt0.noi = args->u.reg_aen.noi;
616db1c875eSMatthew Rosato if (args->u.reg_aen.sb != 0) {
617db1c875eSMatthew Rosato fib.fmt0.aisb = args->u.reg_aen.sb;
618db1c875eSMatthew Rosato fib.fmt0.aisbo = args->u.reg_aen.sbo;
619db1c875eSMatthew Rosato fib.fmt0.sum = 1;
620db1c875eSMatthew Rosato } else {
621db1c875eSMatthew Rosato fib.fmt0.aisb = 0;
622db1c875eSMatthew Rosato fib.fmt0.aisbo = 0;
623db1c875eSMatthew Rosato fib.fmt0.sum = 0;
624db1c875eSMatthew Rosato }
625db1c875eSMatthew Rosato
626db1c875eSMatthew Rosato hostflag = !(args->u.reg_aen.flags & KVM_S390_ZPCIOP_REGAEN_HOST);
627db1c875eSMatthew Rosato return kvm_s390_pci_aif_enable(zdev, &fib, hostflag);
628db1c875eSMatthew Rosato }
629db1c875eSMatthew Rosato
kvm_s390_pci_zpci_op(struct kvm * kvm,struct kvm_s390_zpci_op * args)630db1c875eSMatthew Rosato int kvm_s390_pci_zpci_op(struct kvm *kvm, struct kvm_s390_zpci_op *args)
631db1c875eSMatthew Rosato {
632db1c875eSMatthew Rosato struct kvm_zdev *kzdev;
633db1c875eSMatthew Rosato struct zpci_dev *zdev;
634db1c875eSMatthew Rosato int r;
635db1c875eSMatthew Rosato
636db1c875eSMatthew Rosato zdev = get_zdev_from_kvm_by_fh(kvm, args->fh);
637db1c875eSMatthew Rosato if (!zdev)
638db1c875eSMatthew Rosato return -ENODEV;
639db1c875eSMatthew Rosato
640db1c875eSMatthew Rosato mutex_lock(&zdev->kzdev_lock);
641db1c875eSMatthew Rosato mutex_lock(&kvm->lock);
642db1c875eSMatthew Rosato
643db1c875eSMatthew Rosato kzdev = zdev->kzdev;
644db1c875eSMatthew Rosato if (!kzdev) {
645db1c875eSMatthew Rosato r = -ENODEV;
646db1c875eSMatthew Rosato goto out;
647db1c875eSMatthew Rosato }
648db1c875eSMatthew Rosato if (kzdev->kvm != kvm) {
649db1c875eSMatthew Rosato r = -EPERM;
650db1c875eSMatthew Rosato goto out;
651db1c875eSMatthew Rosato }
652db1c875eSMatthew Rosato
653db1c875eSMatthew Rosato switch (args->op) {
654db1c875eSMatthew Rosato case KVM_S390_ZPCIOP_REG_AEN:
655db1c875eSMatthew Rosato /* Fail on unknown flags */
656db1c875eSMatthew Rosato if (args->u.reg_aen.flags & ~KVM_S390_ZPCIOP_REGAEN_HOST) {
657db1c875eSMatthew Rosato r = -EINVAL;
658db1c875eSMatthew Rosato break;
659db1c875eSMatthew Rosato }
660db1c875eSMatthew Rosato r = kvm_s390_pci_zpci_reg_aen(zdev, args);
661db1c875eSMatthew Rosato break;
662db1c875eSMatthew Rosato case KVM_S390_ZPCIOP_DEREG_AEN:
663db1c875eSMatthew Rosato r = kvm_s390_pci_aif_disable(zdev, false);
664db1c875eSMatthew Rosato break;
665db1c875eSMatthew Rosato default:
666db1c875eSMatthew Rosato r = -EINVAL;
667db1c875eSMatthew Rosato }
668db1c875eSMatthew Rosato
669db1c875eSMatthew Rosato out:
670db1c875eSMatthew Rosato mutex_unlock(&kvm->lock);
671db1c875eSMatthew Rosato mutex_unlock(&zdev->kzdev_lock);
672db1c875eSMatthew Rosato return r;
673db1c875eSMatthew Rosato }
674db1c875eSMatthew Rosato
kvm_s390_pci_init(void)6756c30cd2eSSean Christopherson int __init kvm_s390_pci_init(void)
67698b1d33dSMatthew Rosato {
677189e7d87SMatthew Rosato zpci_kvm_hook.kvm_register = kvm_s390_pci_register_kvm;
678189e7d87SMatthew Rosato zpci_kvm_hook.kvm_unregister = kvm_s390_pci_unregister_kvm;
679189e7d87SMatthew Rosato
680189e7d87SMatthew Rosato if (!kvm_s390_pci_interp_allowed())
681189e7d87SMatthew Rosato return 0;
682189e7d87SMatthew Rosato
68398b1d33dSMatthew Rosato aift = kzalloc(sizeof(struct zpci_aift), GFP_KERNEL);
68498b1d33dSMatthew Rosato if (!aift)
68598b1d33dSMatthew Rosato return -ENOMEM;
68698b1d33dSMatthew Rosato
68798b1d33dSMatthew Rosato spin_lock_init(&aift->gait_lock);
68898b1d33dSMatthew Rosato mutex_init(&aift->aift_lock);
68998b1d33dSMatthew Rosato
69098b1d33dSMatthew Rosato return 0;
69198b1d33dSMatthew Rosato }
69298b1d33dSMatthew Rosato
kvm_s390_pci_exit(void)69398b1d33dSMatthew Rosato void kvm_s390_pci_exit(void)
69498b1d33dSMatthew Rosato {
695ca922fecSPierre Morel zpci_kvm_hook.kvm_register = NULL;
696ca922fecSPierre Morel zpci_kvm_hook.kvm_unregister = NULL;
69798b1d33dSMatthew Rosato
698189e7d87SMatthew Rosato if (!kvm_s390_pci_interp_allowed())
699189e7d87SMatthew Rosato return;
700189e7d87SMatthew Rosato
701189e7d87SMatthew Rosato mutex_destroy(&aift->aift_lock);
702189e7d87SMatthew Rosato
70398b1d33dSMatthew Rosato kfree(aift);
70498b1d33dSMatthew Rosato }
705