Typically, functions of the same PCI device (such as a PF and a VF)
share the same bus and have a common root port and the PF provisions
resources for the VF. Given this model, they can be considered
compatible as far as P2PDMA access is considered.

Currently, although the distance (2) is correctly calculated for
functions of the same device, an ACS check failure prevents P2P DMA
access between them. Therefore, introduce a small function named
pci_devfns_support_p2pdma() to determine if the provider and client
belong to the same device and facilitate P2PDMA between them by
not enforcing the ACS check.

However, since it is hard to determine if the device functions of
any given PCI device are P2PDMA compatible, we only relax the ACS
check enforcement for device functions of Intel GPUs. This is
because the P2PDMA communication between the PF and VF of Intel
GPUs is handled internally and does not typically involve the PCIe
fabric.

Cc: Bjorn Helgaas <[email protected]>
Cc: Logan Gunthorpe <[email protected]>
Cc: <[email protected]>
Signed-off-by: Vivek Kasireddy <[email protected]>
---
v1 -> v2:
- Relax the enforcment of ACS check only for Intel GPU functions
  as they are P2PDMA compatible given the way the PF provisions
  the resources among multiple VFs.

v2 -> v3:
- s/pci_devs_are_p2pdma_compatible/pci_devfns_support_p2pdma
- Improve the commit message to explain the reasoning behind
  relaxing the ACS check enforcement only for Intel GPU functions.

v3 -> v4: (Logan)
- Drop the dev_is_pf() hunk as no special handling is needed for PFs
- Besides the provider, also check to see the client is an Intel GPU
---
 drivers/pci/p2pdma.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index da5657a02007..0a1d884cd0ff 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -544,6 +544,19 @@ static unsigned long map_types_idx(struct pci_dev *client)
        return (pci_domain_nr(client->bus) << 16) | pci_dev_id(client);
 }
 
+static bool pci_devfns_support_p2pdma(struct pci_dev *provider,
+                                     struct pci_dev *client)
+{
+       if (provider->vendor == PCI_VENDOR_ID_INTEL &&
+           client->vendor == PCI_VENDOR_ID_INTEL) {
+               if ((pci_is_vga(provider) && pci_is_vga(client)) ||
+                   (pci_is_display(provider) && pci_is_display(client)))
+                       return pci_physfn(provider) == pci_physfn(client);
+       }
+
+       return false;
+}
+
 /*
  * Calculate the P2PDMA mapping type and distance between two PCI devices.
  *
@@ -643,7 +656,7 @@ calc_map_type_and_dist(struct pci_dev *provider, struct 
pci_dev *client,
 
        *dist = dist_a + dist_b;
 
-       if (!acs_cnt) {
+       if (!acs_cnt || pci_devfns_support_p2pdma(provider, client)) {
                map_type = PCI_P2PDMA_MAP_BUS_ADDR;
                goto done;
        }
-- 
2.50.1

Reply via email to