Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright IBM Corp. 2020
0004  *
0005  * Author(s):
0006  *   Niklas Schnelle <schnelle@linux.ibm.com>
0007  *
0008  */
0009 
0010 #define KMSG_COMPONENT "zpci"
0011 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/pci.h>
0015 
0016 #include "pci_iov.h"
0017 
0018 static struct resource iov_res = {
0019     .name   = "PCI IOV res",
0020     .start  = 0,
0021     .end    = -1,
0022     .flags  = IORESOURCE_MEM,
0023 };
0024 
0025 void zpci_iov_map_resources(struct pci_dev *pdev)
0026 {
0027     resource_size_t len;
0028     int i;
0029 
0030     for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
0031         int bar = i + PCI_IOV_RESOURCES;
0032 
0033         len = pci_resource_len(pdev, bar);
0034         if (!len)
0035             continue;
0036         pdev->resource[bar].parent = &iov_res;
0037     }
0038 }
0039 
0040 void zpci_iov_remove_virtfn(struct pci_dev *pdev, int vfn)
0041 {
0042     pci_lock_rescan_remove();
0043     /* Linux' vfid's start at 0 vfn at 1 */
0044     pci_iov_remove_virtfn(pdev->physfn, vfn - 1);
0045     pci_unlock_rescan_remove();
0046 }
0047 
0048 static int zpci_iov_link_virtfn(struct pci_dev *pdev, struct pci_dev *virtfn, int vfid)
0049 {
0050     int rc;
0051 
0052     rc = pci_iov_sysfs_link(pdev, virtfn, vfid);
0053     if (rc)
0054         return rc;
0055 
0056     virtfn->is_virtfn = 1;
0057     virtfn->multifunction = 0;
0058     virtfn->physfn = pci_dev_get(pdev);
0059 
0060     return 0;
0061 }
0062 
0063 int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn)
0064 {
0065     int i, cand_devfn;
0066     struct zpci_dev *zdev;
0067     struct pci_dev *pdev;
0068     int vfid = vfn - 1; /* Linux' vfid's start at 0 vfn at 1*/
0069     int rc = 0;
0070 
0071     if (!zbus->multifunction)
0072         return 0;
0073 
0074     /* If the parent PF for the given VF is also configured in the
0075      * instance, it must be on the same zbus.
0076      * We can then identify the parent PF by checking what
0077      * devfn the VF would have if it belonged to that PF using the PF's
0078      * stride and offset. Only if this candidate devfn matches the
0079      * actual devfn will we link both functions.
0080      */
0081     for (i = 0; i < ZPCI_FUNCTIONS_PER_BUS; i++) {
0082         zdev = zbus->function[i];
0083         if (zdev && zdev->is_physfn) {
0084             pdev = pci_get_slot(zbus->bus, zdev->devfn);
0085             if (!pdev)
0086                 continue;
0087             cand_devfn = pci_iov_virtfn_devfn(pdev, vfid);
0088             if (cand_devfn == virtfn->devfn) {
0089                 rc = zpci_iov_link_virtfn(pdev, virtfn, vfid);
0090                 /* balance pci_get_slot() */
0091                 pci_dev_put(pdev);
0092                 break;
0093             }
0094             /* balance pci_get_slot() */
0095             pci_dev_put(pdev);
0096         }
0097     }
0098     return rc;
0099 }