FILE
pci_iov.c
File preview with syntax highlighting.
linux-6.19.14/arch/s390/pci/pci_iov.c
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 pr_fmt(fmt) "zpci: " fmt 11 12#include <linux/kernel.h> 13#include <linux/pci.h> 14 15#include "pci_iov.h" 16 17static struct resource iov_res = { 18 .name = "PCI IOV res", 19 .start = 0, 20 .end = -1, 21 .flags = IORESOURCE_MEM, 22}; 23 24void zpci_iov_map_resources(struct pci_dev *pdev) 25{ 26 resource_size_t len; 27 int i; 28 29 for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 30 int bar = i + PCI_IOV_RESOURCES; 31 32 len = pci_resource_len(pdev, bar); 33 if (!len) 34 continue; 35 pdev->resource[bar].parent = &iov_res; 36 } 37} 38 39void zpci_iov_remove_virtfn(struct pci_dev *pdev, int vfn) 40{ 41 pci_lock_rescan_remove(); 42 /* Linux' vfid's start at 0 vfn at 1 */ 43 pci_iov_remove_virtfn(pdev->physfn, vfn - 1); 44 pci_unlock_rescan_remove(); 45} 46 47static int zpci_iov_link_virtfn(struct pci_dev *pdev, struct pci_dev *virtfn, int vfid) 48{ 49 int rc; 50 51 rc = pci_iov_sysfs_link(pdev, virtfn, vfid); 52 if (rc) 53 return rc; 54 55 virtfn->is_virtfn = 1; 56 virtfn->multifunction = 0; 57 virtfn->physfn = pci_dev_get(pdev); 58 59 return 0; 60} 61 62/** 63 * zpci_iov_find_parent_pf - Find the parent PF, if any, of the given function 64 * @zbus: The bus that the PCI function is on, or would be added on 65 * @zdev: The PCI function 66 * 67 * Finds the parent PF, if it exists and is configured, of the given PCI function 68 * and increments its refcount. Th PF is searched for on the provided bus so the 69 * caller has to ensure that this is the correct bus to search. This function may 70 * be used before adding the PCI function to a zbus. 71 * 72 * Return: Pointer to the struct pci_dev of the parent PF or NULL if it not 73 * found. If the function is not a VF or has no RequesterID information, 74 * NULL is returned as well. 75 */ 76struct pci_dev *zpci_iov_find_parent_pf(struct zpci_bus *zbus, struct zpci_dev *zdev) 77{ 78 int i, vfid, devfn, cand_devfn; 79 struct pci_dev *pdev; 80 81 if (!zbus->multifunction) 82 return NULL; 83 /* Non-VFs and VFs without RID available don't have a parent */ 84 if (!zdev->vfn || !zdev->rid_available) 85 return NULL; 86 /* Linux vfid starts at 0 vfn at 1 */ 87 vfid = zdev->vfn - 1; 88 devfn = zdev->rid & ZPCI_RID_MASK_DEVFN; 89 /* 90 * If the parent PF for the given VF is also configured in the 91 * instance, it must be on the same zbus. 92 * We can then identify the parent PF by checking what 93 * devfn the VF would have if it belonged to that PF using the PF's 94 * stride and offset. Only if this candidate devfn matches the 95 * actual devfn will we link both functions. 96 */ 97 for (i = 0; i < ZPCI_FUNCTIONS_PER_BUS; i++) { 98 zdev = zbus->function[i]; 99 if (zdev && zdev->is_physfn) { 100 pdev = pci_get_slot(zbus->bus, zdev->devfn); 101 if (!pdev) 102 continue; 103 cand_devfn = pci_iov_virtfn_devfn(pdev, vfid); 104 if (cand_devfn == devfn) 105 return pdev; 106 /* balance pci_get_slot() */ 107 pci_dev_put(pdev); 108 } 109 } 110 return NULL; 111} 112 113int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn) 114{ 115 struct zpci_dev *zdev = to_zpci(virtfn); 116 struct pci_dev *pdev_pf; 117 int rc = 0; 118 119 pdev_pf = zpci_iov_find_parent_pf(zbus, zdev); 120 if (pdev_pf) { 121 /* Linux' vfids start at 0 while zdev->vfn starts at 1 */ 122 rc = zpci_iov_link_virtfn(pdev_pf, virtfn, zdev->vfn - 1); 123 pci_dev_put(pdev_pf); 124 } 125 return rc; 126}
~/
Read-only file preview.