Skip to content

Commit 22b33e8

Browse files
committed
nouveau: add PRIME support
This adds prime->fd and fd->prime support to nouveau, it passes the SG object to TTM, and then populates the GART entries using it. v2: add stubbed kmap + use new function to fill out pages array for faulting + add reimport test. Reviewed-by: Alex Deucher <[email protected]> Signed-off-by: Dave Airlie <[email protected]>
1 parent 129b78b commit 22b33e8

16 files changed

+296
-25
lines changed

drivers/gpu/drm/nouveau/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
3737
nv50_calc.o \
3838
nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
3939
nv50_vram.o nvc0_vram.o \
40-
nv50_vm.o nvc0_vm.o
40+
nv50_vm.o nvc0_vm.o nouveau_prime.o
4141

4242
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
4343
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o

drivers/gpu/drm/nouveau/nouveau_bo.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,17 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
8989
int
9090
nouveau_bo_new(struct drm_device *dev, int size, int align,
9191
uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
92+
struct sg_table *sg,
9293
struct nouveau_bo **pnvbo)
9394
{
9495
struct drm_nouveau_private *dev_priv = dev->dev_private;
9596
struct nouveau_bo *nvbo;
9697
size_t acc_size;
9798
int ret;
99+
int type = ttm_bo_type_device;
100+
101+
if (sg)
102+
type = ttm_bo_type_sg;
98103

99104
nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
100105
if (!nvbo)
@@ -120,8 +125,8 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
120125
sizeof(struct nouveau_bo));
121126

122127
ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
123-
ttm_bo_type_device, &nvbo->placement,
124-
align >> PAGE_SHIFT, 0, false, NULL, acc_size, NULL,
128+
type, &nvbo->placement,
129+
align >> PAGE_SHIFT, 0, false, NULL, acc_size, sg,
125130
nouveau_bo_del_ttm);
126131
if (ret) {
127132
/* ttm will call nouveau_bo_del_ttm if it fails.. */
@@ -817,9 +822,14 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
817822
} else
818823
if (new_mem && new_mem->mem_type == TTM_PL_TT &&
819824
nvbo->page_shift == vma->vm->spg_shift) {
820-
nouveau_vm_map_sg(vma, 0, new_mem->
821-
num_pages << PAGE_SHIFT,
822-
new_mem->mm_node);
825+
if (((struct nouveau_mem *)new_mem->mm_node)->sg)
826+
nouveau_vm_map_sg_table(vma, 0, new_mem->
827+
num_pages << PAGE_SHIFT,
828+
new_mem->mm_node);
829+
else
830+
nouveau_vm_map_sg(vma, 0, new_mem->
831+
num_pages << PAGE_SHIFT,
832+
new_mem->mm_node);
823833
} else {
824834
nouveau_vm_unmap(vma);
825835
}
@@ -1058,10 +1068,19 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
10581068
struct drm_device *dev;
10591069
unsigned i;
10601070
int r;
1071+
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
10611072

10621073
if (ttm->state != tt_unpopulated)
10631074
return 0;
10641075

1076+
if (slave && ttm->sg) {
1077+
/* make userspace faulting work */
1078+
drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
1079+
ttm_dma->dma_address, ttm->num_pages);
1080+
ttm->state = tt_unbound;
1081+
return 0;
1082+
}
1083+
10651084
dev_priv = nouveau_bdev(ttm->bdev);
10661085
dev = dev_priv->dev;
10671086

@@ -1106,6 +1125,10 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
11061125
struct drm_nouveau_private *dev_priv;
11071126
struct drm_device *dev;
11081127
unsigned i;
1128+
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
1129+
1130+
if (slave)
1131+
return;
11091132

11101133
dev_priv = nouveau_bdev(ttm->bdev);
11111134
dev = dev_priv->dev;
@@ -1181,9 +1204,12 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
11811204

11821205
if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
11831206
nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
1184-
else
1185-
if (nvbo->bo.mem.mem_type == TTM_PL_TT)
1186-
nouveau_vm_map_sg(vma, 0, size, node);
1207+
else if (nvbo->bo.mem.mem_type == TTM_PL_TT) {
1208+
if (node->sg)
1209+
nouveau_vm_map_sg_table(vma, 0, size, node);
1210+
else
1211+
nouveau_vm_map_sg(vma, 0, size, node);
1212+
}
11871213

11881214
list_add_tail(&vma->head, &nvbo->vma_list);
11891215
vma->refcount = 1;

drivers/gpu/drm/nouveau/nouveau_channel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ nouveau_channel_pushbuf_init(struct nouveau_channel *chan)
3838
int ret;
3939

4040
/* allocate buffer object */
41-
ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, &chan->pushbuf_bo);
41+
ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, NULL, &chan->pushbuf_bo);
4242
if (ret)
4343
goto out;
4444

drivers/gpu/drm/nouveau/nouveau_drv.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ static struct drm_driver driver = {
408408
.driver_features =
409409
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
410410
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
411-
DRIVER_MODESET,
411+
DRIVER_MODESET | DRIVER_PRIME,
412412
.load = nouveau_load,
413413
.firstopen = nouveau_firstopen,
414414
.lastclose = nouveau_lastclose,
@@ -430,6 +430,12 @@ static struct drm_driver driver = {
430430
.reclaim_buffers = drm_core_reclaim_buffers,
431431
.ioctls = nouveau_ioctls,
432432
.fops = &nouveau_driver_fops,
433+
434+
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
435+
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
436+
.gem_prime_export = nouveau_gem_prime_export,
437+
.gem_prime_import = nouveau_gem_prime_import,
438+
433439
.gem_init_object = nouveau_gem_object_new,
434440
.gem_free_object = nouveau_gem_object_del,
435441
.gem_open_object = nouveau_gem_object_open,

drivers/gpu/drm/nouveau/nouveau_drv.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ struct nouveau_mem {
8686
u32 memtype;
8787
u64 offset;
8888
u64 size;
89+
struct sg_table *sg;
8990
};
9091

9192
struct nouveau_tile_reg {
@@ -1416,7 +1417,9 @@ extern int nv04_crtc_create(struct drm_device *, int index);
14161417
extern struct ttm_bo_driver nouveau_bo_driver;
14171418
extern int nouveau_bo_new(struct drm_device *, int size, int align,
14181419
uint32_t flags, uint32_t tile_mode,
1419-
uint32_t tile_flags, struct nouveau_bo **);
1420+
uint32_t tile_flags,
1421+
struct sg_table *sg,
1422+
struct nouveau_bo **);
14201423
extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
14211424
extern int nouveau_bo_unpin(struct nouveau_bo *);
14221425
extern int nouveau_bo_map(struct nouveau_bo *);
@@ -1501,6 +1504,11 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
15011504
extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
15021505
struct drm_file *);
15031506

1507+
extern struct dma_buf *nouveau_gem_prime_export(struct drm_device *dev,
1508+
struct drm_gem_object *obj, int flags);
1509+
extern struct drm_gem_object *nouveau_gem_prime_import(struct drm_device *dev,
1510+
struct dma_buf *dma_buf);
1511+
15041512
/* nouveau_display.c */
15051513
int nouveau_display_create(struct drm_device *dev);
15061514
void nouveau_display_destroy(struct drm_device *dev);

drivers/gpu/drm/nouveau/nouveau_fence.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ nouveau_fence_init(struct drm_device *dev)
573573
/* Create a shared VRAM heap for cross-channel sync. */
574574
if (USE_SEMA(dev)) {
575575
ret = nouveau_bo_new(dev, size, 0, TTM_PL_FLAG_VRAM,
576-
0, 0, &dev_priv->fence.bo);
576+
0, 0, NULL, &dev_priv->fence.bo);
577577
if (ret)
578578
return ret;
579579

drivers/gpu/drm/nouveau/nouveau_gem.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2424
*
2525
*/
26+
#include <linux/dma-buf.h>
2627
#include "drmP.h"
2728
#include "drm.h"
2829

@@ -53,6 +54,9 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
5354
nouveau_bo_unpin(nvbo);
5455
}
5556

57+
if (gem->import_attach)
58+
drm_prime_gem_destroy(gem, nvbo->bo.sg);
59+
5660
ttm_bo_unref(&bo);
5761

5862
drm_gem_object_release(gem);
@@ -139,7 +143,7 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain,
139143
flags |= TTM_PL_FLAG_SYSTEM;
140144

141145
ret = nouveau_bo_new(dev, size, align, flags, tile_mode,
142-
tile_flags, pnvbo);
146+
tile_flags, NULL, pnvbo);
143147
if (ret)
144148
return ret;
145149
nvbo = *pnvbo;

drivers/gpu/drm/nouveau/nouveau_mem.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ nouveau_mem_vram_init(struct drm_device *dev)
416416

417417
if (dev_priv->card_type < NV_50) {
418418
ret = nouveau_bo_new(dev, 256*1024, 0, TTM_PL_FLAG_VRAM,
419-
0, 0, &dev_priv->vga_ram);
419+
0, 0, NULL, &dev_priv->vga_ram);
420420
if (ret == 0)
421421
ret = nouveau_bo_pin(dev_priv->vga_ram,
422422
TTM_PL_FLAG_VRAM);
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
2+
#include "drmP.h"
3+
#include "drm.h"
4+
5+
#include "nouveau_drv.h"
6+
#include "nouveau_drm.h"
7+
#include "nouveau_dma.h"
8+
9+
#include <linux/dma-buf.h>
10+
11+
static struct sg_table *nouveau_gem_map_dma_buf(struct dma_buf_attachment *attachment,
12+
enum dma_data_direction dir)
13+
{
14+
struct nouveau_bo *nvbo = attachment->dmabuf->priv;
15+
struct drm_device *dev = nvbo->gem->dev;
16+
int npages = nvbo->bo.num_pages;
17+
struct sg_table *sg;
18+
int nents;
19+
20+
mutex_lock(&dev->struct_mutex);
21+
sg = drm_prime_pages_to_sg(nvbo->bo.ttm->pages, npages);
22+
nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
23+
mutex_unlock(&dev->struct_mutex);
24+
return sg;
25+
}
26+
27+
static void nouveau_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
28+
struct sg_table *sg, enum dma_data_direction dir)
29+
{
30+
dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
31+
sg_free_table(sg);
32+
kfree(sg);
33+
}
34+
35+
static void nouveau_gem_dmabuf_release(struct dma_buf *dma_buf)
36+
{
37+
struct nouveau_bo *nvbo = dma_buf->priv;
38+
39+
if (nvbo->gem->export_dma_buf == dma_buf) {
40+
nvbo->gem->export_dma_buf = NULL;
41+
drm_gem_object_unreference_unlocked(nvbo->gem);
42+
}
43+
}
44+
45+
static void *nouveau_gem_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
46+
{
47+
return NULL;
48+
}
49+
50+
static void nouveau_gem_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
51+
{
52+
53+
}
54+
static void *nouveau_gem_kmap(struct dma_buf *dma_buf, unsigned long page_num)
55+
{
56+
return NULL;
57+
}
58+
59+
static void nouveau_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
60+
{
61+
62+
}
63+
64+
struct dma_buf_ops nouveau_dmabuf_ops = {
65+
.map_dma_buf = nouveau_gem_map_dma_buf,
66+
.unmap_dma_buf = nouveau_gem_unmap_dma_buf,
67+
.release = nouveau_gem_dmabuf_release,
68+
.kmap = nouveau_gem_kmap,
69+
.kmap_atomic = nouveau_gem_kmap_atomic,
70+
.kunmap = nouveau_gem_kunmap,
71+
.kunmap_atomic = nouveau_gem_kunmap_atomic,
72+
};
73+
74+
static int
75+
nouveau_prime_new(struct drm_device *dev,
76+
size_t size,
77+
struct sg_table *sg,
78+
struct nouveau_bo **pnvbo)
79+
{
80+
struct nouveau_bo *nvbo;
81+
u32 flags = 0;
82+
int ret;
83+
84+
flags = TTM_PL_FLAG_TT;
85+
86+
ret = nouveau_bo_new(dev, size, 0, flags, 0, 0,
87+
sg, pnvbo);
88+
if (ret)
89+
return ret;
90+
nvbo = *pnvbo;
91+
92+
/* we restrict allowed domains on nv50+ to only the types
93+
* that were requested at creation time. not possibly on
94+
* earlier chips without busting the ABI.
95+
*/
96+
nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART;
97+
nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
98+
if (!nvbo->gem) {
99+
nouveau_bo_ref(NULL, pnvbo);
100+
return -ENOMEM;
101+
}
102+
103+
nvbo->gem->driver_private = nvbo;
104+
return 0;
105+
}
106+
107+
struct dma_buf *nouveau_gem_prime_export(struct drm_device *dev,
108+
struct drm_gem_object *obj, int flags)
109+
{
110+
struct nouveau_bo *nvbo = nouveau_gem_object(obj);
111+
int ret = 0;
112+
113+
/* pin buffer into GTT */
114+
ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT);
115+
if (ret)
116+
return ERR_PTR(-EINVAL);
117+
118+
return dma_buf_export(nvbo, &nouveau_dmabuf_ops, obj->size, flags);
119+
}
120+
121+
struct drm_gem_object *nouveau_gem_prime_import(struct drm_device *dev,
122+
struct dma_buf *dma_buf)
123+
{
124+
struct dma_buf_attachment *attach;
125+
struct sg_table *sg;
126+
struct nouveau_bo *nvbo;
127+
int ret;
128+
129+
if (dma_buf->ops == &nouveau_dmabuf_ops) {
130+
nvbo = dma_buf->priv;
131+
if (nvbo->gem) {
132+
if (nvbo->gem->dev == dev) {
133+
drm_gem_object_reference(nvbo->gem);
134+
return nvbo->gem;
135+
}
136+
}
137+
}
138+
/* need to attach */
139+
attach = dma_buf_attach(dma_buf, dev->dev);
140+
if (IS_ERR(attach))
141+
return ERR_PTR(PTR_ERR(attach));
142+
143+
sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
144+
if (IS_ERR(sg)) {
145+
ret = PTR_ERR(sg);
146+
goto fail_detach;
147+
}
148+
149+
ret = nouveau_prime_new(dev, dma_buf->size, sg, &nvbo);
150+
if (ret)
151+
goto fail_unmap;
152+
153+
nvbo->gem->import_attach = attach;
154+
155+
return nvbo->gem;
156+
157+
fail_unmap:
158+
dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
159+
fail_detach:
160+
dma_buf_detach(dma_buf, attach);
161+
return ERR_PTR(ret);
162+
}
163+

drivers/gpu/drm/nouveau/nouveau_sgdma.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,10 @@ nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
290290
struct nouveau_mem *node = mem->mm_node;
291291

292292
/* noop: bound in move_notify() */
293-
node->pages = nvbe->ttm.dma_address;
293+
if (ttm->sg) {
294+
node->sg = ttm->sg;
295+
} else
296+
node->pages = nvbe->ttm.dma_address;
294297
return 0;
295298
}
296299

0 commit comments

Comments
 (0)