Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * udl_dmabuf.c
  3 *
  4 * Copyright (c) 2014 The Chromium OS Authors
  5 *
  6 * This program is free software; you can redistribute  it and/or modify it
  7 * under  the terms of  the GNU General  Public License as published by the
  8 * Free Software Foundation;  either version 2 of the  License, or (at your
  9 * option) any later version.
 10 *
 11 * This program is distributed in the hope that it will be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 18 */
 19
 20#include <drm/drmP.h>
 21#include "udl_drv.h"
 22#include <linux/shmem_fs.h>
 23#include <linux/dma-buf.h>
 24
 25struct udl_drm_dmabuf_attachment {
 26	struct sg_table sgt;
 27	enum dma_data_direction dir;
 28	bool is_mapped;
 29};
 30
 31static int udl_attach_dma_buf(struct dma_buf *dmabuf,
 32			      struct device *dev,
 33			      struct dma_buf_attachment *attach)
 34{
 35	struct udl_drm_dmabuf_attachment *udl_attach;
 36
 37	DRM_DEBUG_PRIME("[DEV:%s] size:%zd\n", dev_name(attach->dev),
 38			attach->dmabuf->size);
 39
 40	udl_attach = kzalloc(sizeof(*udl_attach), GFP_KERNEL);
 41	if (!udl_attach)
 42		return -ENOMEM;
 43
 44	udl_attach->dir = DMA_NONE;
 45	attach->priv = udl_attach;
 46
 47	return 0;
 48}
 49
 50static void udl_detach_dma_buf(struct dma_buf *dmabuf,
 51			       struct dma_buf_attachment *attach)
 52{
 53	struct udl_drm_dmabuf_attachment *udl_attach = attach->priv;
 54	struct sg_table *sgt;
 55
 56	if (!udl_attach)
 57		return;
 58
 59	DRM_DEBUG_PRIME("[DEV:%s] size:%zd\n", dev_name(attach->dev),
 60			attach->dmabuf->size);
 61
 62	sgt = &udl_attach->sgt;
 63
 64	if (udl_attach->dir != DMA_NONE)
 65		dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
 66				udl_attach->dir);
 67
 68	sg_free_table(sgt);
 69	kfree(udl_attach);
 70	attach->priv = NULL;
 71}
 72
 73static struct sg_table *udl_map_dma_buf(struct dma_buf_attachment *attach,
 74					enum dma_data_direction dir)
 75{
 76	struct udl_drm_dmabuf_attachment *udl_attach = attach->priv;
 77	struct udl_gem_object *obj = to_udl_bo(attach->dmabuf->priv);
 78	struct drm_device *dev = obj->base.dev;
 79	struct scatterlist *rd, *wr;
 80	struct sg_table *sgt = NULL;
 81	unsigned int i;
 82	int page_count;
 83	int nents, ret;
 84
 85	DRM_DEBUG_PRIME("[DEV:%s] size:%zd dir=%d\n", dev_name(attach->dev),
 86			attach->dmabuf->size, dir);
 87
 88	/* just return current sgt if already requested. */
 89	if (udl_attach->dir == dir && udl_attach->is_mapped)
 90		return &udl_attach->sgt;
 91
 92	if (!obj->pages) {
 93		ret = udl_gem_get_pages(obj);
 94		if (ret) {
 95			DRM_ERROR("failed to map pages.\n");
 96			return ERR_PTR(ret);
 97		}
 98	}
 99
100	page_count = obj->base.size / PAGE_SIZE;
101	obj->sg = drm_prime_pages_to_sg(obj->pages, page_count);
102	if (IS_ERR(obj->sg)) {
103		DRM_ERROR("failed to allocate sgt.\n");
104		return ERR_CAST(obj->sg);
105	}
106
107	sgt = &udl_attach->sgt;
108
109	ret = sg_alloc_table(sgt, obj->sg->orig_nents, GFP_KERNEL);
110	if (ret) {
111		DRM_ERROR("failed to alloc sgt.\n");
112		return ERR_PTR(-ENOMEM);
113	}
114
115	mutex_lock(&dev->struct_mutex);
116
117	rd = obj->sg->sgl;
118	wr = sgt->sgl;
119	for (i = 0; i < sgt->orig_nents; ++i) {
120		sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
121		rd = sg_next(rd);
122		wr = sg_next(wr);
123	}
124
125	if (dir != DMA_NONE) {
126		nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
127		if (!nents) {
128			DRM_ERROR("failed to map sgl with iommu.\n");
129			sg_free_table(sgt);
130			sgt = ERR_PTR(-EIO);
131			goto err_unlock;
132		}
133	}
134
135	udl_attach->is_mapped = true;
136	udl_attach->dir = dir;
137	attach->priv = udl_attach;
138
139err_unlock:
140	mutex_unlock(&dev->struct_mutex);
141	return sgt;
142}
143
144static void udl_unmap_dma_buf(struct dma_buf_attachment *attach,
145			      struct sg_table *sgt,
146			      enum dma_data_direction dir)
147{
148	/* Nothing to do. */
149	DRM_DEBUG_PRIME("[DEV:%s] size:%zd dir:%d\n", dev_name(attach->dev),
150			attach->dmabuf->size, dir);
151}
152
153static void *udl_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
154{
155	/* TODO */
156
157	return NULL;
158}
159
160static void *udl_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
161				    unsigned long page_num)
162{
163	/* TODO */
164
165	return NULL;
166}
167
168static void udl_dmabuf_kunmap(struct dma_buf *dma_buf,
169			      unsigned long page_num, void *addr)
170{
171	/* TODO */
172}
173
174static void udl_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
175				     unsigned long page_num,
176				     void *addr)
177{
178	/* TODO */
179}
180
181static int udl_dmabuf_mmap(struct dma_buf *dma_buf,
182			   struct vm_area_struct *vma)
183{
184	/* TODO */
185
186	return -EINVAL;
187}
188
189static struct dma_buf_ops udl_dmabuf_ops = {
190	.attach			= udl_attach_dma_buf,
191	.detach			= udl_detach_dma_buf,
192	.map_dma_buf		= udl_map_dma_buf,
193	.unmap_dma_buf		= udl_unmap_dma_buf,
194	.kmap			= udl_dmabuf_kmap,
195	.kmap_atomic		= udl_dmabuf_kmap_atomic,
196	.kunmap			= udl_dmabuf_kunmap,
197	.kunmap_atomic		= udl_dmabuf_kunmap_atomic,
198	.mmap			= udl_dmabuf_mmap,
199	.release		= drm_gem_dmabuf_release,
200};
201
202struct dma_buf *udl_gem_prime_export(struct drm_device *dev,
203				     struct drm_gem_object *obj, int flags)
204{
205	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
206
207	exp_info.ops = &udl_dmabuf_ops;
208	exp_info.size = obj->size;
209	exp_info.flags = flags;
210	exp_info.priv = obj;
211
212	return dma_buf_export(&exp_info);
213}
214
215static int udl_prime_create(struct drm_device *dev,
216			    size_t size,
217			    struct sg_table *sg,
218			    struct udl_gem_object **obj_p)
219{
220	struct udl_gem_object *obj;
221	int npages;
222
223	npages = size / PAGE_SIZE;
224
225	*obj_p = NULL;
226	obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE);
227	if (!obj)
228		return -ENOMEM;
229
230	obj->sg = sg;
231	obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
232	if (obj->pages == NULL) {
233		DRM_ERROR("obj pages is NULL %d\n", npages);
234		return -ENOMEM;
235	}
236
237	drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages);
238
239	*obj_p = obj;
240	return 0;
241}
242
243struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
244				struct dma_buf *dma_buf)
245{
246	struct dma_buf_attachment *attach;
247	struct sg_table *sg;
248	struct udl_gem_object *uobj;
249	int ret;
250
251	/* need to attach */
252	get_device(dev->dev);
253	attach = dma_buf_attach(dma_buf, dev->dev);
254	if (IS_ERR(attach)) {
255		put_device(dev->dev);
256		return ERR_CAST(attach);
257	}
258
259	get_dma_buf(dma_buf);
260
261	sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
262	if (IS_ERR(sg)) {
263		ret = PTR_ERR(sg);
264		goto fail_detach;
265	}
266
267	ret = udl_prime_create(dev, dma_buf->size, sg, &uobj);
268	if (ret)
269		goto fail_unmap;
270
271	uobj->base.import_attach = attach;
272	uobj->flags = UDL_BO_WC;
273
274	return &uobj->base;
275
276fail_unmap:
277	dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
278fail_detach:
279	dma_buf_detach(dma_buf, attach);
280	dma_buf_put(dma_buf);
281	put_device(dev->dev);
282	return ERR_PTR(ret);
283}