aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2019-05-13 19:34:33 -0400
committerBjorn Helgaas <bhelgaas@google.com>2019-05-13 19:34:33 -0400
commit292c9396541399b83a4f6d9141b919cb29275c28 (patch)
treeb2ced4e9a473758296332fe0a69a74eaf7b1c1e1
parent09fdd75c1814faecf6623a33e9ad91c5aee08bdb (diff)
parent0f97da83102610db886e8b688b9029e080e6d511 (diff)
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
-rw-r--r--drivers/pci/p2pdma.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index c52298d76e64..742928d0053e 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -275,6 +275,30 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
275} 275}
276 276
277/* 277/*
278 * If we can't find a common upstream bridge take a look at the root
279 * complex and compare it to a whitelist of known good hardware.
280 */
281static bool root_complex_whitelist(struct pci_dev *dev)
282{
283 struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
284 struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
285 unsigned short vendor, device;
286
287 if (!root)
288 return false;
289
290 vendor = root->vendor;
291 device = root->device;
292 pci_dev_put(root);
293
294 /* AMD ZEN host bridges can do peer to peer */
295 if (vendor == PCI_VENDOR_ID_AMD && device == 0x1450)
296 return true;
297
298 return false;
299}
300
301/*
278 * Find the distance through the nearest common upstream bridge between 302 * Find the distance through the nearest common upstream bridge between
279 * two PCI devices. 303 * two PCI devices.
280 * 304 *
@@ -317,13 +341,13 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
317 * In this case, a list of all infringing bridge addresses will be 341 * In this case, a list of all infringing bridge addresses will be
318 * populated in acs_list (assuming it's non-null) for printk purposes. 342 * populated in acs_list (assuming it's non-null) for printk purposes.
319 */ 343 */
320static int upstream_bridge_distance(struct pci_dev *a, 344static int upstream_bridge_distance(struct pci_dev *provider,
321 struct pci_dev *b, 345 struct pci_dev *client,
322 struct seq_buf *acs_list) 346 struct seq_buf *acs_list)
323{ 347{
348 struct pci_dev *a = provider, *b = client, *bb;
324 int dist_a = 0; 349 int dist_a = 0;
325 int dist_b = 0; 350 int dist_b = 0;
326 struct pci_dev *bb = NULL;
327 int acs_cnt = 0; 351 int acs_cnt = 0;
328 352
329 /* 353 /*
@@ -354,6 +378,14 @@ static int upstream_bridge_distance(struct pci_dev *a,
354 dist_a++; 378 dist_a++;
355 } 379 }
356 380
381 /*
382 * Allow the connection if both devices are on a whitelisted root
383 * complex, but add an arbitary large value to the distance.
384 */
385 if (root_complex_whitelist(provider) &&
386 root_complex_whitelist(client))
387 return 0x1000 + dist_a + dist_b;
388
357 return -1; 389 return -1;
358 390
359check_b_path_acs: 391check_b_path_acs: