p2pdma.c (3c53c6255d598db7084c5c3d7553d7200e857818) p2pdma.c (f6b6aefee70aa5261deec7feab80c249bf58397f)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * PCI Peer 2 Peer DMA support.
4 *
5 * Copyright (c) 2016-2018, Logan Gunthorpe
6 * Copyright (c) 2016-2017, Microsemi Corporation
7 * Copyright (c) 2017, Christoph Hellwig
8 * Copyright (c) 2018, Eideticom Inc.

--- 4 unchanged lines hidden (view full) ---

13#include <linux/pci-p2pdma.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/genalloc.h>
17#include <linux/memremap.h>
18#include <linux/percpu-refcount.h>
19#include <linux/random.h>
20#include <linux/seq_buf.h>
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * PCI Peer 2 Peer DMA support.
4 *
5 * Copyright (c) 2016-2018, Logan Gunthorpe
6 * Copyright (c) 2016-2017, Microsemi Corporation
7 * Copyright (c) 2017, Christoph Hellwig
8 * Copyright (c) 2018, Eideticom Inc.

--- 4 unchanged lines hidden (view full) ---

13#include <linux/pci-p2pdma.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/genalloc.h>
17#include <linux/memremap.h>
18#include <linux/percpu-refcount.h>
19#include <linux/random.h>
20#include <linux/seq_buf.h>
21#include <linux/iommu.h>
22
23struct pci_p2pdma {
21
22struct pci_p2pdma {
23 struct percpu_ref devmap_ref;
24 struct completion devmap_ref_done;
24 struct gen_pool *pool;
25 bool p2pmem_published;
26};
27
25 struct gen_pool *pool;
26 bool p2pmem_published;
27};
28
28struct p2pdma_pagemap {
29 struct dev_pagemap pgmap;
30 struct percpu_ref ref;
31 struct completion ref_done;
32};
33
34static ssize_t size_show(struct device *dev, struct device_attribute *attr,
35 char *buf)
36{
37 struct pci_dev *pdev = to_pci_dev(dev);
38 size_t size = 0;
39
40 if (pdev->p2pdma->pool)
41 size = gen_pool_size(pdev->p2pdma->pool);

--- 32 unchanged lines hidden (view full) ---

74 NULL,
75};
76
77static const struct attribute_group p2pmem_group = {
78 .attrs = p2pmem_attrs,
79 .name = "p2pmem",
80};
81
29static ssize_t size_show(struct device *dev, struct device_attribute *attr,
30 char *buf)
31{
32 struct pci_dev *pdev = to_pci_dev(dev);
33 size_t size = 0;
34
35 if (pdev->p2pdma->pool)
36 size = gen_pool_size(pdev->p2pdma->pool);

--- 32 unchanged lines hidden (view full) ---

69 NULL,
70};
71
72static const struct attribute_group p2pmem_group = {
73 .attrs = p2pmem_attrs,
74 .name = "p2pmem",
75};
76
82static struct p2pdma_pagemap *to_p2p_pgmap(struct percpu_ref *ref)
83{
84 return container_of(ref, struct p2pdma_pagemap, ref);
85}
86
87static void pci_p2pdma_percpu_release(struct percpu_ref *ref)
88{
77static void pci_p2pdma_percpu_release(struct percpu_ref *ref)
78{
89 struct p2pdma_pagemap *p2p_pgmap = to_p2p_pgmap(ref);
79 struct pci_p2pdma *p2p =
80 container_of(ref, struct pci_p2pdma, devmap_ref);
90
81
91 complete(&p2p_pgmap->ref_done);
82 complete_all(&p2p->devmap_ref_done);
92}
93
94static void pci_p2pdma_percpu_kill(struct percpu_ref *ref)
95{
83}
84
85static void pci_p2pdma_percpu_kill(struct percpu_ref *ref)
86{
87 /*
88 * pci_p2pdma_add_resource() may be called multiple times
89 * by a driver and may register the percpu_kill devm action multiple
90 * times. We only want the first action to actually kill the
91 * percpu_ref.
92 */
93 if (percpu_ref_is_dying(ref))
94 return;
95
96 percpu_ref_kill(ref);
97}
98
96 percpu_ref_kill(ref);
97}
98
99static void pci_p2pdma_percpu_cleanup(struct percpu_ref *ref)
100{
101 struct p2pdma_pagemap *p2p_pgmap = to_p2p_pgmap(ref);
102
103 wait_for_completion(&p2p_pgmap->ref_done);
104 percpu_ref_exit(&p2p_pgmap->ref);
105}
106
107static void pci_p2pdma_release(void *data)
108{
109 struct pci_dev *pdev = data;
99static void pci_p2pdma_release(void *data)
100{
101 struct pci_dev *pdev = data;
110 struct pci_p2pdma *p2pdma = pdev->p2pdma;
111
102
112 if (!p2pdma)
103 if (!pdev->p2pdma)
113 return;
114
104 return;
105
115 /* Flush and disable pci_alloc_p2p_mem() */
116 pdev->p2pdma = NULL;
117 synchronize_rcu();
106 wait_for_completion(&pdev->p2pdma->devmap_ref_done);
107 percpu_ref_exit(&pdev->p2pdma->devmap_ref);
118
108
119 gen_pool_destroy(p2pdma->pool);
109 gen_pool_destroy(pdev->p2pdma->pool);
120 sysfs_remove_group(&pdev->dev.kobj, &p2pmem_group);
110 sysfs_remove_group(&pdev->dev.kobj, &p2pmem_group);
111 pdev->p2pdma = NULL;
121}
122
123static int pci_p2pdma_setup(struct pci_dev *pdev)
124{
125 int error = -ENOMEM;
126 struct pci_p2pdma *p2p;
127
128 p2p = devm_kzalloc(&pdev->dev, sizeof(*p2p), GFP_KERNEL);
129 if (!p2p)
130 return -ENOMEM;
131
132 p2p->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(&pdev->dev));
133 if (!p2p->pool)
134 goto out;
135
112}
113
114static int pci_p2pdma_setup(struct pci_dev *pdev)
115{
116 int error = -ENOMEM;
117 struct pci_p2pdma *p2p;
118
119 p2p = devm_kzalloc(&pdev->dev, sizeof(*p2p), GFP_KERNEL);
120 if (!p2p)
121 return -ENOMEM;
122
123 p2p->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(&pdev->dev));
124 if (!p2p->pool)
125 goto out;
126
127 init_completion(&p2p->devmap_ref_done);
128 error = percpu_ref_init(&p2p->devmap_ref,
129 pci_p2pdma_percpu_release, 0, GFP_KERNEL);
130 if (error)
131 goto out_pool_destroy;
132
136 error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_release, pdev);
137 if (error)
138 goto out_pool_destroy;
139
140 pdev->p2pdma = p2p;
141
142 error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group);
143 if (error)

--- 17 unchanged lines hidden (view full) ---

161 * @offset: offset into the PCI BAR
162 *
163 * The memory will be given ZONE_DEVICE struct pages so that it may
164 * be used with any DMA request.
165 */
166int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
167 u64 offset)
168{
133 error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_release, pdev);
134 if (error)
135 goto out_pool_destroy;
136
137 pdev->p2pdma = p2p;
138
139 error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group);
140 if (error)

--- 17 unchanged lines hidden (view full) ---

158 * @offset: offset into the PCI BAR
159 *
160 * The memory will be given ZONE_DEVICE struct pages so that it may
161 * be used with any DMA request.
162 */
163int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
164 u64 offset)
165{
169 struct p2pdma_pagemap *p2p_pgmap;
170 struct dev_pagemap *pgmap;
171 void *addr;
172 int error;
173
174 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
175 return -EINVAL;
176
177 if (offset >= pci_resource_len(pdev, bar))

--- 6 unchanged lines hidden (view full) ---

184 return -EINVAL;
185
186 if (!pdev->p2pdma) {
187 error = pci_p2pdma_setup(pdev);
188 if (error)
189 return error;
190 }
191
166 struct dev_pagemap *pgmap;
167 void *addr;
168 int error;
169
170 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
171 return -EINVAL;
172
173 if (offset >= pci_resource_len(pdev, bar))

--- 6 unchanged lines hidden (view full) ---

180 return -EINVAL;
181
182 if (!pdev->p2pdma) {
183 error = pci_p2pdma_setup(pdev);
184 if (error)
185 return error;
186 }
187
192 p2p_pgmap = devm_kzalloc(&pdev->dev, sizeof(*p2p_pgmap), GFP_KERNEL);
193 if (!p2p_pgmap)
188 pgmap = devm_kzalloc(&pdev->dev, sizeof(*pgmap), GFP_KERNEL);
189 if (!pgmap)
194 return -ENOMEM;
195
190 return -ENOMEM;
191
196 init_completion(&p2p_pgmap->ref_done);
197 error = percpu_ref_init(&p2p_pgmap->ref,
198 pci_p2pdma_percpu_release, 0, GFP_KERNEL);
199 if (error)
200 goto pgmap_free;
201
202 pgmap = &p2p_pgmap->pgmap;
203
204 pgmap->res.start = pci_resource_start(pdev, bar) + offset;
205 pgmap->res.end = pgmap->res.start + size - 1;
206 pgmap->res.flags = pci_resource_flags(pdev, bar);
192 pgmap->res.start = pci_resource_start(pdev, bar) + offset;
193 pgmap->res.end = pgmap->res.start + size - 1;
194 pgmap->res.flags = pci_resource_flags(pdev, bar);
207 pgmap->ref = &p2p_pgmap->ref;
195 pgmap->ref = &pdev->p2pdma->devmap_ref;
208 pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
209 pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) -
210 pci_resource_start(pdev, bar);
211 pgmap->kill = pci_p2pdma_percpu_kill;
196 pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
197 pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) -
198 pci_resource_start(pdev, bar);
199 pgmap->kill = pci_p2pdma_percpu_kill;
212 pgmap->cleanup = pci_p2pdma_percpu_cleanup;
213
214 addr = devm_memremap_pages(&pdev->dev, pgmap);
215 if (IS_ERR(addr)) {
216 error = PTR_ERR(addr);
217 goto pgmap_free;
218 }
219
200
201 addr = devm_memremap_pages(&pdev->dev, pgmap);
202 if (IS_ERR(addr)) {
203 error = PTR_ERR(addr);
204 goto pgmap_free;
205 }
206
220 error = gen_pool_add_owner(pdev->p2pdma->pool, (unsigned long)addr,
207 error = gen_pool_add_virt(pdev->p2pdma->pool, (unsigned long)addr,
221 pci_bus_address(pdev, bar) + offset,
208 pci_bus_address(pdev, bar) + offset,
222 resource_size(&pgmap->res), dev_to_node(&pdev->dev),
223 &p2p_pgmap->ref);
209 resource_size(&pgmap->res), dev_to_node(&pdev->dev));
224 if (error)
210 if (error)
225 goto pages_free;
211 goto pgmap_free;
226
227 pci_info(pdev, "added peer-to-peer DMA memory %pR\n",
228 &pgmap->res);
229
230 return 0;
231
212
213 pci_info(pdev, "added peer-to-peer DMA memory %pR\n",
214 &pgmap->res);
215
216 return 0;
217
232pages_free:
233 devm_memunmap_pages(&pdev->dev, pgmap);
234pgmap_free:
218pgmap_free:
235 devm_kfree(&pdev->dev, p2p_pgmap);
219 devm_kfree(&pdev->dev, pgmap);
236 return error;
237}
238EXPORT_SYMBOL_GPL(pci_p2pdma_add_resource);
239
240/*
241 * Note this function returns the parent PCI device with a
220 return error;
221}
222EXPORT_SYMBOL_GPL(pci_p2pdma_add_resource);
223
224/*
225 * Note this function returns the parent PCI device with a
242 * reference taken. It is the caller's responsibily to drop
226 * reference taken. It is the caller's responsibility to drop
243 * the reference.
244 */
245static struct pci_dev *find_parent_pci_dev(struct device *dev)
246{
247 struct device *parent;
248
249 dev = get_device(dev);
250

--- 44 unchanged lines hidden (view full) ---

295 * complex and compare it to a whitelist of known good hardware.
296 */
297static bool root_complex_whitelist(struct pci_dev *dev)
298{
299 struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
300 struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
301 unsigned short vendor, device;
302
227 * the reference.
228 */
229static struct pci_dev *find_parent_pci_dev(struct device *dev)
230{
231 struct device *parent;
232
233 dev = get_device(dev);
234

--- 44 unchanged lines hidden (view full) ---

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
303 if (iommu_present(dev->dev.bus))
304 return false;
305
306 if (!root)
307 return false;
308
309 vendor = root->vendor;
310 device = root->device;
311 pci_dev_put(root);
312
313 /* AMD ZEN host bridges can do peer to peer */

--- 80 unchanged lines hidden (view full) ---

394 }
395
396 a = pci_upstream_bridge(a);
397 dist_a++;
398 }
399
400 /*
401 * Allow the connection if both devices are on a whitelisted root
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 */

--- 80 unchanged lines hidden (view full) ---

375 }
376
377 a = pci_upstream_bridge(a);
378 dist_a++;
379 }
380
381 /*
382 * Allow the connection if both devices are on a whitelisted root
402 * complex, but add an arbitary large value to the distance.
383 * complex, but add an arbitrary large value to the distance.
403 */
404 if (root_complex_whitelist(provider) &&
405 root_complex_whitelist(client))
406 return 0x1000 + dist_a + dist_b;
407
408 return -1;
409
410check_b_path_acs:

--- 42 unchanged lines hidden (view full) ---

453 }
454
455 kfree(acs_list.buffer);
456
457 return ret;
458}
459
460/**
384 */
385 if (root_complex_whitelist(provider) &&
386 root_complex_whitelist(client))
387 return 0x1000 + dist_a + dist_b;
388
389 return -1;
390
391check_b_path_acs:

--- 42 unchanged lines hidden (view full) ---

434 }
435
436 kfree(acs_list.buffer);
437
438 return ret;
439}
440
441/**
461 * pci_p2pdma_distance_many - Determive the cumulative distance between
442 * pci_p2pdma_distance_many - Determine the cumulative distance between
462 * a p2pdma provider and the clients in use.
463 * @provider: p2pdma provider to check against the client list
464 * @clients: array of devices to check (NULL-terminated)
465 * @num_clients: number of clients in the array
466 * @verbose: if true, print warnings for devices when we return -1
467 *
468 * Returns -1 if any of the clients are not compatible (behind the same
469 * root port as the provider), otherwise returns a positive number where

--- 129 unchanged lines hidden (view full) ---

599 * pci_alloc_p2p_mem - allocate peer-to-peer DMA memory
600 * @pdev: the device to allocate memory from
601 * @size: number of bytes to allocate
602 *
603 * Returns the allocated memory or NULL on error.
604 */
605void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
606{
443 * a p2pdma provider and the clients in use.
444 * @provider: p2pdma provider to check against the client list
445 * @clients: array of devices to check (NULL-terminated)
446 * @num_clients: number of clients in the array
447 * @verbose: if true, print warnings for devices when we return -1
448 *
449 * Returns -1 if any of the clients are not compatible (behind the same
450 * root port as the provider), otherwise returns a positive number where

--- 129 unchanged lines hidden (view full) ---

580 * pci_alloc_p2p_mem - allocate peer-to-peer DMA memory
581 * @pdev: the device to allocate memory from
582 * @size: number of bytes to allocate
583 *
584 * Returns the allocated memory or NULL on error.
585 */
586void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
587{
607 void *ret = NULL;
608 struct percpu_ref *ref;
588 void *ret;
609
589
610 /*
611 * Pairs with synchronize_rcu() in pci_p2pdma_release() to
612 * ensure pdev->p2pdma is non-NULL for the duration of the
613 * read-lock.
614 */
615 rcu_read_lock();
616 if (unlikely(!pdev->p2pdma))
590 if (unlikely(!pdev->p2pdma))
617 goto out;
591 return NULL;
618
592
619 ret = (void *)gen_pool_alloc_owner(pdev->p2pdma->pool, size,
620 (void **) &ref);
621 if (!ret)
622 goto out;
593 if (unlikely(!percpu_ref_tryget_live(&pdev->p2pdma->devmap_ref)))
594 return NULL;
623
595
624 if (unlikely(!percpu_ref_tryget_live(ref))) {
625 gen_pool_free(pdev->p2pdma->pool, (unsigned long) ret, size);
626 ret = NULL;
627 goto out;
628 }
629out:
630 rcu_read_unlock();
596 ret = (void *)gen_pool_alloc(pdev->p2pdma->pool, size);
597
598 if (unlikely(!ret))
599 percpu_ref_put(&pdev->p2pdma->devmap_ref);
600
631 return ret;
632}
633EXPORT_SYMBOL_GPL(pci_alloc_p2pmem);
634
635/**
636 * pci_free_p2pmem - free peer-to-peer DMA memory
637 * @pdev: the device the memory was allocated from
638 * @addr: address of the memory that was allocated
639 * @size: number of bytes that were allocated
640 */
641void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
642{
601 return ret;
602}
603EXPORT_SYMBOL_GPL(pci_alloc_p2pmem);
604
605/**
606 * pci_free_p2pmem - free peer-to-peer DMA memory
607 * @pdev: the device the memory was allocated from
608 * @addr: address of the memory that was allocated
609 * @size: number of bytes that were allocated
610 */
611void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
612{
643 struct percpu_ref *ref;
644
645 gen_pool_free_owner(pdev->p2pdma->pool, (uintptr_t)addr, size,
646 (void **) &ref);
647 percpu_ref_put(ref);
613 gen_pool_free(pdev->p2pdma->pool, (uintptr_t)addr, size);
614 percpu_ref_put(&pdev->p2pdma->devmap_ref);
648}
649EXPORT_SYMBOL_GPL(pci_free_p2pmem);
650
651/**
652 * pci_virt_to_bus - return the PCI bus address for a given virtual
653 * address obtained with pci_alloc_p2pmem()
654 * @pdev: the device the memory was allocated from
655 * @addr: address of the memory that was allocated

--- 209 unchanged lines hidden ---
615}
616EXPORT_SYMBOL_GPL(pci_free_p2pmem);
617
618/**
619 * pci_virt_to_bus - return the PCI bus address for a given virtual
620 * address obtained with pci_alloc_p2pmem()
621 * @pdev: the device the memory was allocated from
622 * @addr: address of the memory that was allocated

--- 209 unchanged lines hidden ---