File Index
Files and directories
Sign in
FILE

pci_iov.c

File preview with syntax highlighting.

linux-6.19.14/arch/s390/pci/pci_iov.c 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.