]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/vboxvideo/vbox_main.c
staging: vboxvideo: Use more drm_fb_helper functions
[linux.git] / drivers / staging / vboxvideo / vbox_main.c
1 /*
2  * Copyright (C) 2013-2017 Oracle Corporation
3  * This file is based on ast_main.c
4  * Copyright 2012 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * Authors: Dave Airlie <airlied@redhat.com>,
27  *          Michael Thayer <michael.thayer@oracle.com,
28  *          Hans de Goede <hdegoede@redhat.com>
29  */
30 #include <drm/drm_fb_helper.h>
31 #include <drm/drm_crtc_helper.h>
32
33 #include "vbox_drv.h"
34 #include "vbox_err.h"
35 #include "vboxvideo_guest.h"
36 #include "vboxvideo_vbe.h"
37
38 static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb)
39 {
40         struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb);
41
42         if (vbox_fb->obj)
43                 drm_gem_object_put_unlocked(vbox_fb->obj);
44
45         drm_framebuffer_cleanup(fb);
46         kfree(fb);
47 }
48
49 void vbox_enable_accel(struct vbox_private *vbox)
50 {
51         unsigned int i;
52         struct vbva_buffer *vbva;
53
54         if (!vbox->vbva_info || !vbox->vbva_buffers) {
55                 /* Should never happen... */
56                 DRM_ERROR("vboxvideo: failed to set up VBVA.\n");
57                 return;
58         }
59
60         for (i = 0; i < vbox->num_crtcs; ++i) {
61                 if (vbox->vbva_info[i].vbva)
62                         continue;
63
64                 vbva = (void __force *)vbox->vbva_buffers +
65                         i * VBVA_MIN_BUFFER_SIZE;
66                 if (!vbva_enable(&vbox->vbva_info[i],
67                                  vbox->guest_pool, vbva, i)) {
68                         /* very old host or driver error. */
69                         DRM_ERROR("vboxvideo: vbva_enable failed\n");
70                         return;
71                 }
72         }
73 }
74
75 void vbox_disable_accel(struct vbox_private *vbox)
76 {
77         unsigned int i;
78
79         for (i = 0; i < vbox->num_crtcs; ++i)
80                 vbva_disable(&vbox->vbva_info[i], vbox->guest_pool, i);
81 }
82
83 void vbox_report_caps(struct vbox_private *vbox)
84 {
85         u32 caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION |
86                    VBVACAPS_IRQ | VBVACAPS_USE_VBVA_ONLY;
87
88         if (vbox->initial_mode_queried)
89                 caps |= VBVACAPS_VIDEO_MODE_HINTS;
90
91         hgsmi_send_caps_info(vbox->guest_pool, caps);
92 }
93
94 /**
95  * Send information about dirty rectangles to VBVA.  If necessary we enable
96  * VBVA first, as this is normally disabled after a change of master in case
97  * the new master does not send dirty rectangle information (is this even
98  * allowed?)
99  */
100 void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
101                                        struct drm_clip_rect *rects,
102                                        unsigned int num_rects)
103 {
104         struct vbox_private *vbox = fb->dev->dev_private;
105         struct drm_display_mode *mode;
106         struct drm_crtc *crtc;
107         int crtc_x, crtc_y;
108         unsigned int i;
109
110         mutex_lock(&vbox->hw_mutex);
111         list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head) {
112                 if (crtc->primary->state->fb != fb)
113                         continue;
114
115                 mode = &crtc->state->mode;
116                 crtc_x = crtc->primary->state->src_x >> 16;
117                 crtc_y = crtc->primary->state->src_y >> 16;
118
119                 vbox_enable_accel(vbox);
120
121                 for (i = 0; i < num_rects; ++i) {
122                         struct vbva_cmd_hdr cmd_hdr;
123                         unsigned int crtc_id = to_vbox_crtc(crtc)->crtc_id;
124
125                         if ((rects[i].x1 > crtc_x + mode->hdisplay) ||
126                             (rects[i].y1 > crtc_y + mode->vdisplay) ||
127                             (rects[i].x2 < crtc_x) ||
128                             (rects[i].y2 < crtc_y))
129                                 continue;
130
131                         cmd_hdr.x = (s16)rects[i].x1;
132                         cmd_hdr.y = (s16)rects[i].y1;
133                         cmd_hdr.w = (u16)rects[i].x2 - rects[i].x1;
134                         cmd_hdr.h = (u16)rects[i].y2 - rects[i].y1;
135
136                         if (!vbva_buffer_begin_update(&vbox->vbva_info[crtc_id],
137                                                       vbox->guest_pool))
138                                 continue;
139
140                         vbva_write(&vbox->vbva_info[crtc_id], vbox->guest_pool,
141                                    &cmd_hdr, sizeof(cmd_hdr));
142                         vbva_buffer_end_update(&vbox->vbva_info[crtc_id]);
143                 }
144         }
145         mutex_unlock(&vbox->hw_mutex);
146 }
147
148 static int vbox_user_framebuffer_dirty(struct drm_framebuffer *fb,
149                                        struct drm_file *file_priv,
150                                        unsigned int flags, unsigned int color,
151                                        struct drm_clip_rect *rects,
152                                        unsigned int num_rects)
153 {
154         vbox_framebuffer_dirty_rectangles(fb, rects, num_rects);
155
156         return 0;
157 }
158
159 static const struct drm_framebuffer_funcs vbox_fb_funcs = {
160         .destroy = vbox_user_framebuffer_destroy,
161         .dirty = vbox_user_framebuffer_dirty,
162 };
163
164 int vbox_framebuffer_init(struct vbox_private *vbox,
165                           struct vbox_framebuffer *vbox_fb,
166                           const struct DRM_MODE_FB_CMD *mode_cmd,
167                           struct drm_gem_object *obj)
168 {
169         int ret;
170
171         drm_helper_mode_fill_fb_struct(&vbox->ddev, &vbox_fb->base, mode_cmd);
172         vbox_fb->obj = obj;
173         ret = drm_framebuffer_init(&vbox->ddev, &vbox_fb->base, &vbox_fb_funcs);
174         if (ret) {
175                 DRM_ERROR("framebuffer init failed %d\n", ret);
176                 return ret;
177         }
178
179         return 0;
180 }
181
182 static int vbox_accel_init(struct vbox_private *vbox)
183 {
184         unsigned int i;
185
186         vbox->vbva_info = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs,
187                                        sizeof(*vbox->vbva_info), GFP_KERNEL);
188         if (!vbox->vbva_info)
189                 return -ENOMEM;
190
191         /* Take a command buffer for each screen from the end of usable VRAM. */
192         vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
193
194         vbox->vbva_buffers = pci_iomap_range(vbox->ddev.pdev, 0,
195                                              vbox->available_vram_size,
196                                              vbox->num_crtcs *
197                                              VBVA_MIN_BUFFER_SIZE);
198         if (!vbox->vbva_buffers)
199                 return -ENOMEM;
200
201         for (i = 0; i < vbox->num_crtcs; ++i)
202                 vbva_setup_buffer_context(&vbox->vbva_info[i],
203                                           vbox->available_vram_size +
204                                           i * VBVA_MIN_BUFFER_SIZE,
205                                           VBVA_MIN_BUFFER_SIZE);
206
207         return 0;
208 }
209
210 static void vbox_accel_fini(struct vbox_private *vbox)
211 {
212         vbox_disable_accel(vbox);
213         pci_iounmap(vbox->ddev.pdev, vbox->vbva_buffers);
214 }
215
216 /** Do we support the 4.3 plus mode hint reporting interface? */
217 static bool have_hgsmi_mode_hints(struct vbox_private *vbox)
218 {
219         u32 have_hints, have_cursor;
220         int ret;
221
222         ret = hgsmi_query_conf(vbox->guest_pool,
223                                VBOX_VBVA_CONF32_MODE_HINT_REPORTING,
224                                &have_hints);
225         if (ret)
226                 return false;
227
228         ret = hgsmi_query_conf(vbox->guest_pool,
229                                VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING,
230                                &have_cursor);
231         if (ret)
232                 return false;
233
234         return have_hints == VINF_SUCCESS && have_cursor == VINF_SUCCESS;
235 }
236
237 bool vbox_check_supported(u16 id)
238 {
239         u16 dispi_id;
240
241         vbox_write_ioport(VBE_DISPI_INDEX_ID, id);
242         dispi_id = inw(VBE_DISPI_IOPORT_DATA);
243
244         return dispi_id == id;
245 }
246
247 /**
248  * Set up our heaps and data exchange buffers in VRAM before handing the rest
249  * to the memory manager.
250  */
251 int vbox_hw_init(struct vbox_private *vbox)
252 {
253         int ret = -ENOMEM;
254
255         vbox->full_vram_size = inl(VBE_DISPI_IOPORT_DATA);
256         vbox->any_pitch = vbox_check_supported(VBE_DISPI_ID_ANYX);
257
258         DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
259
260         /* Map guest-heap at end of vram */
261         vbox->guest_heap =
262             pci_iomap_range(vbox->ddev.pdev, 0, GUEST_HEAP_OFFSET(vbox),
263                             GUEST_HEAP_SIZE);
264         if (!vbox->guest_heap)
265                 return -ENOMEM;
266
267         /* Create guest-heap mem-pool use 2^4 = 16 byte chunks */
268         vbox->guest_pool = gen_pool_create(4, -1);
269         if (!vbox->guest_pool)
270                 goto err_unmap_guest_heap;
271
272         ret = gen_pool_add_virt(vbox->guest_pool,
273                                 (unsigned long)vbox->guest_heap,
274                                 GUEST_HEAP_OFFSET(vbox),
275                                 GUEST_HEAP_USABLE_SIZE, -1);
276         if (ret)
277                 goto err_destroy_guest_pool;
278
279         ret = hgsmi_test_query_conf(vbox->guest_pool);
280         if (ret) {
281                 DRM_ERROR("vboxvideo: hgsmi_test_query_conf failed\n");
282                 goto err_destroy_guest_pool;
283         }
284
285         /* Reduce available VRAM size to reflect the guest heap. */
286         vbox->available_vram_size = GUEST_HEAP_OFFSET(vbox);
287         /* Linux drm represents monitors as a 32-bit array. */
288         hgsmi_query_conf(vbox->guest_pool, VBOX_VBVA_CONF32_MONITOR_COUNT,
289                          &vbox->num_crtcs);
290         vbox->num_crtcs = clamp_t(u32, vbox->num_crtcs, 1, VBOX_MAX_SCREENS);
291
292         if (!have_hgsmi_mode_hints(vbox)) {
293                 ret = -ENOTSUPP;
294                 goto err_destroy_guest_pool;
295         }
296
297         vbox->last_mode_hints = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs,
298                                              sizeof(struct vbva_modehint),
299                                              GFP_KERNEL);
300         if (!vbox->last_mode_hints) {
301                 ret = -ENOMEM;
302                 goto err_destroy_guest_pool;
303         }
304
305         ret = vbox_accel_init(vbox);
306         if (ret)
307                 goto err_destroy_guest_pool;
308
309         return 0;
310
311 err_destroy_guest_pool:
312         gen_pool_destroy(vbox->guest_pool);
313 err_unmap_guest_heap:
314         pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
315         return ret;
316 }
317
318 void vbox_hw_fini(struct vbox_private *vbox)
319 {
320         vbox_accel_fini(vbox);
321         gen_pool_destroy(vbox->guest_pool);
322         pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
323 }
324
325 int vbox_gem_create(struct vbox_private *vbox,
326                     u32 size, bool iskernel, struct drm_gem_object **obj)
327 {
328         struct vbox_bo *vboxbo;
329         int ret;
330
331         *obj = NULL;
332
333         size = roundup(size, PAGE_SIZE);
334         if (size == 0)
335                 return -EINVAL;
336
337         ret = vbox_bo_create(vbox, size, 0, 0, &vboxbo);
338         if (ret) {
339                 if (ret != -ERESTARTSYS)
340                         DRM_ERROR("failed to allocate GEM object\n");
341                 return ret;
342         }
343
344         *obj = &vboxbo->gem;
345
346         return 0;
347 }
348
349 int vbox_dumb_create(struct drm_file *file,
350                      struct drm_device *dev, struct drm_mode_create_dumb *args)
351 {
352         struct vbox_private *vbox =
353                 container_of(dev, struct vbox_private, ddev);
354         struct drm_gem_object *gobj;
355         u32 handle;
356         int ret;
357
358         args->pitch = args->width * ((args->bpp + 7) / 8);
359         args->size = args->pitch * args->height;
360
361         ret = vbox_gem_create(vbox, args->size, false, &gobj);
362         if (ret)
363                 return ret;
364
365         ret = drm_gem_handle_create(file, gobj, &handle);
366         drm_gem_object_put_unlocked(gobj);
367         if (ret)
368                 return ret;
369
370         args->handle = handle;
371
372         return 0;
373 }
374
375 void vbox_gem_free_object(struct drm_gem_object *obj)
376 {
377         struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj);
378
379         ttm_bo_put(&vbox_bo->bo);
380 }
381
382 static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo)
383 {
384         return drm_vma_node_offset_addr(&bo->bo.vma_node);
385 }
386
387 int
388 vbox_dumb_mmap_offset(struct drm_file *file,
389                       struct drm_device *dev,
390                       u32 handle, u64 *offset)
391 {
392         struct drm_gem_object *obj;
393         int ret;
394         struct vbox_bo *bo;
395
396         mutex_lock(&dev->struct_mutex);
397         obj = drm_gem_object_lookup(file, handle);
398         if (!obj) {
399                 ret = -ENOENT;
400                 goto out_unlock;
401         }
402
403         bo = gem_to_vbox_bo(obj);
404         *offset = vbox_bo_mmap_offset(bo);
405
406         drm_gem_object_put(obj);
407         ret = 0;
408
409 out_unlock:
410         mutex_unlock(&dev->struct_mutex);
411         return ret;
412 }