xref: /openbmc/linux/arch/s390/kvm/pci.c (revision 3c5a1b6f0a18520a0edd0600fef6f1a8553b8fdc)
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>
14*3c5a1b6fSMatthew Rosato #include <asm/pci_io.h>
156438e307SMatthew Rosato #include "pci.h"
166438e307SMatthew Rosato 
1798b1d33dSMatthew Rosato struct zpci_aift *aift;
1898b1d33dSMatthew Rosato 
1998b1d33dSMatthew Rosato static inline int __set_irq_noiib(u16 ctl, u8 isc)
2098b1d33dSMatthew Rosato {
2198b1d33dSMatthew Rosato 	union zpci_sic_iib iib = {{0}};
2298b1d33dSMatthew Rosato 
2398b1d33dSMatthew Rosato 	return zpci_set_irq_ctrl(ctl, isc, &iib);
2498b1d33dSMatthew Rosato }
2598b1d33dSMatthew Rosato 
2698b1d33dSMatthew Rosato void kvm_s390_pci_aen_exit(void)
2798b1d33dSMatthew Rosato {
2898b1d33dSMatthew Rosato 	unsigned long flags;
2998b1d33dSMatthew Rosato 	struct kvm_zdev **gait_kzdev;
3098b1d33dSMatthew Rosato 
3198b1d33dSMatthew Rosato 	lockdep_assert_held(&aift->aift_lock);
3298b1d33dSMatthew Rosato 
3398b1d33dSMatthew Rosato 	/*
3498b1d33dSMatthew Rosato 	 * Contents of the aipb remain registered for the life of the host
3598b1d33dSMatthew Rosato 	 * kernel, the information preserved in zpci_aipb and zpci_aif_sbv
3698b1d33dSMatthew Rosato 	 * in case we insert the KVM module again later.  Clear the AIFT
3798b1d33dSMatthew Rosato 	 * information and free anything not registered with underlying
3898b1d33dSMatthew Rosato 	 * firmware.
3998b1d33dSMatthew Rosato 	 */
4098b1d33dSMatthew Rosato 	spin_lock_irqsave(&aift->gait_lock, flags);
4198b1d33dSMatthew Rosato 	gait_kzdev = aift->kzdev;
4298b1d33dSMatthew Rosato 	aift->gait = NULL;
4398b1d33dSMatthew Rosato 	aift->sbv = NULL;
4498b1d33dSMatthew Rosato 	aift->kzdev = NULL;
4598b1d33dSMatthew Rosato 	spin_unlock_irqrestore(&aift->gait_lock, flags);
4698b1d33dSMatthew Rosato 
4798b1d33dSMatthew Rosato 	kfree(gait_kzdev);
4898b1d33dSMatthew Rosato }
4998b1d33dSMatthew Rosato 
5098b1d33dSMatthew Rosato static int zpci_setup_aipb(u8 nisc)
5198b1d33dSMatthew Rosato {
5298b1d33dSMatthew Rosato 	struct page *page;
5398b1d33dSMatthew Rosato 	int size, rc;
5498b1d33dSMatthew Rosato 
5598b1d33dSMatthew Rosato 	zpci_aipb = kzalloc(sizeof(union zpci_sic_iib), GFP_KERNEL);
5698b1d33dSMatthew Rosato 	if (!zpci_aipb)
5798b1d33dSMatthew Rosato 		return -ENOMEM;
5898b1d33dSMatthew Rosato 
5998b1d33dSMatthew Rosato 	aift->sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, 0);
6098b1d33dSMatthew Rosato 	if (!aift->sbv) {
6198b1d33dSMatthew Rosato 		rc = -ENOMEM;
6298b1d33dSMatthew Rosato 		goto free_aipb;
6398b1d33dSMatthew Rosato 	}
6498b1d33dSMatthew Rosato 	zpci_aif_sbv = aift->sbv;
6598b1d33dSMatthew Rosato 	size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES *
6698b1d33dSMatthew Rosato 						sizeof(struct zpci_gaite)));
6798b1d33dSMatthew Rosato 	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, size);
6898b1d33dSMatthew Rosato 	if (!page) {
6998b1d33dSMatthew Rosato 		rc = -ENOMEM;
7098b1d33dSMatthew Rosato 		goto free_sbv;
7198b1d33dSMatthew Rosato 	}
7298b1d33dSMatthew Rosato 	aift->gait = (struct zpci_gaite *)page_to_phys(page);
7398b1d33dSMatthew Rosato 
7498b1d33dSMatthew Rosato 	zpci_aipb->aipb.faisb = virt_to_phys(aift->sbv->vector);
7598b1d33dSMatthew Rosato 	zpci_aipb->aipb.gait = virt_to_phys(aift->gait);
7698b1d33dSMatthew Rosato 	zpci_aipb->aipb.afi = nisc;
7798b1d33dSMatthew Rosato 	zpci_aipb->aipb.faal = ZPCI_NR_DEVICES;
7898b1d33dSMatthew Rosato 
7998b1d33dSMatthew Rosato 	/* Setup Adapter Event Notification Interpretation */
8098b1d33dSMatthew Rosato 	if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, zpci_aipb)) {
8198b1d33dSMatthew Rosato 		rc = -EIO;
8298b1d33dSMatthew Rosato 		goto free_gait;
8398b1d33dSMatthew Rosato 	}
8498b1d33dSMatthew Rosato 
8598b1d33dSMatthew Rosato 	return 0;
8698b1d33dSMatthew Rosato 
8798b1d33dSMatthew Rosato free_gait:
8898b1d33dSMatthew Rosato 	free_pages((unsigned long)aift->gait, size);
8998b1d33dSMatthew Rosato free_sbv:
9098b1d33dSMatthew Rosato 	airq_iv_release(aift->sbv);
9198b1d33dSMatthew Rosato 	zpci_aif_sbv = NULL;
9298b1d33dSMatthew Rosato free_aipb:
9398b1d33dSMatthew Rosato 	kfree(zpci_aipb);
9498b1d33dSMatthew Rosato 	zpci_aipb = NULL;
9598b1d33dSMatthew Rosato 
9698b1d33dSMatthew Rosato 	return rc;
9798b1d33dSMatthew Rosato }
9898b1d33dSMatthew Rosato 
9998b1d33dSMatthew Rosato static int zpci_reset_aipb(u8 nisc)
10098b1d33dSMatthew Rosato {
10198b1d33dSMatthew Rosato 	/*
10298b1d33dSMatthew Rosato 	 * AEN registration can only happen once per system boot.  If
10398b1d33dSMatthew Rosato 	 * an aipb already exists then AEN was already registered and
10498b1d33dSMatthew Rosato 	 * we can re-use the aipb contents.  This can only happen if
10598b1d33dSMatthew Rosato 	 * the KVM module was removed and re-inserted.  However, we must
10698b1d33dSMatthew Rosato 	 * ensure that the same forwarding ISC is used as this is assigned
10798b1d33dSMatthew Rosato 	 * during KVM module load.
10898b1d33dSMatthew Rosato 	 */
10998b1d33dSMatthew Rosato 	if (zpci_aipb->aipb.afi != nisc)
11098b1d33dSMatthew Rosato 		return -EINVAL;
11198b1d33dSMatthew Rosato 
11298b1d33dSMatthew Rosato 	aift->sbv = zpci_aif_sbv;
11398b1d33dSMatthew Rosato 	aift->gait = (struct zpci_gaite *)zpci_aipb->aipb.gait;
11498b1d33dSMatthew Rosato 
11598b1d33dSMatthew Rosato 	return 0;
11698b1d33dSMatthew Rosato }
11798b1d33dSMatthew Rosato 
11898b1d33dSMatthew Rosato int kvm_s390_pci_aen_init(u8 nisc)
11998b1d33dSMatthew Rosato {
12098b1d33dSMatthew Rosato 	int rc = 0;
12198b1d33dSMatthew Rosato 
12298b1d33dSMatthew Rosato 	/* If already enabled for AEN, bail out now */
12398b1d33dSMatthew Rosato 	if (aift->gait || aift->sbv)
12498b1d33dSMatthew Rosato 		return -EPERM;
12598b1d33dSMatthew Rosato 
12698b1d33dSMatthew Rosato 	mutex_lock(&aift->aift_lock);
12798b1d33dSMatthew Rosato 	aift->kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev),
12898b1d33dSMatthew Rosato 			      GFP_KERNEL);
12998b1d33dSMatthew Rosato 	if (!aift->kzdev) {
13098b1d33dSMatthew Rosato 		rc = -ENOMEM;
13198b1d33dSMatthew Rosato 		goto unlock;
13298b1d33dSMatthew Rosato 	}
13398b1d33dSMatthew Rosato 
13498b1d33dSMatthew Rosato 	if (!zpci_aipb)
13598b1d33dSMatthew Rosato 		rc = zpci_setup_aipb(nisc);
13698b1d33dSMatthew Rosato 	else
13798b1d33dSMatthew Rosato 		rc = zpci_reset_aipb(nisc);
13898b1d33dSMatthew Rosato 	if (rc)
13998b1d33dSMatthew Rosato 		goto free_zdev;
14098b1d33dSMatthew Rosato 
14198b1d33dSMatthew Rosato 	/* Enable floating IRQs */
14298b1d33dSMatthew Rosato 	if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) {
14398b1d33dSMatthew Rosato 		rc = -EIO;
14498b1d33dSMatthew Rosato 		kvm_s390_pci_aen_exit();
14598b1d33dSMatthew Rosato 	}
14698b1d33dSMatthew Rosato 
14798b1d33dSMatthew Rosato 	goto unlock;
14898b1d33dSMatthew Rosato 
14998b1d33dSMatthew Rosato free_zdev:
15098b1d33dSMatthew Rosato 	kfree(aift->kzdev);
15198b1d33dSMatthew Rosato unlock:
15298b1d33dSMatthew Rosato 	mutex_unlock(&aift->aift_lock);
15398b1d33dSMatthew Rosato 	return rc;
15498b1d33dSMatthew Rosato }
15598b1d33dSMatthew Rosato 
156*3c5a1b6fSMatthew Rosato /* Modify PCI: Register floating adapter interruption forwarding */
157*3c5a1b6fSMatthew Rosato static int kvm_zpci_set_airq(struct zpci_dev *zdev)
158*3c5a1b6fSMatthew Rosato {
159*3c5a1b6fSMatthew Rosato 	u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT);
160*3c5a1b6fSMatthew Rosato 	struct zpci_fib fib = {};
161*3c5a1b6fSMatthew Rosato 	u8 status;
162*3c5a1b6fSMatthew Rosato 
163*3c5a1b6fSMatthew Rosato 	fib.fmt0.isc = zdev->kzdev->fib.fmt0.isc;
164*3c5a1b6fSMatthew Rosato 	fib.fmt0.sum = 1;       /* enable summary notifications */
165*3c5a1b6fSMatthew Rosato 	fib.fmt0.noi = airq_iv_end(zdev->aibv);
166*3c5a1b6fSMatthew Rosato 	fib.fmt0.aibv = virt_to_phys(zdev->aibv->vector);
167*3c5a1b6fSMatthew Rosato 	fib.fmt0.aibvo = 0;
168*3c5a1b6fSMatthew Rosato 	fib.fmt0.aisb = virt_to_phys(aift->sbv->vector + (zdev->aisb / 64) * 8);
169*3c5a1b6fSMatthew Rosato 	fib.fmt0.aisbo = zdev->aisb & 63;
170*3c5a1b6fSMatthew Rosato 	fib.gd = zdev->gisa;
171*3c5a1b6fSMatthew Rosato 
172*3c5a1b6fSMatthew Rosato 	return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
173*3c5a1b6fSMatthew Rosato }
174*3c5a1b6fSMatthew Rosato 
175*3c5a1b6fSMatthew Rosato /* Modify PCI: Unregister floating adapter interruption forwarding */
176*3c5a1b6fSMatthew Rosato static int kvm_zpci_clear_airq(struct zpci_dev *zdev)
177*3c5a1b6fSMatthew Rosato {
178*3c5a1b6fSMatthew Rosato 	u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT);
179*3c5a1b6fSMatthew Rosato 	struct zpci_fib fib = {};
180*3c5a1b6fSMatthew Rosato 	u8 cc, status;
181*3c5a1b6fSMatthew Rosato 
182*3c5a1b6fSMatthew Rosato 	fib.gd = zdev->gisa;
183*3c5a1b6fSMatthew Rosato 
184*3c5a1b6fSMatthew Rosato 	cc = zpci_mod_fc(req, &fib, &status);
185*3c5a1b6fSMatthew Rosato 	if (cc == 3 || (cc == 1 && status == 24))
186*3c5a1b6fSMatthew Rosato 		/* Function already gone or IRQs already deregistered. */
187*3c5a1b6fSMatthew Rosato 		cc = 0;
188*3c5a1b6fSMatthew Rosato 
189*3c5a1b6fSMatthew Rosato 	return cc ? -EIO : 0;
190*3c5a1b6fSMatthew Rosato }
191*3c5a1b6fSMatthew Rosato 
192*3c5a1b6fSMatthew Rosato static inline void unaccount_mem(unsigned long nr_pages)
193*3c5a1b6fSMatthew Rosato {
194*3c5a1b6fSMatthew Rosato 	struct user_struct *user = get_uid(current_user());
195*3c5a1b6fSMatthew Rosato 
196*3c5a1b6fSMatthew Rosato 	if (user)
197*3c5a1b6fSMatthew Rosato 		atomic_long_sub(nr_pages, &user->locked_vm);
198*3c5a1b6fSMatthew Rosato 	if (current->mm)
199*3c5a1b6fSMatthew Rosato 		atomic64_sub(nr_pages, &current->mm->pinned_vm);
200*3c5a1b6fSMatthew Rosato }
201*3c5a1b6fSMatthew Rosato 
202*3c5a1b6fSMatthew Rosato static inline int account_mem(unsigned long nr_pages)
203*3c5a1b6fSMatthew Rosato {
204*3c5a1b6fSMatthew Rosato 	struct user_struct *user = get_uid(current_user());
205*3c5a1b6fSMatthew Rosato 	unsigned long page_limit, cur_pages, new_pages;
206*3c5a1b6fSMatthew Rosato 
207*3c5a1b6fSMatthew Rosato 	page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
208*3c5a1b6fSMatthew Rosato 
209*3c5a1b6fSMatthew Rosato 	do {
210*3c5a1b6fSMatthew Rosato 		cur_pages = atomic_long_read(&user->locked_vm);
211*3c5a1b6fSMatthew Rosato 		new_pages = cur_pages + nr_pages;
212*3c5a1b6fSMatthew Rosato 		if (new_pages > page_limit)
213*3c5a1b6fSMatthew Rosato 			return -ENOMEM;
214*3c5a1b6fSMatthew Rosato 	} while (atomic_long_cmpxchg(&user->locked_vm, cur_pages,
215*3c5a1b6fSMatthew Rosato 					new_pages) != cur_pages);
216*3c5a1b6fSMatthew Rosato 
217*3c5a1b6fSMatthew Rosato 	atomic64_add(nr_pages, &current->mm->pinned_vm);
218*3c5a1b6fSMatthew Rosato 
219*3c5a1b6fSMatthew Rosato 	return 0;
220*3c5a1b6fSMatthew Rosato }
221*3c5a1b6fSMatthew Rosato 
222*3c5a1b6fSMatthew Rosato static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
223*3c5a1b6fSMatthew Rosato 				   bool assist)
224*3c5a1b6fSMatthew Rosato {
225*3c5a1b6fSMatthew Rosato 	struct page *pages[1], *aibv_page, *aisb_page = NULL;
226*3c5a1b6fSMatthew Rosato 	unsigned int msi_vecs, idx;
227*3c5a1b6fSMatthew Rosato 	struct zpci_gaite *gaite;
228*3c5a1b6fSMatthew Rosato 	unsigned long hva, bit;
229*3c5a1b6fSMatthew Rosato 	struct kvm *kvm;
230*3c5a1b6fSMatthew Rosato 	phys_addr_t gaddr;
231*3c5a1b6fSMatthew Rosato 	int rc = 0, gisc, npages, pcount = 0;
232*3c5a1b6fSMatthew Rosato 
233*3c5a1b6fSMatthew Rosato 	/*
234*3c5a1b6fSMatthew Rosato 	 * Interrupt forwarding is only applicable if the device is already
235*3c5a1b6fSMatthew Rosato 	 * enabled for interpretation
236*3c5a1b6fSMatthew Rosato 	 */
237*3c5a1b6fSMatthew Rosato 	if (zdev->gisa == 0)
238*3c5a1b6fSMatthew Rosato 		return -EINVAL;
239*3c5a1b6fSMatthew Rosato 
240*3c5a1b6fSMatthew Rosato 	kvm = zdev->kzdev->kvm;
241*3c5a1b6fSMatthew Rosato 	msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
242*3c5a1b6fSMatthew Rosato 
243*3c5a1b6fSMatthew Rosato 	/* Get the associated forwarding ISC - if invalid, return the error */
244*3c5a1b6fSMatthew Rosato 	gisc = kvm_s390_gisc_register(kvm, fib->fmt0.isc);
245*3c5a1b6fSMatthew Rosato 	if (gisc < 0)
246*3c5a1b6fSMatthew Rosato 		return gisc;
247*3c5a1b6fSMatthew Rosato 
248*3c5a1b6fSMatthew Rosato 	/* Replace AIBV address */
249*3c5a1b6fSMatthew Rosato 	idx = srcu_read_lock(&kvm->srcu);
250*3c5a1b6fSMatthew Rosato 	hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
251*3c5a1b6fSMatthew Rosato 	npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
252*3c5a1b6fSMatthew Rosato 	srcu_read_unlock(&kvm->srcu, idx);
253*3c5a1b6fSMatthew Rosato 	if (npages < 1) {
254*3c5a1b6fSMatthew Rosato 		rc = -EIO;
255*3c5a1b6fSMatthew Rosato 		goto out;
256*3c5a1b6fSMatthew Rosato 	}
257*3c5a1b6fSMatthew Rosato 	aibv_page = pages[0];
258*3c5a1b6fSMatthew Rosato 	pcount++;
259*3c5a1b6fSMatthew Rosato 	gaddr = page_to_phys(aibv_page) + (fib->fmt0.aibv & ~PAGE_MASK);
260*3c5a1b6fSMatthew Rosato 	fib->fmt0.aibv = gaddr;
261*3c5a1b6fSMatthew Rosato 
262*3c5a1b6fSMatthew Rosato 	/* Pin the guest AISB if one was specified */
263*3c5a1b6fSMatthew Rosato 	if (fib->fmt0.sum == 1) {
264*3c5a1b6fSMatthew Rosato 		idx = srcu_read_lock(&kvm->srcu);
265*3c5a1b6fSMatthew Rosato 		hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb));
266*3c5a1b6fSMatthew Rosato 		npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
267*3c5a1b6fSMatthew Rosato 					     pages);
268*3c5a1b6fSMatthew Rosato 		srcu_read_unlock(&kvm->srcu, idx);
269*3c5a1b6fSMatthew Rosato 		if (npages < 1) {
270*3c5a1b6fSMatthew Rosato 			rc = -EIO;
271*3c5a1b6fSMatthew Rosato 			goto unpin1;
272*3c5a1b6fSMatthew Rosato 		}
273*3c5a1b6fSMatthew Rosato 		aisb_page = pages[0];
274*3c5a1b6fSMatthew Rosato 		pcount++;
275*3c5a1b6fSMatthew Rosato 	}
276*3c5a1b6fSMatthew Rosato 
277*3c5a1b6fSMatthew Rosato 	/* Account for pinned pages, roll back on failure */
278*3c5a1b6fSMatthew Rosato 	if (account_mem(pcount))
279*3c5a1b6fSMatthew Rosato 		goto unpin2;
280*3c5a1b6fSMatthew Rosato 
281*3c5a1b6fSMatthew Rosato 	/* AISB must be allocated before we can fill in GAITE */
282*3c5a1b6fSMatthew Rosato 	mutex_lock(&aift->aift_lock);
283*3c5a1b6fSMatthew Rosato 	bit = airq_iv_alloc_bit(aift->sbv);
284*3c5a1b6fSMatthew Rosato 	if (bit == -1UL)
285*3c5a1b6fSMatthew Rosato 		goto unlock;
286*3c5a1b6fSMatthew Rosato 	zdev->aisb = bit; /* store the summary bit number */
287*3c5a1b6fSMatthew Rosato 	zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
288*3c5a1b6fSMatthew Rosato 				    AIRQ_IV_BITLOCK |
289*3c5a1b6fSMatthew Rosato 				    AIRQ_IV_GUESTVEC,
290*3c5a1b6fSMatthew Rosato 				    phys_to_virt(fib->fmt0.aibv));
291*3c5a1b6fSMatthew Rosato 
292*3c5a1b6fSMatthew Rosato 	spin_lock_irq(&aift->gait_lock);
293*3c5a1b6fSMatthew Rosato 	gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb *
294*3c5a1b6fSMatthew Rosato 						   sizeof(struct zpci_gaite));
295*3c5a1b6fSMatthew Rosato 
296*3c5a1b6fSMatthew Rosato 	/* If assist not requested, host will get all alerts */
297*3c5a1b6fSMatthew Rosato 	if (assist)
298*3c5a1b6fSMatthew Rosato 		gaite->gisa = (u32)virt_to_phys(&kvm->arch.sie_page2->gisa);
299*3c5a1b6fSMatthew Rosato 	else
300*3c5a1b6fSMatthew Rosato 		gaite->gisa = 0;
301*3c5a1b6fSMatthew Rosato 
302*3c5a1b6fSMatthew Rosato 	gaite->gisc = fib->fmt0.isc;
303*3c5a1b6fSMatthew Rosato 	gaite->count++;
304*3c5a1b6fSMatthew Rosato 	gaite->aisbo = fib->fmt0.aisbo;
305*3c5a1b6fSMatthew Rosato 	gaite->aisb = virt_to_phys(page_address(aisb_page) + (fib->fmt0.aisb &
306*3c5a1b6fSMatthew Rosato 							      ~PAGE_MASK));
307*3c5a1b6fSMatthew Rosato 	aift->kzdev[zdev->aisb] = zdev->kzdev;
308*3c5a1b6fSMatthew Rosato 	spin_unlock_irq(&aift->gait_lock);
309*3c5a1b6fSMatthew Rosato 
310*3c5a1b6fSMatthew Rosato 	/* Update guest FIB for re-issue */
311*3c5a1b6fSMatthew Rosato 	fib->fmt0.aisbo = zdev->aisb & 63;
312*3c5a1b6fSMatthew Rosato 	fib->fmt0.aisb = virt_to_phys(aift->sbv->vector + (zdev->aisb / 64) * 8);
313*3c5a1b6fSMatthew Rosato 	fib->fmt0.isc = gisc;
314*3c5a1b6fSMatthew Rosato 
315*3c5a1b6fSMatthew Rosato 	/* Save some guest fib values in the host for later use */
316*3c5a1b6fSMatthew Rosato 	zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc;
317*3c5a1b6fSMatthew Rosato 	zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv;
318*3c5a1b6fSMatthew Rosato 	mutex_unlock(&aift->aift_lock);
319*3c5a1b6fSMatthew Rosato 
320*3c5a1b6fSMatthew Rosato 	/* Issue the clp to setup the irq now */
321*3c5a1b6fSMatthew Rosato 	rc = kvm_zpci_set_airq(zdev);
322*3c5a1b6fSMatthew Rosato 	return rc;
323*3c5a1b6fSMatthew Rosato 
324*3c5a1b6fSMatthew Rosato unlock:
325*3c5a1b6fSMatthew Rosato 	mutex_unlock(&aift->aift_lock);
326*3c5a1b6fSMatthew Rosato unpin2:
327*3c5a1b6fSMatthew Rosato 	if (fib->fmt0.sum == 1)
328*3c5a1b6fSMatthew Rosato 		unpin_user_page(aisb_page);
329*3c5a1b6fSMatthew Rosato unpin1:
330*3c5a1b6fSMatthew Rosato 	unpin_user_page(aibv_page);
331*3c5a1b6fSMatthew Rosato out:
332*3c5a1b6fSMatthew Rosato 	return rc;
333*3c5a1b6fSMatthew Rosato }
334*3c5a1b6fSMatthew Rosato 
335*3c5a1b6fSMatthew Rosato static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force)
336*3c5a1b6fSMatthew Rosato {
337*3c5a1b6fSMatthew Rosato 	struct kvm_zdev *kzdev = zdev->kzdev;
338*3c5a1b6fSMatthew Rosato 	struct zpci_gaite *gaite;
339*3c5a1b6fSMatthew Rosato 	struct page *vpage = NULL, *spage = NULL;
340*3c5a1b6fSMatthew Rosato 	int rc, pcount = 0;
341*3c5a1b6fSMatthew Rosato 	u8 isc;
342*3c5a1b6fSMatthew Rosato 
343*3c5a1b6fSMatthew Rosato 	if (zdev->gisa == 0)
344*3c5a1b6fSMatthew Rosato 		return -EINVAL;
345*3c5a1b6fSMatthew Rosato 
346*3c5a1b6fSMatthew Rosato 	mutex_lock(&aift->aift_lock);
347*3c5a1b6fSMatthew Rosato 
348*3c5a1b6fSMatthew Rosato 	/*
349*3c5a1b6fSMatthew Rosato 	 * If the clear fails due to an error, leave now unless we know this
350*3c5a1b6fSMatthew Rosato 	 * device is about to go away (force) -- In that case clear the GAITE
351*3c5a1b6fSMatthew Rosato 	 * regardless.
352*3c5a1b6fSMatthew Rosato 	 */
353*3c5a1b6fSMatthew Rosato 	rc = kvm_zpci_clear_airq(zdev);
354*3c5a1b6fSMatthew Rosato 	if (rc && !force)
355*3c5a1b6fSMatthew Rosato 		goto out;
356*3c5a1b6fSMatthew Rosato 
357*3c5a1b6fSMatthew Rosato 	if (zdev->kzdev->fib.fmt0.aibv == 0)
358*3c5a1b6fSMatthew Rosato 		goto out;
359*3c5a1b6fSMatthew Rosato 	spin_lock_irq(&aift->gait_lock);
360*3c5a1b6fSMatthew Rosato 	gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb *
361*3c5a1b6fSMatthew Rosato 						   sizeof(struct zpci_gaite));
362*3c5a1b6fSMatthew Rosato 	isc = gaite->gisc;
363*3c5a1b6fSMatthew Rosato 	gaite->count--;
364*3c5a1b6fSMatthew Rosato 	if (gaite->count == 0) {
365*3c5a1b6fSMatthew Rosato 		/* Release guest AIBV and AISB */
366*3c5a1b6fSMatthew Rosato 		vpage = phys_to_page(kzdev->fib.fmt0.aibv);
367*3c5a1b6fSMatthew Rosato 		if (gaite->aisb != 0)
368*3c5a1b6fSMatthew Rosato 			spage = phys_to_page(gaite->aisb);
369*3c5a1b6fSMatthew Rosato 		/* Clear the GAIT entry */
370*3c5a1b6fSMatthew Rosato 		gaite->aisb = 0;
371*3c5a1b6fSMatthew Rosato 		gaite->gisc = 0;
372*3c5a1b6fSMatthew Rosato 		gaite->aisbo = 0;
373*3c5a1b6fSMatthew Rosato 		gaite->gisa = 0;
374*3c5a1b6fSMatthew Rosato 		aift->kzdev[zdev->aisb] = 0;
375*3c5a1b6fSMatthew Rosato 		/* Clear zdev info */
376*3c5a1b6fSMatthew Rosato 		airq_iv_free_bit(aift->sbv, zdev->aisb);
377*3c5a1b6fSMatthew Rosato 		airq_iv_release(zdev->aibv);
378*3c5a1b6fSMatthew Rosato 		zdev->aisb = 0;
379*3c5a1b6fSMatthew Rosato 		zdev->aibv = NULL;
380*3c5a1b6fSMatthew Rosato 	}
381*3c5a1b6fSMatthew Rosato 	spin_unlock_irq(&aift->gait_lock);
382*3c5a1b6fSMatthew Rosato 	kvm_s390_gisc_unregister(kzdev->kvm, isc);
383*3c5a1b6fSMatthew Rosato 	kzdev->fib.fmt0.isc = 0;
384*3c5a1b6fSMatthew Rosato 	kzdev->fib.fmt0.aibv = 0;
385*3c5a1b6fSMatthew Rosato 
386*3c5a1b6fSMatthew Rosato 	if (vpage) {
387*3c5a1b6fSMatthew Rosato 		unpin_user_page(vpage);
388*3c5a1b6fSMatthew Rosato 		pcount++;
389*3c5a1b6fSMatthew Rosato 	}
390*3c5a1b6fSMatthew Rosato 	if (spage) {
391*3c5a1b6fSMatthew Rosato 		unpin_user_page(spage);
392*3c5a1b6fSMatthew Rosato 		pcount++;
393*3c5a1b6fSMatthew Rosato 	}
394*3c5a1b6fSMatthew Rosato 	if (pcount > 0)
395*3c5a1b6fSMatthew Rosato 		unaccount_mem(pcount);
396*3c5a1b6fSMatthew Rosato out:
397*3c5a1b6fSMatthew Rosato 	mutex_unlock(&aift->aift_lock);
398*3c5a1b6fSMatthew Rosato 
399*3c5a1b6fSMatthew Rosato 	return rc;
400*3c5a1b6fSMatthew Rosato }
401*3c5a1b6fSMatthew Rosato 
4026438e307SMatthew Rosato static int kvm_s390_pci_dev_open(struct zpci_dev *zdev)
4036438e307SMatthew Rosato {
4046438e307SMatthew Rosato 	struct kvm_zdev *kzdev;
4056438e307SMatthew Rosato 
4066438e307SMatthew Rosato 	kzdev = kzalloc(sizeof(struct kvm_zdev), GFP_KERNEL);
4076438e307SMatthew Rosato 	if (!kzdev)
4086438e307SMatthew Rosato 		return -ENOMEM;
4096438e307SMatthew Rosato 
4106438e307SMatthew Rosato 	kzdev->zdev = zdev;
4116438e307SMatthew Rosato 	zdev->kzdev = kzdev;
4126438e307SMatthew Rosato 
4136438e307SMatthew Rosato 	return 0;
4146438e307SMatthew Rosato }
4156438e307SMatthew Rosato 
4166438e307SMatthew Rosato static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
4176438e307SMatthew Rosato {
4186438e307SMatthew Rosato 	struct kvm_zdev *kzdev;
4196438e307SMatthew Rosato 
4206438e307SMatthew Rosato 	kzdev = zdev->kzdev;
4216438e307SMatthew Rosato 	WARN_ON(kzdev->zdev != zdev);
4226438e307SMatthew Rosato 	zdev->kzdev = NULL;
4236438e307SMatthew Rosato 	kfree(kzdev);
4246438e307SMatthew Rosato }
42598b1d33dSMatthew Rosato 
42698b1d33dSMatthew Rosato int kvm_s390_pci_init(void)
42798b1d33dSMatthew Rosato {
42898b1d33dSMatthew Rosato 	aift = kzalloc(sizeof(struct zpci_aift), GFP_KERNEL);
42998b1d33dSMatthew Rosato 	if (!aift)
43098b1d33dSMatthew Rosato 		return -ENOMEM;
43198b1d33dSMatthew Rosato 
43298b1d33dSMatthew Rosato 	spin_lock_init(&aift->gait_lock);
43398b1d33dSMatthew Rosato 	mutex_init(&aift->aift_lock);
43498b1d33dSMatthew Rosato 
43598b1d33dSMatthew Rosato 	return 0;
43698b1d33dSMatthew Rosato }
43798b1d33dSMatthew Rosato 
43898b1d33dSMatthew Rosato void kvm_s390_pci_exit(void)
43998b1d33dSMatthew Rosato {
44098b1d33dSMatthew Rosato 	mutex_destroy(&aift->aift_lock);
44198b1d33dSMatthew Rosato 
44298b1d33dSMatthew Rosato 	kfree(aift);
44398b1d33dSMatthew Rosato }
444