xref: /openbmc/linux/arch/s390/kvm/pci.c (revision 98b1d33dac5fd09060486762c02fd1a78baeb1e0)
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>
12*98b1d33dSMatthew Rosato #include <asm/pci.h>
13*98b1d33dSMatthew Rosato #include <asm/pci_insn.h>
146438e307SMatthew Rosato #include "pci.h"
156438e307SMatthew Rosato 
16*98b1d33dSMatthew Rosato struct zpci_aift *aift;
17*98b1d33dSMatthew Rosato 
18*98b1d33dSMatthew Rosato static inline int __set_irq_noiib(u16 ctl, u8 isc)
19*98b1d33dSMatthew Rosato {
20*98b1d33dSMatthew Rosato 	union zpci_sic_iib iib = {{0}};
21*98b1d33dSMatthew Rosato 
22*98b1d33dSMatthew Rosato 	return zpci_set_irq_ctrl(ctl, isc, &iib);
23*98b1d33dSMatthew Rosato }
24*98b1d33dSMatthew Rosato 
25*98b1d33dSMatthew Rosato void kvm_s390_pci_aen_exit(void)
26*98b1d33dSMatthew Rosato {
27*98b1d33dSMatthew Rosato 	unsigned long flags;
28*98b1d33dSMatthew Rosato 	struct kvm_zdev **gait_kzdev;
29*98b1d33dSMatthew Rosato 
30*98b1d33dSMatthew Rosato 	lockdep_assert_held(&aift->aift_lock);
31*98b1d33dSMatthew Rosato 
32*98b1d33dSMatthew Rosato 	/*
33*98b1d33dSMatthew Rosato 	 * Contents of the aipb remain registered for the life of the host
34*98b1d33dSMatthew Rosato 	 * kernel, the information preserved in zpci_aipb and zpci_aif_sbv
35*98b1d33dSMatthew Rosato 	 * in case we insert the KVM module again later.  Clear the AIFT
36*98b1d33dSMatthew Rosato 	 * information and free anything not registered with underlying
37*98b1d33dSMatthew Rosato 	 * firmware.
38*98b1d33dSMatthew Rosato 	 */
39*98b1d33dSMatthew Rosato 	spin_lock_irqsave(&aift->gait_lock, flags);
40*98b1d33dSMatthew Rosato 	gait_kzdev = aift->kzdev;
41*98b1d33dSMatthew Rosato 	aift->gait = NULL;
42*98b1d33dSMatthew Rosato 	aift->sbv = NULL;
43*98b1d33dSMatthew Rosato 	aift->kzdev = NULL;
44*98b1d33dSMatthew Rosato 	spin_unlock_irqrestore(&aift->gait_lock, flags);
45*98b1d33dSMatthew Rosato 
46*98b1d33dSMatthew Rosato 	kfree(gait_kzdev);
47*98b1d33dSMatthew Rosato }
48*98b1d33dSMatthew Rosato 
49*98b1d33dSMatthew Rosato static int zpci_setup_aipb(u8 nisc)
50*98b1d33dSMatthew Rosato {
51*98b1d33dSMatthew Rosato 	struct page *page;
52*98b1d33dSMatthew Rosato 	int size, rc;
53*98b1d33dSMatthew Rosato 
54*98b1d33dSMatthew Rosato 	zpci_aipb = kzalloc(sizeof(union zpci_sic_iib), GFP_KERNEL);
55*98b1d33dSMatthew Rosato 	if (!zpci_aipb)
56*98b1d33dSMatthew Rosato 		return -ENOMEM;
57*98b1d33dSMatthew Rosato 
58*98b1d33dSMatthew Rosato 	aift->sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, 0);
59*98b1d33dSMatthew Rosato 	if (!aift->sbv) {
60*98b1d33dSMatthew Rosato 		rc = -ENOMEM;
61*98b1d33dSMatthew Rosato 		goto free_aipb;
62*98b1d33dSMatthew Rosato 	}
63*98b1d33dSMatthew Rosato 	zpci_aif_sbv = aift->sbv;
64*98b1d33dSMatthew Rosato 	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
65*98b1d33dSMatthew Rosato 						sizeof(struct zpci_gaite)));
66*98b1d33dSMatthew Rosato 	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, size);
67*98b1d33dSMatthew Rosato 	if (!page) {
68*98b1d33dSMatthew Rosato 		rc = -ENOMEM;
69*98b1d33dSMatthew Rosato 		goto free_sbv;
70*98b1d33dSMatthew Rosato 	}
71*98b1d33dSMatthew Rosato 	aift->gait = (struct zpci_gaite *)page_to_phys(page);
72*98b1d33dSMatthew Rosato 
73*98b1d33dSMatthew Rosato 	zpci_aipb->aipb.faisb = virt_to_phys(aift->sbv->vector);
74*98b1d33dSMatthew Rosato 	zpci_aipb->aipb.gait = virt_to_phys(aift->gait);
75*98b1d33dSMatthew Rosato 	zpci_aipb->aipb.afi = nisc;
76*98b1d33dSMatthew Rosato 	zpci_aipb->aipb.faal = ZPCI_NR_DEVICES;
77*98b1d33dSMatthew Rosato 
78*98b1d33dSMatthew Rosato 	/* Setup Adapter Event Notification Interpretation */
79*98b1d33dSMatthew Rosato 	if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, zpci_aipb)) {
80*98b1d33dSMatthew Rosato 		rc = -EIO;
81*98b1d33dSMatthew Rosato 		goto free_gait;
82*98b1d33dSMatthew Rosato 	}
83*98b1d33dSMatthew Rosato 
84*98b1d33dSMatthew Rosato 	return 0;
85*98b1d33dSMatthew Rosato 
86*98b1d33dSMatthew Rosato free_gait:
87*98b1d33dSMatthew Rosato 	free_pages((unsigned long)aift->gait, size);
88*98b1d33dSMatthew Rosato free_sbv:
89*98b1d33dSMatthew Rosato 	airq_iv_release(aift->sbv);
90*98b1d33dSMatthew Rosato 	zpci_aif_sbv = NULL;
91*98b1d33dSMatthew Rosato free_aipb:
92*98b1d33dSMatthew Rosato 	kfree(zpci_aipb);
93*98b1d33dSMatthew Rosato 	zpci_aipb = NULL;
94*98b1d33dSMatthew Rosato 
95*98b1d33dSMatthew Rosato 	return rc;
96*98b1d33dSMatthew Rosato }
97*98b1d33dSMatthew Rosato 
98*98b1d33dSMatthew Rosato static int zpci_reset_aipb(u8 nisc)
99*98b1d33dSMatthew Rosato {
100*98b1d33dSMatthew Rosato 	/*
101*98b1d33dSMatthew Rosato 	 * AEN registration can only happen once per system boot.  If
102*98b1d33dSMatthew Rosato 	 * an aipb already exists then AEN was already registered and
103*98b1d33dSMatthew Rosato 	 * we can re-use the aipb contents.  This can only happen if
104*98b1d33dSMatthew Rosato 	 * the KVM module was removed and re-inserted.  However, we must
105*98b1d33dSMatthew Rosato 	 * ensure that the same forwarding ISC is used as this is assigned
106*98b1d33dSMatthew Rosato 	 * during KVM module load.
107*98b1d33dSMatthew Rosato 	 */
108*98b1d33dSMatthew Rosato 	if (zpci_aipb->aipb.afi != nisc)
109*98b1d33dSMatthew Rosato 		return -EINVAL;
110*98b1d33dSMatthew Rosato 
111*98b1d33dSMatthew Rosato 	aift->sbv = zpci_aif_sbv;
112*98b1d33dSMatthew Rosato 	aift->gait = (struct zpci_gaite *)zpci_aipb->aipb.gait;
113*98b1d33dSMatthew Rosato 
114*98b1d33dSMatthew Rosato 	return 0;
115*98b1d33dSMatthew Rosato }
116*98b1d33dSMatthew Rosato 
117*98b1d33dSMatthew Rosato int kvm_s390_pci_aen_init(u8 nisc)
118*98b1d33dSMatthew Rosato {
119*98b1d33dSMatthew Rosato 	int rc = 0;
120*98b1d33dSMatthew Rosato 
121*98b1d33dSMatthew Rosato 	/* If already enabled for AEN, bail out now */
122*98b1d33dSMatthew Rosato 	if (aift->gait || aift->sbv)
123*98b1d33dSMatthew Rosato 		return -EPERM;
124*98b1d33dSMatthew Rosato 
125*98b1d33dSMatthew Rosato 	mutex_lock(&aift->aift_lock);
126*98b1d33dSMatthew Rosato 	aift->kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev),
127*98b1d33dSMatthew Rosato 			      GFP_KERNEL);
128*98b1d33dSMatthew Rosato 	if (!aift->kzdev) {
129*98b1d33dSMatthew Rosato 		rc = -ENOMEM;
130*98b1d33dSMatthew Rosato 		goto unlock;
131*98b1d33dSMatthew Rosato 	}
132*98b1d33dSMatthew Rosato 
133*98b1d33dSMatthew Rosato 	if (!zpci_aipb)
134*98b1d33dSMatthew Rosato 		rc = zpci_setup_aipb(nisc);
135*98b1d33dSMatthew Rosato 	else
136*98b1d33dSMatthew Rosato 		rc = zpci_reset_aipb(nisc);
137*98b1d33dSMatthew Rosato 	if (rc)
138*98b1d33dSMatthew Rosato 		goto free_zdev;
139*98b1d33dSMatthew Rosato 
140*98b1d33dSMatthew Rosato 	/* Enable floating IRQs */
141*98b1d33dSMatthew Rosato 	if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) {
142*98b1d33dSMatthew Rosato 		rc = -EIO;
143*98b1d33dSMatthew Rosato 		kvm_s390_pci_aen_exit();
144*98b1d33dSMatthew Rosato 	}
145*98b1d33dSMatthew Rosato 
146*98b1d33dSMatthew Rosato 	goto unlock;
147*98b1d33dSMatthew Rosato 
148*98b1d33dSMatthew Rosato free_zdev:
149*98b1d33dSMatthew Rosato 	kfree(aift->kzdev);
150*98b1d33dSMatthew Rosato unlock:
151*98b1d33dSMatthew Rosato 	mutex_unlock(&aift->aift_lock);
152*98b1d33dSMatthew Rosato 	return rc;
153*98b1d33dSMatthew Rosato }
154*98b1d33dSMatthew Rosato 
1556438e307SMatthew Rosato static int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
1566438e307SMatthew Rosato {
1576438e307SMatthew Rosato 	struct kvm_zdev *kzdev;
1586438e307SMatthew Rosato 
1596438e307SMatthew Rosato 	kzdev = kzalloc(sizeof(struct kvm_zdev), GFP_KERNEL);
1606438e307SMatthew Rosato 	if (!kzdev)
1616438e307SMatthew Rosato 		return -ENOMEM;
1626438e307SMatthew Rosato 
1636438e307SMatthew Rosato 	kzdev->zdev = zdev;
1646438e307SMatthew Rosato 	zdev->kzdev = kzdev;
1656438e307SMatthew Rosato 
1666438e307SMatthew Rosato 	return 0;
1676438e307SMatthew Rosato }
1686438e307SMatthew Rosato 
1696438e307SMatthew Rosato static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
1706438e307SMatthew Rosato {
1716438e307SMatthew Rosato 	struct kvm_zdev *kzdev;
1726438e307SMatthew Rosato 
1736438e307SMatthew Rosato 	kzdev = zdev->kzdev;
1746438e307SMatthew Rosato 	WARN_ON(kzdev->zdev != zdev);
1756438e307SMatthew Rosato 	zdev->kzdev = NULL;
1766438e307SMatthew Rosato 	kfree(kzdev);
1776438e307SMatthew Rosato }
178*98b1d33dSMatthew Rosato 
179*98b1d33dSMatthew Rosato int kvm_s390_pci_init(void)
180*98b1d33dSMatthew Rosato {
181*98b1d33dSMatthew Rosato 	aift = kzalloc(sizeof(struct zpci_aift), GFP_KERNEL);
182*98b1d33dSMatthew Rosato 	if (!aift)
183*98b1d33dSMatthew Rosato 		return -ENOMEM;
184*98b1d33dSMatthew Rosato 
185*98b1d33dSMatthew Rosato 	spin_lock_init(&aift->gait_lock);
186*98b1d33dSMatthew Rosato 	mutex_init(&aift->aift_lock);
187*98b1d33dSMatthew Rosato 
188*98b1d33dSMatthew Rosato 	return 0;
189*98b1d33dSMatthew Rosato }
190*98b1d33dSMatthew Rosato 
191*98b1d33dSMatthew Rosato void kvm_s390_pci_exit(void)
192*98b1d33dSMatthew Rosato {
193*98b1d33dSMatthew Rosato 	mutex_destroy(&aift->aift_lock);
194*98b1d33dSMatthew Rosato 
195*98b1d33dSMatthew Rosato 	kfree(aift);
196*98b1d33dSMatthew Rosato }
197