| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define KMSG_COMPONENT "zpci" |
| #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| |
| #include <linux/kernel.h> |
| #include <linux/pci.h> |
| |
| #include "pci_iov.h" |
| |
| static struct resource iov_res = { |
| <------>.name = "PCI IOV res", |
| <------>.start = 0, |
| <------>.end = -1, |
| <------>.flags = IORESOURCE_MEM, |
| }; |
| |
| void zpci_iov_map_resources(struct pci_dev *pdev) |
| { |
| <------>resource_size_t len; |
| <------>int i; |
| |
| <------>for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { |
| <------><------>int bar = i + PCI_IOV_RESOURCES; |
| |
| <------><------>len = pci_resource_len(pdev, bar); |
| <------><------>if (!len) |
| <------><------><------>continue; |
| <------><------>pdev->resource[bar].parent = &iov_res; |
| <------>} |
| } |
| |
| void zpci_iov_remove_virtfn(struct pci_dev *pdev, int vfn) |
| { |
| <------>pci_lock_rescan_remove(); |
| <------> |
| <------>pci_iov_remove_virtfn(pdev->physfn, vfn - 1); |
| <------>pci_unlock_rescan_remove(); |
| } |
| |
| static int zpci_iov_link_virtfn(struct pci_dev *pdev, struct pci_dev *virtfn, int vfid) |
| { |
| <------>int rc; |
| |
| <------>rc = pci_iov_sysfs_link(pdev, virtfn, vfid); |
| <------>if (rc) |
| <------><------>return rc; |
| |
| <------>virtfn->is_virtfn = 1; |
| <------>virtfn->multifunction = 0; |
| <------>virtfn->physfn = pci_dev_get(pdev); |
| |
| <------>return 0; |
| } |
| |
| int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn) |
| { |
| <------>int i, cand_devfn; |
| <------>struct zpci_dev *zdev; |
| <------>struct pci_dev *pdev; |
| <------>int vfid = vfn - 1; |
| <------>int rc = 0; |
| |
| <------>if (!zbus->multifunction) |
| <------><------>return 0; |
| |
| <------> |
| <------> * instance, it must be on the same zbus. |
| <------> * We can then identify the parent PF by checking what |
| <------> * devfn the VF would have if it belonged to that PF using the PF's |
| <------> * stride and offset. Only if this candidate devfn matches the |
| <------> * actual devfn will we link both functions. |
| <------> */ |
| <------>for (i = 0; i < ZPCI_FUNCTIONS_PER_BUS; i++) { |
| <------><------>zdev = zbus->function[i]; |
| <------><------>if (zdev && zdev->is_physfn) { |
| <------><------><------>pdev = pci_get_slot(zbus->bus, zdev->devfn); |
| <------><------><------>if (!pdev) |
| <------><------><------><------>continue; |
| <------><------><------>cand_devfn = pci_iov_virtfn_devfn(pdev, vfid); |
| <------><------><------>if (cand_devfn == virtfn->devfn) { |
| <------><------><------><------>rc = zpci_iov_link_virtfn(pdev, virtfn, vfid); |
| <------><------><------><------> |
| <------><------><------><------>pci_dev_put(pdev); |
| <------><------><------><------>break; |
| <------><------><------>} |
| <------><------><------> |
| <------><------><------>pci_dev_put(pdev); |
| <------><------>} |
| <------>} |
| <------>return rc; |
| } |
| |