]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/vboxvideo/vbox_main.c
drm/vboxvideo: Switch to drm_atomic_helper_dirty_fb()
[linux.git] / drivers / gpu / drm / vboxvideo / vbox_main.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright (C) 2013-2017 Oracle Corporation
4  * This file is based on ast_main.c
5  * Copyright 2012 Red Hat Inc.
6  * Authors: Dave Airlie <airlied@redhat.com>,
7  *          Michael Thayer <michael.thayer@oracle.com,
8  *          Hans de Goede <hdegoede@redhat.com>
9  */
10
11 #include <linux/vbox_err.h>
12 #include <drm/drm_fb_helper.h>
13 #include <drm/drm_crtc_helper.h>
14 #include <drm/drm_damage_helper.h>
15
16 #include "vbox_drv.h"
17 #include "vboxvideo_guest.h"
18 #include "vboxvideo_vbe.h"
19
20 static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb)
21 {
22         struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb);
23
24         if (vbox_fb->obj)
25                 drm_gem_object_put_unlocked(vbox_fb->obj);
26
27         drm_framebuffer_cleanup(fb);
28         kfree(fb);
29 }
30
31 void vbox_report_caps(struct vbox_private *vbox)
32 {
33         u32 caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION |
34                    VBVACAPS_IRQ | VBVACAPS_USE_VBVA_ONLY;
35
36         /* The host only accepts VIDEO_MODE_HINTS if it is send separately. */
37         hgsmi_send_caps_info(vbox->guest_pool, caps);
38         caps |= VBVACAPS_VIDEO_MODE_HINTS;
39         hgsmi_send_caps_info(vbox->guest_pool, caps);
40 }
41
42 static const struct drm_framebuffer_funcs vbox_fb_funcs = {
43         .destroy = vbox_user_framebuffer_destroy,
44         .dirty = drm_atomic_helper_dirtyfb,
45 };
46
47 int vbox_framebuffer_init(struct vbox_private *vbox,
48                           struct vbox_framebuffer *vbox_fb,
49                           const struct drm_mode_fb_cmd2 *mode_cmd,
50                           struct drm_gem_object *obj)
51 {
52         int ret;
53
54         drm_helper_mode_fill_fb_struct(&vbox->ddev, &vbox_fb->base, mode_cmd);
55         vbox_fb->obj = obj;
56         ret = drm_framebuffer_init(&vbox->ddev, &vbox_fb->base, &vbox_fb_funcs);
57         if (ret) {
58                 DRM_ERROR("framebuffer init failed %d\n", ret);
59                 return ret;
60         }
61
62         return 0;
63 }
64
65 static int vbox_accel_init(struct vbox_private *vbox)
66 {
67         struct vbva_buffer *vbva;
68         unsigned int i;
69
70         vbox->vbva_info = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs,
71                                        sizeof(*vbox->vbva_info), GFP_KERNEL);
72         if (!vbox->vbva_info)
73                 return -ENOMEM;
74
75         /* Take a command buffer for each screen from the end of usable VRAM. */
76         vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
77
78         vbox->vbva_buffers = pci_iomap_range(vbox->ddev.pdev, 0,
79                                              vbox->available_vram_size,
80                                              vbox->num_crtcs *
81                                              VBVA_MIN_BUFFER_SIZE);
82         if (!vbox->vbva_buffers)
83                 return -ENOMEM;
84
85         for (i = 0; i < vbox->num_crtcs; ++i) {
86                 vbva_setup_buffer_context(&vbox->vbva_info[i],
87                                           vbox->available_vram_size +
88                                           i * VBVA_MIN_BUFFER_SIZE,
89                                           VBVA_MIN_BUFFER_SIZE);
90                 vbva = (void __force *)vbox->vbva_buffers +
91                         i * VBVA_MIN_BUFFER_SIZE;
92                 if (!vbva_enable(&vbox->vbva_info[i],
93                                  vbox->guest_pool, vbva, i)) {
94                         /* very old host or driver error. */
95                         DRM_ERROR("vboxvideo: vbva_enable failed\n");
96                 }
97         }
98
99         return 0;
100 }
101
102 static void vbox_accel_fini(struct vbox_private *vbox)
103 {
104         unsigned int i;
105
106         for (i = 0; i < vbox->num_crtcs; ++i)
107                 vbva_disable(&vbox->vbva_info[i], vbox->guest_pool, i);
108
109         pci_iounmap(vbox->ddev.pdev, vbox->vbva_buffers);
110 }
111
112 /* Do we support the 4.3 plus mode hint reporting interface? */
113 static bool have_hgsmi_mode_hints(struct vbox_private *vbox)
114 {
115         u32 have_hints, have_cursor;
116         int ret;
117
118         ret = hgsmi_query_conf(vbox->guest_pool,
119                                VBOX_VBVA_CONF32_MODE_HINT_REPORTING,
120                                &have_hints);
121         if (ret)
122                 return false;
123
124         ret = hgsmi_query_conf(vbox->guest_pool,
125                                VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING,
126                                &have_cursor);
127         if (ret)
128                 return false;
129
130         return have_hints == VINF_SUCCESS && have_cursor == VINF_SUCCESS;
131 }
132
133 bool vbox_check_supported(u16 id)
134 {
135         u16 dispi_id;
136
137         vbox_write_ioport(VBE_DISPI_INDEX_ID, id);
138         dispi_id = inw(VBE_DISPI_IOPORT_DATA);
139
140         return dispi_id == id;
141 }
142
143 int vbox_hw_init(struct vbox_private *vbox)
144 {
145         int ret = -ENOMEM;
146
147         vbox->full_vram_size = inl(VBE_DISPI_IOPORT_DATA);
148         vbox->any_pitch = vbox_check_supported(VBE_DISPI_ID_ANYX);
149
150         DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
151
152         /* Map guest-heap at end of vram */
153         vbox->guest_heap =
154             pci_iomap_range(vbox->ddev.pdev, 0, GUEST_HEAP_OFFSET(vbox),
155                             GUEST_HEAP_SIZE);
156         if (!vbox->guest_heap)
157                 return -ENOMEM;
158
159         /* Create guest-heap mem-pool use 2^4 = 16 byte chunks */
160         vbox->guest_pool = gen_pool_create(4, -1);
161         if (!vbox->guest_pool)
162                 goto err_unmap_guest_heap;
163
164         ret = gen_pool_add_virt(vbox->guest_pool,
165                                 (unsigned long)vbox->guest_heap,
166                                 GUEST_HEAP_OFFSET(vbox),
167                                 GUEST_HEAP_USABLE_SIZE, -1);
168         if (ret)
169                 goto err_destroy_guest_pool;
170
171         ret = hgsmi_test_query_conf(vbox->guest_pool);
172         if (ret) {
173                 DRM_ERROR("vboxvideo: hgsmi_test_query_conf failed\n");
174                 goto err_destroy_guest_pool;
175         }
176
177         /* Reduce available VRAM size to reflect the guest heap. */
178         vbox->available_vram_size = GUEST_HEAP_OFFSET(vbox);
179         /* Linux drm represents monitors as a 32-bit array. */
180         hgsmi_query_conf(vbox->guest_pool, VBOX_VBVA_CONF32_MONITOR_COUNT,
181                          &vbox->num_crtcs);
182         vbox->num_crtcs = clamp_t(u32, vbox->num_crtcs, 1, VBOX_MAX_SCREENS);
183
184         if (!have_hgsmi_mode_hints(vbox)) {
185                 ret = -ENOTSUPP;
186                 goto err_destroy_guest_pool;
187         }
188
189         vbox->last_mode_hints = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs,
190                                              sizeof(struct vbva_modehint),
191                                              GFP_KERNEL);
192         if (!vbox->last_mode_hints) {
193                 ret = -ENOMEM;
194                 goto err_destroy_guest_pool;
195         }
196
197         ret = vbox_accel_init(vbox);
198         if (ret)
199                 goto err_destroy_guest_pool;
200
201         return 0;
202
203 err_destroy_guest_pool:
204         gen_pool_destroy(vbox->guest_pool);
205 err_unmap_guest_heap:
206         pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
207         return ret;
208 }
209
210 void vbox_hw_fini(struct vbox_private *vbox)
211 {
212         vbox_accel_fini(vbox);
213         gen_pool_destroy(vbox->guest_pool);
214         pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
215 }
216
217 int vbox_gem_create(struct vbox_private *vbox,
218                     u32 size, bool iskernel, struct drm_gem_object **obj)
219 {
220         struct drm_gem_vram_object *gbo;
221         int ret;
222
223         *obj = NULL;
224
225         size = roundup(size, PAGE_SIZE);
226         if (size == 0)
227                 return -EINVAL;
228
229         gbo = drm_gem_vram_create(&vbox->ddev, &vbox->ddev.vram_mm->bdev,
230                                   size, 0, false);
231         if (IS_ERR(gbo)) {
232                 ret = PTR_ERR(gbo);
233                 if (ret != -ERESTARTSYS)
234                         DRM_ERROR("failed to allocate GEM object\n");
235                 return ret;
236         }
237
238         *obj = &gbo->bo.base;
239
240         return 0;
241 }