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(pdev->physfn, 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(pdev, virtfn, vfid); 53 if (rc) 54 return rc; 55 56 virtfn->is_virtfn = 1; 57 virtfn->multifunction = 0; 58 virtfn->physfn = pci_dev_get(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(zbus->bus, zdev->devfn); 85 if (!pdev) 86 continue; 87 cand_devfn = pci_iov_virtfn_devfn(pdev, 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(pdev); 92 break; 93 } 94 /* balance pci_get_slot() */ 95 pci_dev_put(pdev); 96 } 97 } 98 return rc; 99 } 100