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