gma500: Move our other GEM helper into the bits want to push into GEM
[pandora-kernel.git] / drivers / staging / gma500 / psb_gem.c
1 /*
2  *  psb GEM interface
3  *
4  * Copyright (c) 2011, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Authors: Alan Cox
20  *
21  * TODO:
22  *      -       we don't actually put GEM objects into the GART yet
23  *      -       we need to work out if the MMU is relevant as well (eg for
24  *              accelerated operations on a GEM object)
25  *      -       cache coherency
26  *
27  * ie this is just an initial framework to get us going.
28  */
29
30 #include <drm/drmP.h>
31 #include <drm/drm.h>
32 #include "psb_drm.h"
33 #include "psb_drv.h"
34
35 int psb_gem_init_object(struct drm_gem_object *obj)
36 {
37         return -EINVAL;
38 }
39
40 void psb_gem_free_object(struct drm_gem_object *obj)
41 {
42         struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);
43         if (obj->map_list.map) {
44                 /* Do things GEM should do for us */
45                 struct drm_gem_mm *mm = obj->dev->mm_private;
46                 struct drm_map_list *list = &obj->map_list;
47                 drm_ht_remove_item(&mm->offset_hash, &list->hash);
48                 drm_mm_put_block(list->file_offset_node);
49                 kfree(list->map);
50                 list->map = NULL;
51         }
52         drm_gem_object_release_wrap(obj);
53         /* This must occur last as it frees up the memory of the GEM object */
54         psb_gtt_free_range(obj->dev, gtt);
55 }
56
57 int psb_gem_get_aperture(struct drm_device *dev, void *data,
58                                 struct drm_file *file)
59 {
60         return -EINVAL;
61 }
62
63 /**
64  *      psb_gem_dumb_map_gtt    -       buffer mapping for dumb interface
65  *      @file: our drm client file
66  *      @dev: drm device
67  *      @handle: GEM handle to the object (from dumb_create)
68  *
69  *      Do the necessary setup to allow the mapping of the frame buffer
70  *      into user memory. We don't have to do much here at the moment.
71  */
72 int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
73                          uint32_t handle, uint64_t *offset)
74 {
75         int ret = 0;
76         struct drm_gem_object *obj;
77
78         if (!(dev->driver->driver_features & DRIVER_GEM))
79                 return -ENODEV;
80
81         mutex_lock(&dev->struct_mutex);
82
83         /* GEM does all our handle to object mapping */
84         obj = drm_gem_object_lookup(dev, file, handle);
85         if (obj == NULL) {
86                 ret = -ENOENT;
87                 goto unlock;
88         }
89         /* What validation is needed here ? */
90
91         /* Make it mmapable */
92         if (!obj->map_list.map) {
93                 ret = gem_create_mmap_offset(obj);
94                 if (ret)
95                         goto out;
96         }
97         /* GEM should really work out the hash offsets for us */
98         *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
99 out:
100         drm_gem_object_unreference(obj);
101 unlock:
102         mutex_unlock(&dev->struct_mutex);
103         return ret;
104 }
105
106 /**
107  *      psb_gem_create          -       create a mappable object
108  *      @file: the DRM file of the client
109  *      @dev: our device
110  *      @size: the size requested
111  *      @handlep: returned handle (opaque number)
112  *
113  *      Create a GEM object, fill in the boilerplate and attach a handle to
114  *      it so that userspace can speak about it. This does the core work
115  *      for the various methods that do/will create GEM objects for things
116  */
117 static int psb_gem_create(struct drm_file *file,
118         struct drm_device *dev, uint64_t size, uint32_t *handlep)
119 {
120         struct gtt_range *r;
121         int ret;
122         u32 handle;
123
124         size = roundup(size, PAGE_SIZE);
125
126         /* Allocate our object - for now a direct gtt range which is not
127            stolen memory backed */
128         r = psb_gtt_alloc_range(dev, size, "gem", 0);
129         if (r == NULL) {
130                 dev_err(dev->dev, "no memory for %lld byte GEM object\n", size);
131                 return -ENOSPC;
132         }
133         /* Initialize the extra goodies GEM needs to do all the hard work */
134         if (drm_gem_object_init(dev, &r->gem, size) != 0) {
135                 psb_gtt_free_range(dev, r);
136                 /* GEM doesn't give an error code and we don't have an
137                    EGEMSUCKS so make something up for now - FIXME */
138                 dev_err(dev->dev, "GEM init failed for %lld\n", size);
139                 return -ENOMEM;
140         }
141         /* Give the object a handle so we can carry it more easily */
142         ret = drm_gem_handle_create(file, &r->gem, &handle);
143         if (ret) {
144                 dev_err(dev->dev, "GEM handle failed for %p, %lld\n",
145                                                         &r->gem, size);
146                 drm_gem_object_release(&r->gem);
147                 psb_gtt_free_range(dev, r);
148                 return ret;
149         }
150         /* We have the initial and handle reference but need only one now */
151         drm_gem_object_unreference(&r->gem);
152         *handlep = handle;
153         return 0;
154 }
155
156 /**
157  *      psb_gem_dumb_create     -       create a dumb buffer
158  *      @drm_file: our client file
159  *      @dev: our device
160  *      @args: the requested arguments copied from userspace
161  *
162  *      Allocate a buffer suitable for use for a frame buffer of the
163  *      form described by user space. Give userspace a handle by which
164  *      to reference it.
165  */
166 int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
167                         struct drm_mode_create_dumb *args)
168 {
169         args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64);
170         args->size = args->pitch * args->height;
171         return psb_gem_create(file, dev, args->size, &args->handle);
172 }
173
174 /**
175  *      psb_gem_dumb_destroy    -       destroy a dumb buffer
176  *      @file: client file
177  *      @dev: our DRM device
178  *      @handle: the object handle
179  *
180  *      Destroy a handle that was created via psb_gem_dumb_create, at least
181  *      we hope it was created that way. i915 seems to assume the caller
182  *      does the checking but that might be worth review ! FIXME
183  */
184 int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
185                         uint32_t handle)
186 {
187         /* No special work needed, drop the reference and see what falls out */
188         return drm_gem_handle_delete(file, handle);
189 }
190
191 /**
192  *      psb_gem_fault           -       pagefault handler for GEM objects
193  *      @vma: the VMA of the GEM object
194  *      @vmf: fault detail
195  *
196  *      Invoked when a fault occurs on an mmap of a GEM managed area. GEM
197  *      does most of the work for us including the actual map/unmap calls
198  *      but we need to do the actual page work.
199  *
200  *      This code eventually needs to handle faulting objects in and out
201  *      of the GTT and repacking it when we run out of space. We can put
202  *      that off for now and for our simple uses
203  *
204  *      The VMA was set up by GEM. In doing so it also ensured that the
205  *      vma->vm_private_data points to the GEM object that is backing this
206  *      mapping.
207  *
208  *      FIXME
209  */
210 int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
211 {
212         struct drm_gem_object *obj;
213         struct gtt_range *r;
214         int ret;
215         unsigned long pfn;
216         pgoff_t page_offset;
217         struct drm_device *dev;
218         struct drm_psb_private *dev_priv;
219
220         obj = vma->vm_private_data;     /* GEM object */
221         dev = obj->dev;
222         dev_priv = dev->dev_private;
223
224         r = container_of(obj, struct gtt_range, gem);   /* Get the gtt range */
225
226         /* Make sure we don't parallel update on a fault, nor move or remove
227            something from beneath our feet */
228         mutex_lock(&dev->struct_mutex);
229
230         /* For now the mmap pins the object and it stays pinned. As things
231            stand that will do us no harm */
232         if (r->mmapping == 0) {
233                 ret = psb_gtt_pin(r);
234                 if (ret < 0) {
235                         dev_err(dev->dev, "gma500: pin failed: %d\n", ret);
236                         goto fail;
237                 }
238                 r->mmapping = 1;
239         }
240
241         /* Page relative to the VMA start - we must calculate this ourselves
242            because vmf->pgoff is the fake GEM offset */
243         page_offset = ((unsigned long) vmf->virtual_address - vma->vm_start)
244                                 >> PAGE_SHIFT;
245
246         /* CPU view of the page, don't go via the GART for CPU writes */
247         if (r->stolen)
248                 pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT;
249         else
250                 pfn = page_to_pfn(r->pages[page_offset]);
251         ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
252
253 fail:
254         mutex_unlock(&dev->struct_mutex);
255         switch (ret) {
256         case 0:
257         case -ERESTARTSYS:
258         case -EINTR:
259                 return VM_FAULT_NOPAGE;
260         case -ENOMEM:
261                 return VM_FAULT_OOM;
262         default:
263                 return VM_FAULT_SIGBUS;
264         }
265 }