linux/arch/s390/pci/pci_iov.c
<<
>>
Prefs
   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
  18static struct resource iov_res = {
  19        .name   = "PCI IOV res",
  20        .start  = 0,
  21        .end    = -1,
  22        .flags  = IORESOURCE_MEM,
  23};
  24
  25void 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
  40void 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
  48static 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
  63int 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