1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <drm/drmP.h>
27#include <drm/drm.h>
28#include <drm/gma_drm.h>
29#include "psb_drv.h"
30
31int psb_gem_init_object(struct drm_gem_object *obj)
32{
33 return -EINVAL;
34}
35
36void psb_gem_free_object(struct drm_gem_object *obj)
37{
38 struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);
39
40
41 if (obj->map_list.map)
42 drm_gem_free_mmap_offset(obj);
43 drm_gem_object_release(obj);
44
45
46 psb_gtt_free_range(obj->dev, gtt);
47}
48
49int psb_gem_get_aperture(struct drm_device *dev, void *data,
50 struct drm_file *file)
51{
52 return -EINVAL;
53}
54
55
56
57
58
59
60
61
62
63
64int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
65 uint32_t handle, uint64_t *offset)
66{
67 int ret = 0;
68 struct drm_gem_object *obj;
69
70 if (!(dev->driver->driver_features & DRIVER_GEM))
71 return -ENODEV;
72
73 mutex_lock(&dev->struct_mutex);
74
75
76 obj = drm_gem_object_lookup(dev, file, handle);
77 if (obj == NULL) {
78 ret = -ENOENT;
79 goto unlock;
80 }
81
82
83
84 if (!obj->map_list.map) {
85 ret = drm_gem_create_mmap_offset(obj);
86 if (ret)
87 goto out;
88 }
89
90 *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
91out:
92 drm_gem_object_unreference(obj);
93unlock:
94 mutex_unlock(&dev->struct_mutex);
95 return ret;
96}
97
98
99
100
101
102
103
104
105
106
107
108
109static int psb_gem_create(struct drm_file *file,
110 struct drm_device *dev, uint64_t size, uint32_t *handlep)
111{
112 struct gtt_range *r;
113 int ret;
114 u32 handle;
115
116 size = roundup(size, PAGE_SIZE);
117
118
119
120 r = psb_gtt_alloc_range(dev, size, "gem", 0);
121 if (r == NULL) {
122 dev_err(dev->dev, "no memory for %lld byte GEM object\n", size);
123 return -ENOSPC;
124 }
125
126 if (drm_gem_object_init(dev, &r->gem, size) != 0) {
127 psb_gtt_free_range(dev, r);
128
129 dev_err(dev->dev, "GEM init failed for %lld\n", size);
130 return -ENOMEM;
131 }
132
133 mapping_set_gfp_mask(r->gem.filp->f_mapping, GFP_KERNEL | __GFP_DMA32);
134
135 ret = drm_gem_handle_create(file, &r->gem, &handle);
136 if (ret) {
137 dev_err(dev->dev, "GEM handle failed for %p, %lld\n",
138 &r->gem, size);
139 drm_gem_object_release(&r->gem);
140 psb_gtt_free_range(dev, r);
141 return ret;
142 }
143
144 drm_gem_object_unreference(&r->gem);
145 *handlep = handle;
146 return 0;
147}
148
149
150
151
152
153
154
155
156
157
158
159int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
160 struct drm_mode_create_dumb *args)
161{
162 args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64);
163 args->size = args->pitch * args->height;
164 return psb_gem_create(file, dev, args->size, &args->handle);
165}
166
167
168
169
170
171
172
173
174
175
176
177int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
178 uint32_t handle)
179{
180
181 return drm_gem_handle_delete(file, handle);
182}
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
202{
203 struct drm_gem_object *obj;
204 struct gtt_range *r;
205 int ret;
206 unsigned long pfn;
207 pgoff_t page_offset;
208 struct drm_device *dev;
209 struct drm_psb_private *dev_priv;
210
211 obj = vma->vm_private_data;
212 dev = obj->dev;
213 dev_priv = dev->dev_private;
214
215 r = container_of(obj, struct gtt_range, gem);
216
217
218
219 mutex_lock(&dev->struct_mutex);
220
221
222
223 if (r->mmapping == 0) {
224 ret = psb_gtt_pin(r);
225 if (ret < 0) {
226 dev_err(dev->dev, "gma500: pin failed: %d\n", ret);
227 goto fail;
228 }
229 r->mmapping = 1;
230 }
231
232
233
234 page_offset = ((unsigned long) vmf->virtual_address - vma->vm_start)
235 >> PAGE_SHIFT;
236
237
238 if (r->stolen)
239 pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT;
240 else
241 pfn = page_to_pfn(r->pages[page_offset]);
242 ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
243
244fail:
245 mutex_unlock(&dev->struct_mutex);
246 switch (ret) {
247 case 0:
248 case -ERESTARTSYS:
249 case -EINTR:
250 return VM_FAULT_NOPAGE;
251 case -ENOMEM:
252 return VM_FAULT_OOM;
253 default:
254 return VM_FAULT_SIGBUS;
255 }
256}
257
258static int psb_gem_create_stolen(struct drm_file *file, struct drm_device *dev,
259 int size, u32 *handle)
260{
261 struct gtt_range *gtt = psb_gtt_alloc_range(dev, size, "gem", 1);
262 if (gtt == NULL)
263 return -ENOMEM;
264 if (drm_gem_private_object_init(dev, >t->gem, size) != 0)
265 goto free_gtt;
266 if (drm_gem_handle_create(file, >t->gem, handle) == 0)
267 return 0;
268free_gtt:
269 psb_gtt_free_range(dev, gtt);
270 return -ENOMEM;
271}
272
273
274
275
276int psb_gem_create_ioctl(struct drm_device *dev, void *data,
277 struct drm_file *file)
278{
279 struct drm_psb_gem_create *args = data;
280 int ret;
281 if (args->flags & GMA_GEM_CREATE_STOLEN) {
282 ret = psb_gem_create_stolen(file, dev, args->size,
283 &args->handle);
284 if (ret == 0)
285 return 0;
286
287 args->flags &= ~GMA_GEM_CREATE_STOLEN;
288 }
289 return psb_gem_create(file, dev, args->size, &args->handle);
290}
291
292int psb_gem_mmap_ioctl(struct drm_device *dev, void *data,
293 struct drm_file *file)
294{
295 struct drm_psb_gem_mmap *args = data;
296 return dev->driver->dumb_map_offset(file, dev,
297 args->handle, &args->offset);
298}
299
300