1254885Sdumbbell/*
2254885Sdumbbell * Copyright 2012 Advanced Micro Devices, Inc.
3254885Sdumbbell *
4254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
5254885Sdumbbell * copy of this software and associated documentation files (the "Software"),
6254885Sdumbbell * to deal in the Software without restriction, including without limitation
7254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the
9254885Sdumbbell * Software is furnished to do so, subject to the following conditions:
10254885Sdumbbell *
11254885Sdumbbell * The above copyright notice and this permission notice shall be included in
12254885Sdumbbell * all copies or substantial portions of the Software.
13254885Sdumbbell *
14254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE.
21254885Sdumbbell *
22254885Sdumbbell * based on nouveau_prime.c
23254885Sdumbbell *
24254885Sdumbbell * Authors: Alex Deucher
25254885Sdumbbell */
26254885Sdumbbell
27254885Sdumbbell#include <sys/cdefs.h>
28254885Sdumbbell__FBSDID("$FreeBSD$");
29254885Sdumbbell
30254885Sdumbbell#include <drm/drmP.h>
31254885Sdumbbell
32254885Sdumbbell#include "radeon.h"
33254885Sdumbbell#include <drm/radeon_drm.h>
34254885Sdumbbell
35254885Sdumbbell#include <linux/dma-buf.h>
36254885Sdumbbell
37254885Sdumbbellstatic struct sg_table *radeon_gem_map_dma_buf(struct dma_buf_attachment *attachment,
38254885Sdumbbell					       enum dma_data_direction dir)
39254885Sdumbbell{
40254885Sdumbbell	struct radeon_bo *bo = attachment->dmabuf->priv;
41254885Sdumbbell	struct drm_device *dev = bo->rdev->ddev;
42254885Sdumbbell	int npages = bo->tbo.num_pages;
43254885Sdumbbell	struct sg_table *sg;
44254885Sdumbbell	int nents;
45254885Sdumbbell
46254885Sdumbbell	mutex_lock(&dev->struct_mutex);
47254885Sdumbbell	sg = drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
48254885Sdumbbell	nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
49254885Sdumbbell	mutex_unlock(&dev->struct_mutex);
50254885Sdumbbell	return sg;
51254885Sdumbbell}
52254885Sdumbbell
53254885Sdumbbellstatic void radeon_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
54254885Sdumbbell				     struct sg_table *sg, enum dma_data_direction dir)
55254885Sdumbbell{
56254885Sdumbbell	dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
57254885Sdumbbell	sg_free_table(sg);
58254885Sdumbbell	kfree(sg);
59254885Sdumbbell}
60254885Sdumbbell
61254885Sdumbbellstatic void radeon_gem_dmabuf_release(struct dma_buf *dma_buf)
62254885Sdumbbell{
63254885Sdumbbell	struct radeon_bo *bo = dma_buf->priv;
64254885Sdumbbell
65254885Sdumbbell	if (bo->gem_base.export_dma_buf == dma_buf) {
66254885Sdumbbell		DRM_ERROR("unreference dmabuf %p\n", &bo->gem_base);
67254885Sdumbbell		bo->gem_base.export_dma_buf = NULL;
68254885Sdumbbell		drm_gem_object_unreference_unlocked(&bo->gem_base);
69254885Sdumbbell	}
70254885Sdumbbell}
71254885Sdumbbell
72254885Sdumbbellstatic void *radeon_gem_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
73254885Sdumbbell{
74254885Sdumbbell	return NULL;
75254885Sdumbbell}
76254885Sdumbbell
77254885Sdumbbellstatic void radeon_gem_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
78254885Sdumbbell{
79254885Sdumbbell
80254885Sdumbbell}
81254885Sdumbbellstatic void *radeon_gem_kmap(struct dma_buf *dma_buf, unsigned long page_num)
82254885Sdumbbell{
83254885Sdumbbell	return NULL;
84254885Sdumbbell}
85254885Sdumbbell
86254885Sdumbbellstatic void radeon_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
87254885Sdumbbell{
88254885Sdumbbell
89254885Sdumbbell}
90254885Sdumbbell
91254885Sdumbbellstatic int radeon_gem_prime_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
92254885Sdumbbell{
93254885Sdumbbell	return -EINVAL;
94254885Sdumbbell}
95254885Sdumbbell
96254885Sdumbbellstatic void *radeon_gem_prime_vmap(struct dma_buf *dma_buf)
97254885Sdumbbell{
98254885Sdumbbell	struct radeon_bo *bo = dma_buf->priv;
99254885Sdumbbell	struct drm_device *dev = bo->rdev->ddev;
100254885Sdumbbell	int ret;
101254885Sdumbbell
102254885Sdumbbell	mutex_lock(&dev->struct_mutex);
103254885Sdumbbell	if (bo->vmapping_count) {
104254885Sdumbbell		bo->vmapping_count++;
105254885Sdumbbell		goto out_unlock;
106254885Sdumbbell	}
107254885Sdumbbell
108254885Sdumbbell	ret = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages,
109254885Sdumbbell			  &bo->dma_buf_vmap);
110254885Sdumbbell	if (ret) {
111254885Sdumbbell		mutex_unlock(&dev->struct_mutex);
112254885Sdumbbell		return ERR_PTR(ret);
113254885Sdumbbell	}
114254885Sdumbbell	bo->vmapping_count = 1;
115254885Sdumbbellout_unlock:
116254885Sdumbbell	mutex_unlock(&dev->struct_mutex);
117254885Sdumbbell	return bo->dma_buf_vmap.virtual;
118254885Sdumbbell}
119254885Sdumbbell
120254885Sdumbbellstatic void radeon_gem_prime_vunmap(struct dma_buf *dma_buf, void *vaddr)
121254885Sdumbbell{
122254885Sdumbbell	struct radeon_bo *bo = dma_buf->priv;
123254885Sdumbbell	struct drm_device *dev = bo->rdev->ddev;
124254885Sdumbbell
125254885Sdumbbell	mutex_lock(&dev->struct_mutex);
126254885Sdumbbell	bo->vmapping_count--;
127254885Sdumbbell	if (bo->vmapping_count == 0) {
128254885Sdumbbell		ttm_bo_kunmap(&bo->dma_buf_vmap);
129254885Sdumbbell	}
130254885Sdumbbell	mutex_unlock(&dev->struct_mutex);
131254885Sdumbbell}
132254885Sdumbbellconst static struct dma_buf_ops radeon_dmabuf_ops =  {
133254885Sdumbbell	.map_dma_buf = radeon_gem_map_dma_buf,
134254885Sdumbbell	.unmap_dma_buf = radeon_gem_unmap_dma_buf,
135254885Sdumbbell	.release = radeon_gem_dmabuf_release,
136254885Sdumbbell	.kmap = radeon_gem_kmap,
137254885Sdumbbell	.kmap_atomic = radeon_gem_kmap_atomic,
138254885Sdumbbell	.kunmap = radeon_gem_kunmap,
139254885Sdumbbell	.kunmap_atomic = radeon_gem_kunmap_atomic,
140254885Sdumbbell	.mmap = radeon_gem_prime_mmap,
141254885Sdumbbell	.vmap = radeon_gem_prime_vmap,
142254885Sdumbbell	.vunmap = radeon_gem_prime_vunmap,
143254885Sdumbbell};
144254885Sdumbbell
145254885Sdumbbellstatic int radeon_prime_create(struct drm_device *dev,
146254885Sdumbbell			       size_t size,
147254885Sdumbbell			       struct sg_table *sg,
148254885Sdumbbell			       struct radeon_bo **pbo)
149254885Sdumbbell{
150254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
151254885Sdumbbell	struct radeon_bo *bo;
152254885Sdumbbell	int ret;
153254885Sdumbbell
154254885Sdumbbell	ret = radeon_bo_create(rdev, size, PAGE_SIZE, false,
155254885Sdumbbell			       RADEON_GEM_DOMAIN_GTT, sg, pbo);
156254885Sdumbbell	if (ret)
157254885Sdumbbell		return ret;
158254885Sdumbbell	bo = *pbo;
159254885Sdumbbell	bo->gem_base.driver_private = bo;
160254885Sdumbbell
161254885Sdumbbell	mutex_lock(&rdev->gem.mutex);
162254885Sdumbbell	list_add_tail(&bo->list, &rdev->gem.objects);
163254885Sdumbbell	mutex_unlock(&rdev->gem.mutex);
164254885Sdumbbell
165254885Sdumbbell	return 0;
166254885Sdumbbell}
167254885Sdumbbell
168254885Sdumbbellstruct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
169254885Sdumbbell					struct drm_gem_object *obj,
170254885Sdumbbell					int flags)
171254885Sdumbbell{
172254885Sdumbbell	struct radeon_bo *bo = gem_to_radeon_bo(obj);
173254885Sdumbbell	int ret = 0;
174254885Sdumbbell
175254885Sdumbbell	ret = radeon_bo_reserve(bo, false);
176254885Sdumbbell	if (unlikely(ret != 0))
177254885Sdumbbell		return ERR_PTR(ret);
178254885Sdumbbell
179254885Sdumbbell	/* pin buffer into GTT */
180254885Sdumbbell	ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL);
181254885Sdumbbell	if (ret) {
182254885Sdumbbell		radeon_bo_unreserve(bo);
183254885Sdumbbell		return ERR_PTR(ret);
184254885Sdumbbell	}
185254885Sdumbbell	radeon_bo_unreserve(bo);
186254885Sdumbbell	return dma_buf_export(bo, &radeon_dmabuf_ops, obj->size, flags);
187254885Sdumbbell}
188254885Sdumbbell
189254885Sdumbbellstruct drm_gem_object *radeon_gem_prime_import(struct drm_device *dev,
190254885Sdumbbell					       struct dma_buf *dma_buf)
191254885Sdumbbell{
192254885Sdumbbell	struct dma_buf_attachment *attach;
193254885Sdumbbell	struct sg_table *sg;
194254885Sdumbbell	struct radeon_bo *bo;
195254885Sdumbbell	int ret;
196254885Sdumbbell
197254885Sdumbbell	if (dma_buf->ops == &radeon_dmabuf_ops) {
198254885Sdumbbell		bo = dma_buf->priv;
199254885Sdumbbell		if (bo->gem_base.dev == dev) {
200254885Sdumbbell			drm_gem_object_reference(&bo->gem_base);
201254885Sdumbbell			dma_buf_put(dma_buf);
202254885Sdumbbell			return &bo->gem_base;
203254885Sdumbbell		}
204254885Sdumbbell	}
205254885Sdumbbell
206254885Sdumbbell	/* need to attach */
207254885Sdumbbell	attach = dma_buf_attach(dma_buf, dev->dev);
208254885Sdumbbell	if (IS_ERR(attach))
209254885Sdumbbell		return ERR_CAST(attach);
210254885Sdumbbell
211254885Sdumbbell	sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
212254885Sdumbbell	if (IS_ERR(sg)) {
213254885Sdumbbell		ret = PTR_ERR(sg);
214254885Sdumbbell		goto fail_detach;
215254885Sdumbbell	}
216254885Sdumbbell
217254885Sdumbbell	ret = radeon_prime_create(dev, dma_buf->size, sg, &bo);
218254885Sdumbbell	if (ret)
219254885Sdumbbell		goto fail_unmap;
220254885Sdumbbell
221254885Sdumbbell	bo->gem_base.import_attach = attach;
222254885Sdumbbell
223254885Sdumbbell	return &bo->gem_base;
224254885Sdumbbell
225254885Sdumbbellfail_unmap:
226254885Sdumbbell	dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
227254885Sdumbbellfail_detach:
228254885Sdumbbell	dma_buf_detach(dma_buf, attach);
229254885Sdumbbell	return ERR_PTR(ret);
230254885Sdumbbell}
231