xref: /openbmc/linux/arch/s390/pci/pci_iov.c (revision abb95b7550f88bfb77081601f80662a259f2d143)
1*abb95b75SNiklas Schnelle // SPDX-License-Identifier: GPL-2.0
2*abb95b75SNiklas Schnelle /*
3*abb95b75SNiklas Schnelle  * Copyright IBM Corp. 2020
4*abb95b75SNiklas Schnelle  *
5*abb95b75SNiklas Schnelle  * Author(s):
6*abb95b75SNiklas Schnelle  *   Niklas Schnelle <schnelle@linux.ibm.com>
7*abb95b75SNiklas Schnelle  *
8*abb95b75SNiklas Schnelle  */
9*abb95b75SNiklas Schnelle 
10*abb95b75SNiklas Schnelle #define KMSG_COMPONENT "zpci"
11*abb95b75SNiklas Schnelle #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12*abb95b75SNiklas Schnelle 
13*abb95b75SNiklas Schnelle #include <linux/kernel.h>
14*abb95b75SNiklas Schnelle #include <linux/pci.h>
15*abb95b75SNiklas Schnelle 
16*abb95b75SNiklas Schnelle static struct resource iov_res = {
17*abb95b75SNiklas Schnelle 	.name	= "PCI IOV res",
18*abb95b75SNiklas Schnelle 	.start	= 0,
19*abb95b75SNiklas Schnelle 	.end	= -1,
20*abb95b75SNiklas Schnelle 	.flags	= IORESOURCE_MEM,
21*abb95b75SNiklas Schnelle };
22*abb95b75SNiklas Schnelle 
23*abb95b75SNiklas Schnelle void zpci_iov_map_resources(struct pci_dev *pdev)
24*abb95b75SNiklas Schnelle {
25*abb95b75SNiklas Schnelle 	resource_size_t len;
26*abb95b75SNiklas Schnelle 	int i;
27*abb95b75SNiklas Schnelle 
28*abb95b75SNiklas Schnelle 	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
29*abb95b75SNiklas Schnelle 		int bar = i + PCI_IOV_RESOURCES;
30*abb95b75SNiklas Schnelle 
31*abb95b75SNiklas Schnelle 		len = pci_resource_len(pdev, bar);
32*abb95b75SNiklas Schnelle 		if (!len)
33*abb95b75SNiklas Schnelle 			continue;
34*abb95b75SNiklas Schnelle 		pdev->resource[bar].parent = &iov_res;
35*abb95b75SNiklas Schnelle 	}
36*abb95b75SNiklas Schnelle }
37*abb95b75SNiklas Schnelle 
38*abb95b75SNiklas Schnelle void zpci_iov_remove_virtfn(struct pci_dev *pdev, int vfn)
39*abb95b75SNiklas Schnelle {
40*abb95b75SNiklas Schnelle 	pci_lock_rescan_remove();
41*abb95b75SNiklas Schnelle 	/* Linux' vfid's start at 0 vfn at 1 */
42*abb95b75SNiklas Schnelle 	pci_iov_remove_virtfn(pdev->physfn, vfn - 1);
43*abb95b75SNiklas Schnelle 	pci_unlock_rescan_remove();
44*abb95b75SNiklas Schnelle }
45*abb95b75SNiklas Schnelle 
46*abb95b75SNiklas Schnelle static int zpci_iov_link_virtfn(struct pci_dev *pdev, struct pci_dev *virtfn, int vfid)
47*abb95b75SNiklas Schnelle {
48*abb95b75SNiklas Schnelle 	int rc;
49*abb95b75SNiklas Schnelle 
50*abb95b75SNiklas Schnelle 	rc = pci_iov_sysfs_link(pdev, virtfn, vfid);
51*abb95b75SNiklas Schnelle 	if (rc)
52*abb95b75SNiklas Schnelle 		return rc;
53*abb95b75SNiklas Schnelle 
54*abb95b75SNiklas Schnelle 	virtfn->is_virtfn = 1;
55*abb95b75SNiklas Schnelle 	virtfn->multifunction = 0;
56*abb95b75SNiklas Schnelle 	virtfn->physfn = pci_dev_get(pdev);
57*abb95b75SNiklas Schnelle 
58*abb95b75SNiklas Schnelle 	return 0;
59*abb95b75SNiklas Schnelle }
60*abb95b75SNiklas Schnelle 
61*abb95b75SNiklas Schnelle int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn)
62*abb95b75SNiklas Schnelle {
63*abb95b75SNiklas Schnelle 	int i, cand_devfn;
64*abb95b75SNiklas Schnelle 	struct zpci_dev *zdev;
65*abb95b75SNiklas Schnelle 	struct pci_dev *pdev;
66*abb95b75SNiklas Schnelle 	int vfid = vfn - 1; /* Linux' vfid's start at 0 vfn at 1*/
67*abb95b75SNiklas Schnelle 	int rc = 0;
68*abb95b75SNiklas Schnelle 
69*abb95b75SNiklas Schnelle 	if (!zbus->multifunction)
70*abb95b75SNiklas Schnelle 		return 0;
71*abb95b75SNiklas Schnelle 
72*abb95b75SNiklas Schnelle 	/* If the parent PF for the given VF is also configured in the
73*abb95b75SNiklas Schnelle 	 * instance, it must be on the same zbus.
74*abb95b75SNiklas Schnelle 	 * We can then identify the parent PF by checking what
75*abb95b75SNiklas Schnelle 	 * devfn the VF would have if it belonged to that PF using the PF's
76*abb95b75SNiklas Schnelle 	 * stride and offset. Only if this candidate devfn matches the
77*abb95b75SNiklas Schnelle 	 * actual devfn will we link both functions.
78*abb95b75SNiklas Schnelle 	 */
79*abb95b75SNiklas Schnelle 	for (i = 0; i < ZPCI_FUNCTIONS_PER_BUS; i++) {
80*abb95b75SNiklas Schnelle 		zdev = zbus->function[i];
81*abb95b75SNiklas Schnelle 		if (zdev && zdev->is_physfn) {
82*abb95b75SNiklas Schnelle 			pdev = pci_get_slot(zbus->bus, zdev->devfn);
83*abb95b75SNiklas Schnelle 			if (!pdev)
84*abb95b75SNiklas Schnelle 				continue;
85*abb95b75SNiklas Schnelle 			cand_devfn = pci_iov_virtfn_devfn(pdev, vfid);
86*abb95b75SNiklas Schnelle 			if (cand_devfn == virtfn->devfn) {
87*abb95b75SNiklas Schnelle 				rc = zpci_iov_link_virtfn(pdev, virtfn, vfid);
88*abb95b75SNiklas Schnelle 				/* balance pci_get_slot() */
89*abb95b75SNiklas Schnelle 				pci_dev_put(pdev);
90*abb95b75SNiklas Schnelle 				break;
91*abb95b75SNiklas Schnelle 			}
92*abb95b75SNiklas Schnelle 			/* balance pci_get_slot() */
93*abb95b75SNiklas Schnelle 			pci_dev_put(pdev);
94*abb95b75SNiklas Schnelle 		}
95*abb95b75SNiklas Schnelle 	}
96*abb95b75SNiklas Schnelle 	return rc;
97*abb95b75SNiklas Schnelle }
98