Skip to content

Commit 1286ff7

Browse files
danvetairlied
authored andcommitted
i915: add dmabuf/prime buffer sharing support.
This adds handle->fd and fd->handle support to i915, this is to allow for offloading of rendering in one direction and outputs in the other. v2 from Daniel Vetter: - fixup conflicts with the prepare/finish gtt prep work. - implement ppgtt binding support. Note that we have squat i-g-t testcoverage for any of the lifetime and access rules dma_buf/prime support brings along. And there are quite a few intricate situations here. Also note that the integration with the existing code is a bit hackish, especially around get_gtt_pages and put_gtt_pages. It imo would be easier with the prep code from Chris Wilson's unbound series, but that is for 3.6. Also note that I didn't bother to put the new prepare/finish gtt hooks to good use by moving the dma_buf_map/unmap_attachment calls in there (like we've originally planned for). Last but not least this patch is only compile-tested, but I've changed very little compared to Dave Airlie's version. So there's a decent chance v2 on drm-next works as well as v1 on 3.4-rc. v3: Right when I've hit sent I've noticed that I've screwed up one obj->sg_list (for dmar support) and obj->sg_table (for prime support) disdinction. We should be able to merge these 2 paths, but that's material for another patch. v4: fix the error reporting bugs pointed out by ickle. v5: fix another error, and stop non-gtt mmaps on shared objects stop pread/pwrite on imported objects, add fake kmap Signed-off-by: Dave Airlie <[email protected]> Signed-Off-by: Daniel Vetter <[email protected]>
1 parent 22b33e8 commit 1286ff7

File tree

6 files changed

+239
-6
lines changed

6 files changed

+239
-6
lines changed

drivers/gpu/drm/i915/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
3838
dvo_ch7017.o \
3939
dvo_ivch.o \
4040
dvo_tfp410.o \
41-
dvo_sil164.o
41+
dvo_sil164.o \
42+
i915_gem_dmabuf.o
4243

4344
i915-$(CONFIG_COMPAT) += i915_ioc32.o
4445

drivers/gpu/drm/i915/i915_drv.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ static struct drm_driver driver = {
10391039
*/
10401040
.driver_features =
10411041
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
1042-
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
1042+
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME,
10431043
.load = i915_driver_load,
10441044
.unload = i915_driver_unload,
10451045
.open = i915_driver_open,
@@ -1062,6 +1062,12 @@ static struct drm_driver driver = {
10621062
.gem_init_object = i915_gem_init_object,
10631063
.gem_free_object = i915_gem_free_object,
10641064
.gem_vm_ops = &i915_gem_vm_ops,
1065+
1066+
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
1067+
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
1068+
.gem_prime_export = i915_gem_prime_export,
1069+
.gem_prime_import = i915_gem_prime_import,
1070+
10651071
.dumb_create = i915_gem_dumb_create,
10661072
.dumb_map_offset = i915_gem_mmap_gtt,
10671073
.dumb_destroy = i915_gem_dumb_destroy,

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,8 @@ struct drm_i915_gem_object {
940940
struct scatterlist *sg_list;
941941
int num_sg;
942942

943+
/* prime dma-buf support */
944+
struct sg_table *sg_table;
943945
/**
944946
* Used for performing relocations during execbuffer insertion.
945947
*/
@@ -1245,6 +1247,8 @@ int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj);
12451247
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
12461248
void i915_gem_lastclose(struct drm_device *dev);
12471249

1250+
int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
1251+
gfp_t gfpmask);
12481252
int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
12491253
int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj);
12501254
int i915_gem_object_sync(struct drm_i915_gem_object *obj,
@@ -1342,6 +1346,13 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
13421346
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
13431347
enum i915_cache_level cache_level);
13441348

1349+
struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
1350+
struct dma_buf *dma_buf);
1351+
1352+
struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
1353+
struct drm_gem_object *gem_obj, int flags);
1354+
1355+
13451356
/* i915_gem_gtt.c */
13461357
int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
13471358
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);

drivers/gpu/drm/i915/i915_gem.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <linux/slab.h>
3636
#include <linux/swap.h>
3737
#include <linux/pci.h>
38+
#include <linux/dma-buf.h>
3839

3940
static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj);
4041
static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
@@ -538,6 +539,14 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
538539
goto out;
539540
}
540541

542+
/* prime objects have no backing filp to GEM pread/pwrite
543+
* pages from.
544+
*/
545+
if (!obj->base.filp) {
546+
ret = -EINVAL;
547+
goto out;
548+
}
549+
541550
trace_i915_gem_object_pread(obj, args->offset, args->size);
542551

543552
ret = i915_gem_shmem_pread(dev, obj, args, file);
@@ -880,6 +889,14 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
880889
goto out;
881890
}
882891

892+
/* prime objects have no backing filp to GEM pread/pwrite
893+
* pages from.
894+
*/
895+
if (!obj->base.filp) {
896+
ret = -EINVAL;
897+
goto out;
898+
}
899+
883900
trace_i915_gem_object_pwrite(obj, args->offset, args->size);
884901

885902
ret = -EFAULT;
@@ -1021,6 +1038,14 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
10211038
if (obj == NULL)
10221039
return -ENOENT;
10231040

1041+
/* prime objects have no backing filp to GEM mmap
1042+
* pages from.
1043+
*/
1044+
if (!obj->filp) {
1045+
drm_gem_object_unreference_unlocked(obj);
1046+
return -EINVAL;
1047+
}
1048+
10241049
addr = vm_mmap(obj->filp, 0, args->size,
10251050
PROT_READ | PROT_WRITE, MAP_SHARED,
10261051
args->offset);
@@ -1302,8 +1327,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
13021327
return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
13031328
}
13041329

1305-
1306-
static int
1330+
int
13071331
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
13081332
gfp_t gfpmask)
13091333
{
@@ -1312,6 +1336,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
13121336
struct inode *inode;
13131337
struct page *page;
13141338

1339+
if (obj->pages || obj->sg_table)
1340+
return 0;
1341+
13151342
/* Get the list of pages out of our struct file. They'll be pinned
13161343
* at this point until we release them.
13171344
*/
@@ -1353,6 +1380,9 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
13531380
int page_count = obj->base.size / PAGE_SIZE;
13541381
int i;
13551382

1383+
if (!obj->pages)
1384+
return;
1385+
13561386
BUG_ON(obj->madv == __I915_MADV_PURGED);
13571387

13581388
if (i915_gem_object_needs_bit17_swizzle(obj))
@@ -3327,6 +3357,9 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
33273357

33283358
trace_i915_gem_object_destroy(obj);
33293359

3360+
if (gem_obj->import_attach)
3361+
drm_prime_gem_destroy(gem_obj, obj->sg_table);
3362+
33303363
if (obj->phys_obj)
33313364
i915_gem_detach_phys_object(dev, obj);
33323365

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright 2012 Red Hat Inc
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a
5+
* copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the
9+
* Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice (including the next
12+
* paragraph) shall be included in all copies or substantial portions of the
13+
* Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+
* DEALINGS IN THE SOFTWARE.
22+
*
23+
* Authors:
24+
* Dave Airlie <[email protected]>
25+
*/
26+
#include "drmP.h"
27+
#include "i915_drv.h"
28+
#include <linux/dma-buf.h>
29+
30+
struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
31+
enum dma_data_direction dir)
32+
{
33+
struct drm_i915_gem_object *obj = attachment->dmabuf->priv;
34+
struct drm_device *dev = obj->base.dev;
35+
int npages = obj->base.size / PAGE_SIZE;
36+
struct sg_table *sg = NULL;
37+
int ret;
38+
int nents;
39+
40+
ret = i915_mutex_lock_interruptible(dev);
41+
if (ret)
42+
return ERR_PTR(ret);
43+
44+
if (!obj->pages) {
45+
ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
46+
if (ret)
47+
goto out;
48+
}
49+
50+
/* link the pages into an SG then map the sg */
51+
sg = drm_prime_pages_to_sg(obj->pages, npages);
52+
nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
53+
out:
54+
mutex_unlock(&dev->struct_mutex);
55+
return sg;
56+
}
57+
58+
void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
59+
struct sg_table *sg, enum dma_data_direction dir)
60+
{
61+
dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
62+
sg_free_table(sg);
63+
kfree(sg);
64+
}
65+
66+
void i915_gem_dmabuf_release(struct dma_buf *dma_buf)
67+
{
68+
struct drm_i915_gem_object *obj = dma_buf->priv;
69+
70+
if (obj->base.export_dma_buf == dma_buf) {
71+
/* drop the reference on the export fd holds */
72+
obj->base.export_dma_buf = NULL;
73+
drm_gem_object_unreference_unlocked(&obj->base);
74+
}
75+
}
76+
77+
static void *i915_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
78+
{
79+
return NULL;
80+
}
81+
82+
static void i915_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
83+
{
84+
85+
}
86+
static void *i915_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
87+
{
88+
return NULL;
89+
}
90+
91+
static void i915_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
92+
{
93+
94+
}
95+
96+
struct dma_buf_ops i915_dmabuf_ops = {
97+
.map_dma_buf = i915_gem_map_dma_buf,
98+
.unmap_dma_buf = i915_gem_unmap_dma_buf,
99+
.release = i915_gem_dmabuf_release,
100+
.kmap = i915_gem_dmabuf_kmap,
101+
.kmap_atomic = i915_gem_dmabuf_kmap_atomic,
102+
.kunmap = i915_gem_dmabuf_kunmap,
103+
.kunmap_atomic = i915_gem_dmabuf_kunmap_atomic,
104+
};
105+
106+
struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
107+
struct drm_gem_object *gem_obj, int flags)
108+
{
109+
struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
110+
111+
return dma_buf_export(obj, &i915_dmabuf_ops,
112+
obj->base.size, 0600);
113+
}
114+
115+
struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
116+
struct dma_buf *dma_buf)
117+
{
118+
struct dma_buf_attachment *attach;
119+
struct sg_table *sg;
120+
struct drm_i915_gem_object *obj;
121+
int npages;
122+
int size;
123+
int ret;
124+
125+
/* is this one of own objects? */
126+
if (dma_buf->ops == &i915_dmabuf_ops) {
127+
obj = dma_buf->priv;
128+
/* is it from our device? */
129+
if (obj->base.dev == dev) {
130+
drm_gem_object_reference(&obj->base);
131+
return &obj->base;
132+
}
133+
}
134+
135+
/* need to attach */
136+
attach = dma_buf_attach(dma_buf, dev->dev);
137+
if (IS_ERR(attach))
138+
return ERR_CAST(attach);
139+
140+
sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
141+
if (IS_ERR(sg)) {
142+
ret = PTR_ERR(sg);
143+
goto fail_detach;
144+
}
145+
146+
size = dma_buf->size;
147+
npages = size / PAGE_SIZE;
148+
149+
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
150+
if (obj == NULL) {
151+
ret = -ENOMEM;
152+
goto fail_unmap;
153+
}
154+
155+
ret = drm_gem_private_object_init(dev, &obj->base, size);
156+
if (ret) {
157+
kfree(obj);
158+
goto fail_unmap;
159+
}
160+
161+
obj->sg_table = sg;
162+
obj->base.import_attach = attach;
163+
164+
return &obj->base;
165+
166+
fail_unmap:
167+
dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
168+
fail_detach:
169+
dma_buf_detach(dma_buf, attach);
170+
return ERR_PTR(ret);
171+
}

drivers/gpu/drm/i915/i915_gem_gtt.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,13 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
267267
BUG();
268268
}
269269

270-
if (dev_priv->mm.gtt->needs_dmar) {
270+
if (obj->sg_table) {
271+
i915_ppgtt_insert_sg_entries(ppgtt,
272+
obj->sg_table->sgl,
273+
obj->sg_table->nents,
274+
obj->gtt_space->start >> PAGE_SHIFT,
275+
pte_flags);
276+
} else if (dev_priv->mm.gtt->needs_dmar) {
271277
BUG_ON(!obj->sg_list);
272278

273279
i915_ppgtt_insert_sg_entries(ppgtt,
@@ -371,7 +377,12 @@ void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
371377
struct drm_i915_private *dev_priv = dev->dev_private;
372378
unsigned int agp_type = cache_level_to_agp_type(dev, cache_level);
373379

374-
if (dev_priv->mm.gtt->needs_dmar) {
380+
if (obj->sg_table) {
381+
intel_gtt_insert_sg_entries(obj->sg_table->sgl,
382+
obj->sg_table->nents,
383+
obj->gtt_space->start >> PAGE_SHIFT,
384+
agp_type);
385+
} else if (dev_priv->mm.gtt->needs_dmar) {
375386
BUG_ON(!obj->sg_list);
376387

377388
intel_gtt_insert_sg_entries(obj->sg_list,

0 commit comments

Comments
 (0)