Merge branch 'pci/peer-to-peer'
- Add a whitelist of Root Complexes known to support peer-to-peer DMA between Root Ports (Christian König) * pci/peer-to-peer: PCI/P2PDMA: Allow P2P DMA between any devices under AMD ZEN Root Complex
This commit is contained in:
commit
292c939654
|
@ -274,6 +274,30 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
|
||||||
seq_buf_printf(buf, "%s;", pci_name(pdev));
|
seq_buf_printf(buf, "%s;", pci_name(pdev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we can't find a common upstream bridge take a look at the root
|
||||||
|
* complex and compare it to a whitelist of known good hardware.
|
||||||
|
*/
|
||||||
|
static bool root_complex_whitelist(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
|
||||||
|
struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
|
||||||
|
unsigned short vendor, device;
|
||||||
|
|
||||||
|
if (!root)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vendor = root->vendor;
|
||||||
|
device = root->device;
|
||||||
|
pci_dev_put(root);
|
||||||
|
|
||||||
|
/* AMD ZEN host bridges can do peer to peer */
|
||||||
|
if (vendor == PCI_VENDOR_ID_AMD && device == 0x1450)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the distance through the nearest common upstream bridge between
|
* Find the distance through the nearest common upstream bridge between
|
||||||
* two PCI devices.
|
* two PCI devices.
|
||||||
|
@ -317,13 +341,13 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
|
||||||
* In this case, a list of all infringing bridge addresses will be
|
* In this case, a list of all infringing bridge addresses will be
|
||||||
* populated in acs_list (assuming it's non-null) for printk purposes.
|
* populated in acs_list (assuming it's non-null) for printk purposes.
|
||||||
*/
|
*/
|
||||||
static int upstream_bridge_distance(struct pci_dev *a,
|
static int upstream_bridge_distance(struct pci_dev *provider,
|
||||||
struct pci_dev *b,
|
struct pci_dev *client,
|
||||||
struct seq_buf *acs_list)
|
struct seq_buf *acs_list)
|
||||||
{
|
{
|
||||||
|
struct pci_dev *a = provider, *b = client, *bb;
|
||||||
int dist_a = 0;
|
int dist_a = 0;
|
||||||
int dist_b = 0;
|
int dist_b = 0;
|
||||||
struct pci_dev *bb = NULL;
|
|
||||||
int acs_cnt = 0;
|
int acs_cnt = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -354,6 +378,14 @@ static int upstream_bridge_distance(struct pci_dev *a,
|
||||||
dist_a++;
|
dist_a++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow the connection if both devices are on a whitelisted root
|
||||||
|
* complex, but add an arbitary large value to the distance.
|
||||||
|
*/
|
||||||
|
if (root_complex_whitelist(provider) &&
|
||||||
|
root_complex_whitelist(client))
|
||||||
|
return 0x1000 + dist_a + dist_b;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
check_b_path_acs:
|
check_b_path_acs:
|
||||||
|
|
Loading…
Reference in New Issue