Commit | Line | Data |
---|---|---|
6ad11bc3 | 1 | /* |
8bb0daff | 2 | * drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c |
6ad11bc3 RC |
3 | * |
4 | * Copyright (C) 2011 Texas Instruments | |
5 | * Author: Rob Clark <rob.clark@linaro.org> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License version 2 as published by | |
9 | * the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include "omap_drv.h" | |
21 | ||
22 | #include <linux/dma-buf.h> | |
23 | ||
24 | static struct sg_table *omap_gem_map_dma_buf( | |
25 | struct dma_buf_attachment *attachment, | |
26 | enum dma_data_direction dir) | |
27 | { | |
28 | struct drm_gem_object *obj = attachment->dmabuf->priv; | |
29 | struct sg_table *sg; | |
30 | dma_addr_t paddr; | |
31 | int ret; | |
32 | ||
33 | sg = kzalloc(sizeof(*sg), GFP_KERNEL); | |
34 | if (!sg) | |
35 | return ERR_PTR(-ENOMEM); | |
36 | ||
37 | /* camera, etc, need physically contiguous.. but we need a | |
38 | * better way to know this.. | |
39 | */ | |
40 | ret = omap_gem_get_paddr(obj, &paddr, true); | |
41 | if (ret) | |
42 | goto out; | |
43 | ||
44 | ret = sg_alloc_table(sg, 1, GFP_KERNEL); | |
45 | if (ret) | |
46 | goto out; | |
47 | ||
48 | sg_init_table(sg->sgl, 1); | |
49 | sg_dma_len(sg->sgl) = obj->size; | |
50 | sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0); | |
51 | sg_dma_address(sg->sgl) = paddr; | |
52 | ||
8b6b569e RC |
53 | /* this should be after _get_paddr() to ensure we have pages attached */ |
54 | omap_gem_dma_sync(obj, dir); | |
55 | ||
6ad11bc3 | 56 | return sg; |
32ac1a52 CD |
57 | out: |
58 | kfree(sg); | |
59 | return ERR_PTR(ret); | |
6ad11bc3 RC |
60 | } |
61 | ||
62 | static void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, | |
63 | struct sg_table *sg, enum dma_data_direction dir) | |
64 | { | |
65 | struct drm_gem_object *obj = attachment->dmabuf->priv; | |
66 | omap_gem_put_paddr(obj); | |
67 | sg_free_table(sg); | |
68 | kfree(sg); | |
69 | } | |
70 | ||
71 | static void omap_gem_dmabuf_release(struct dma_buf *buffer) | |
72 | { | |
73 | struct drm_gem_object *obj = buffer->priv; | |
74 | /* release reference that was taken when dmabuf was exported | |
75 | * in omap_gem_prime_set().. | |
76 | */ | |
77 | drm_gem_object_unreference_unlocked(obj); | |
78 | } | |
79 | ||
80 | ||
81 | static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, | |
82 | size_t start, size_t len, enum dma_data_direction dir) | |
83 | { | |
84 | struct drm_gem_object *obj = buffer->priv; | |
85 | struct page **pages; | |
86 | if (omap_gem_flags(obj) & OMAP_BO_TILED) { | |
87 | /* TODO we would need to pin at least part of the buffer to | |
88 | * get de-tiled view. For now just reject it. | |
89 | */ | |
90 | return -ENOMEM; | |
91 | } | |
92 | /* make sure we have the pages: */ | |
93 | return omap_gem_get_pages(obj, &pages, true); | |
94 | } | |
95 | ||
96 | static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, | |
97 | size_t start, size_t len, enum dma_data_direction dir) | |
98 | { | |
99 | struct drm_gem_object *obj = buffer->priv; | |
100 | omap_gem_put_pages(obj); | |
101 | } | |
102 | ||
103 | ||
104 | static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer, | |
105 | unsigned long page_num) | |
106 | { | |
107 | struct drm_gem_object *obj = buffer->priv; | |
108 | struct page **pages; | |
109 | omap_gem_get_pages(obj, &pages, false); | |
8b6b569e | 110 | omap_gem_cpu_sync(obj, page_num); |
6ad11bc3 RC |
111 | return kmap_atomic(pages[page_num]); |
112 | } | |
113 | ||
114 | static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer, | |
115 | unsigned long page_num, void *addr) | |
116 | { | |
117 | kunmap_atomic(addr); | |
118 | } | |
119 | ||
120 | static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, | |
121 | unsigned long page_num) | |
122 | { | |
123 | struct drm_gem_object *obj = buffer->priv; | |
124 | struct page **pages; | |
125 | omap_gem_get_pages(obj, &pages, false); | |
8b6b569e | 126 | omap_gem_cpu_sync(obj, page_num); |
6ad11bc3 RC |
127 | return kmap(pages[page_num]); |
128 | } | |
129 | ||
130 | static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, | |
131 | unsigned long page_num, void *addr) | |
132 | { | |
133 | struct drm_gem_object *obj = buffer->priv; | |
134 | struct page **pages; | |
135 | omap_gem_get_pages(obj, &pages, false); | |
136 | kunmap(pages[page_num]); | |
137 | } | |
138 | ||
8b6b569e RC |
139 | static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, |
140 | struct vm_area_struct *vma) | |
141 | { | |
142 | struct drm_gem_object *obj = buffer->priv; | |
4368dd84 | 143 | struct drm_device *dev = obj->dev; |
8b6b569e RC |
144 | int ret = 0; |
145 | ||
146 | if (WARN_ON(!obj->filp)) | |
147 | return -EINVAL; | |
148 | ||
4368dd84 | 149 | mutex_lock(&dev->struct_mutex); |
bda3fdaa | 150 | ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma); |
4368dd84 | 151 | mutex_unlock(&dev->struct_mutex); |
bda3fdaa LP |
152 | if (ret < 0) |
153 | return ret; | |
8b6b569e RC |
154 | |
155 | return omap_gem_mmap_obj(obj, vma); | |
156 | } | |
157 | ||
6717cd29 | 158 | static struct dma_buf_ops omap_dmabuf_ops = { |
6ad11bc3 RC |
159 | .map_dma_buf = omap_gem_map_dma_buf, |
160 | .unmap_dma_buf = omap_gem_unmap_dma_buf, | |
161 | .release = omap_gem_dmabuf_release, | |
162 | .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, | |
163 | .end_cpu_access = omap_gem_dmabuf_end_cpu_access, | |
164 | .kmap_atomic = omap_gem_dmabuf_kmap_atomic, | |
165 | .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic, | |
166 | .kmap = omap_gem_dmabuf_kmap, | |
167 | .kunmap = omap_gem_dmabuf_kunmap, | |
8b6b569e | 168 | .mmap = omap_gem_dmabuf_mmap, |
6ad11bc3 RC |
169 | }; |
170 | ||
11d3d27b | 171 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, |
6ad11bc3 RC |
172 | struct drm_gem_object *obj, int flags) |
173 | { | |
3aac4502 | 174 | return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, flags, NULL); |
6ad11bc3 | 175 | } |
3080b838 | 176 | |
11d3d27b | 177 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, |
3080b838 RC |
178 | struct dma_buf *buffer) |
179 | { | |
180 | struct drm_gem_object *obj; | |
181 | ||
182 | /* is this one of own objects? */ | |
183 | if (buffer->ops == &omap_dmabuf_ops) { | |
184 | obj = buffer->priv; | |
185 | /* is it from our device? */ | |
186 | if (obj->dev == dev) { | |
be8a42ae SWK |
187 | /* |
188 | * Importing dmabuf exported from out own gem increases | |
189 | * refcount on gem itself instead of f_count of dmabuf. | |
190 | */ | |
3080b838 RC |
191 | drm_gem_object_reference(obj); |
192 | return obj; | |
193 | } | |
194 | } | |
195 | ||
196 | /* | |
197 | * TODO add support for importing buffers from other devices.. | |
198 | * for now we don't need this but would be nice to add eventually | |
199 | */ | |
200 | return ERR_PTR(-EINVAL); | |
201 | } |