aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_scatter.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-05-28 20:09:59 -0400
committerDave Airlie <airlied@redhat.com>2008-07-13 20:45:01 -0400
commitc0e09200dc0813972442e550a5905a132768e56c (patch)
treed38e635a30ff8b0a2b98b9d7f97cab1501f8209e /drivers/gpu/drm/drm_scatter.c
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
drm: reorganise drm tree to be more future proof.
With the coming of kernel based modesetting and the memory manager stuff, the everything in one directory approach was getting very ugly and starting to be unmanageable. This restructures the drm along the lines of other kernel components. It creates a drivers/gpu/drm directory and moves the hw drivers into subdirectores. It moves the includes into an include/drm, and sets up the unifdef for the userspace headers we should be exporting. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_scatter.c')
-rw-r--r--drivers/gpu/drm/drm_scatter.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c
new file mode 100644
index 000000000000..b2b0f3d41714
--- /dev/null
+++ b/drivers/gpu/drm/drm_scatter.c
@@ -0,0 +1,227 @@
1/**
2 * \file drm_scatter.c
3 * IOCTLs to manage scatter/gather memory
4 *
5 * \author Gareth Hughes <gareth@valinux.com>
6 */
7
8/*
9 * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com
10 *
11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12 * All Rights Reserved.
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
23 * Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 */
33
34#include <linux/vmalloc.h>
35#include "drmP.h"
36
37#define DEBUG_SCATTER 0
38
39static inline void *drm_vmalloc_dma(unsigned long size)
40{
41#if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE)
42 return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL | _PAGE_NO_CACHE);
43#else
44 return vmalloc_32(size);
45#endif
46}
47
48void drm_sg_cleanup(struct drm_sg_mem * entry)
49{
50 struct page *page;
51 int i;
52
53 for (i = 0; i < entry->pages; i++) {
54 page = entry->pagelist[i];
55 if (page)
56 ClearPageReserved(page);
57 }
58
59 vfree(entry->virtual);
60
61 drm_free(entry->busaddr,
62 entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES);
63 drm_free(entry->pagelist,
64 entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES);
65 drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
66}
67
68#ifdef _LP64
69# define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1)))
70#else
71# define ScatterHandle(x) (unsigned int)(x)
72#endif
73
74int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
75{
76 struct drm_sg_mem *entry;
77 unsigned long pages, i, j;
78
79 DRM_DEBUG("\n");
80
81 if (!drm_core_check_feature(dev, DRIVER_SG))
82 return -EINVAL;
83
84 if (dev->sg)
85 return -EINVAL;
86
87 entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS);
88 if (!entry)
89 return -ENOMEM;
90
91 memset(entry, 0, sizeof(*entry));
92 pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
93 DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages);
94
95 entry->pages = pages;
96 entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist),
97 DRM_MEM_PAGES);
98 if (!entry->pagelist) {
99 drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
100 return -ENOMEM;
101 }
102
103 memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
104
105 entry->busaddr = drm_alloc(pages * sizeof(*entry->busaddr),
106 DRM_MEM_PAGES);
107 if (!entry->busaddr) {
108 drm_free(entry->pagelist,
109 entry->pages * sizeof(*entry->pagelist),
110 DRM_MEM_PAGES);
111 drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
112 return -ENOMEM;
113 }
114 memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr));
115
116 entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT);
117 if (!entry->virtual) {
118 drm_free(entry->busaddr,
119 entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES);
120 drm_free(entry->pagelist,
121 entry->pages * sizeof(*entry->pagelist),
122 DRM_MEM_PAGES);
123 drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
124 return -ENOMEM;
125 }
126
127 /* This also forces the mapping of COW pages, so our page list
128 * will be valid. Please don't remove it...
129 */
130 memset(entry->virtual, 0, pages << PAGE_SHIFT);
131
132 entry->handle = ScatterHandle((unsigned long)entry->virtual);
133
134 DRM_DEBUG("handle = %08lx\n", entry->handle);
135 DRM_DEBUG("virtual = %p\n", entry->virtual);
136
137 for (i = (unsigned long)entry->virtual, j = 0; j < pages;
138 i += PAGE_SIZE, j++) {
139 entry->pagelist[j] = vmalloc_to_page((void *)i);
140 if (!entry->pagelist[j])
141 goto failed;
142 SetPageReserved(entry->pagelist[j]);
143 }
144
145 request->handle = entry->handle;
146
147 dev->sg = entry;
148
149#if DEBUG_SCATTER
150 /* Verify that each page points to its virtual address, and vice
151 * versa.
152 */
153 {
154 int error = 0;
155
156 for (i = 0; i < pages; i++) {
157 unsigned long *tmp;
158
159 tmp = page_address(entry->pagelist[i]);
160 for (j = 0;
161 j < PAGE_SIZE / sizeof(unsigned long);
162 j++, tmp++) {
163 *tmp = 0xcafebabe;
164 }
165 tmp = (unsigned long *)((u8 *) entry->virtual +
166 (PAGE_SIZE * i));
167 for (j = 0;
168 j < PAGE_SIZE / sizeof(unsigned long);
169 j++, tmp++) {
170 if (*tmp != 0xcafebabe && error == 0) {
171 error = 1;
172 DRM_ERROR("Scatter allocation error, "
173 "pagelist does not match "
174 "virtual mapping\n");
175 }
176 }
177 tmp = page_address(entry->pagelist[i]);
178 for (j = 0;
179 j < PAGE_SIZE / sizeof(unsigned long);
180 j++, tmp++) {
181 *tmp = 0;
182 }
183 }
184 if (error == 0)
185 DRM_ERROR("Scatter allocation matches pagelist\n");
186 }
187#endif
188
189 return 0;
190
191 failed:
192 drm_sg_cleanup(entry);
193 return -ENOMEM;
194}
195EXPORT_SYMBOL(drm_sg_alloc);
196
197
198int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
199 struct drm_file *file_priv)
200{
201 struct drm_scatter_gather *request = data;
202
203 return drm_sg_alloc(dev, request);
204
205}
206
207int drm_sg_free(struct drm_device *dev, void *data,
208 struct drm_file *file_priv)
209{
210 struct drm_scatter_gather *request = data;
211 struct drm_sg_mem *entry;
212
213 if (!drm_core_check_feature(dev, DRIVER_SG))
214 return -EINVAL;
215
216 entry = dev->sg;
217 dev->sg = NULL;
218
219 if (!entry || entry->handle != request->handle)
220 return -EINVAL;
221
222 DRM_DEBUG("virtual = %p\n", entry->virtual);
223
224 drm_sg_cleanup(entry);
225
226 return 0;
227}