1 // SPDX-License-Identifier: MIT
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>
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>
17 #include "vboxvideo_guest.h"
18 #include "vboxvideo_vbe.h"
20 void vbox_report_caps(struct vbox_private
*vbox
)
22 u32 caps
= VBVACAPS_DISABLE_CURSOR_INTEGRATION
|
23 VBVACAPS_IRQ
| VBVACAPS_USE_VBVA_ONLY
;
25 /* The host only accepts VIDEO_MODE_HINTS if it is send separately. */
26 hgsmi_send_caps_info(vbox
->guest_pool
, caps
);
27 caps
|= VBVACAPS_VIDEO_MODE_HINTS
;
28 hgsmi_send_caps_info(vbox
->guest_pool
, caps
);
31 static int vbox_accel_init(struct vbox_private
*vbox
)
33 struct vbva_buffer
*vbva
;
36 vbox
->vbva_info
= devm_kcalloc(vbox
->ddev
.dev
, vbox
->num_crtcs
,
37 sizeof(*vbox
->vbva_info
), GFP_KERNEL
);
41 /* Take a command buffer for each screen from the end of usable VRAM. */
42 vbox
->available_vram_size
-= vbox
->num_crtcs
* VBVA_MIN_BUFFER_SIZE
;
44 vbox
->vbva_buffers
= pci_iomap_range(vbox
->ddev
.pdev
, 0,
45 vbox
->available_vram_size
,
47 VBVA_MIN_BUFFER_SIZE
);
48 if (!vbox
->vbva_buffers
)
51 for (i
= 0; i
< vbox
->num_crtcs
; ++i
) {
52 vbva_setup_buffer_context(&vbox
->vbva_info
[i
],
53 vbox
->available_vram_size
+
54 i
* VBVA_MIN_BUFFER_SIZE
,
55 VBVA_MIN_BUFFER_SIZE
);
56 vbva
= (void __force
*)vbox
->vbva_buffers
+
57 i
* VBVA_MIN_BUFFER_SIZE
;
58 if (!vbva_enable(&vbox
->vbva_info
[i
],
59 vbox
->guest_pool
, vbva
, i
)) {
60 /* very old host or driver error. */
61 DRM_ERROR("vboxvideo: vbva_enable failed\n");
68 static void vbox_accel_fini(struct vbox_private
*vbox
)
72 for (i
= 0; i
< vbox
->num_crtcs
; ++i
)
73 vbva_disable(&vbox
->vbva_info
[i
], vbox
->guest_pool
, i
);
76 /* Do we support the 4.3 plus mode hint reporting interface? */
77 static bool have_hgsmi_mode_hints(struct vbox_private
*vbox
)
79 u32 have_hints
, have_cursor
;
82 ret
= hgsmi_query_conf(vbox
->guest_pool
,
83 VBOX_VBVA_CONF32_MODE_HINT_REPORTING
,
88 ret
= hgsmi_query_conf(vbox
->guest_pool
,
89 VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING
,
94 return have_hints
== VINF_SUCCESS
&& have_cursor
== VINF_SUCCESS
;
97 bool vbox_check_supported(u16 id
)
101 vbox_write_ioport(VBE_DISPI_INDEX_ID
, id
);
102 dispi_id
= inw(VBE_DISPI_IOPORT_DATA
);
104 return dispi_id
== id
;
107 int vbox_hw_init(struct vbox_private
*vbox
)
111 vbox
->full_vram_size
= inl(VBE_DISPI_IOPORT_DATA
);
112 vbox
->any_pitch
= vbox_check_supported(VBE_DISPI_ID_ANYX
);
114 DRM_INFO("VRAM %08x\n", vbox
->full_vram_size
);
116 /* Map guest-heap at end of vram */
118 pci_iomap_range(vbox
->ddev
.pdev
, 0, GUEST_HEAP_OFFSET(vbox
),
120 if (!vbox
->guest_heap
)
123 /* Create guest-heap mem-pool use 2^4 = 16 byte chunks */
124 vbox
->guest_pool
= devm_gen_pool_create(vbox
->ddev
.dev
, 4, -1,
126 if (!vbox
->guest_pool
)
129 ret
= gen_pool_add_virt(vbox
->guest_pool
,
130 (unsigned long)vbox
->guest_heap
,
131 GUEST_HEAP_OFFSET(vbox
),
132 GUEST_HEAP_USABLE_SIZE
, -1);
136 ret
= hgsmi_test_query_conf(vbox
->guest_pool
);
138 DRM_ERROR("vboxvideo: hgsmi_test_query_conf failed\n");
142 /* Reduce available VRAM size to reflect the guest heap. */
143 vbox
->available_vram_size
= GUEST_HEAP_OFFSET(vbox
);
144 /* Linux drm represents monitors as a 32-bit array. */
145 hgsmi_query_conf(vbox
->guest_pool
, VBOX_VBVA_CONF32_MONITOR_COUNT
,
147 vbox
->num_crtcs
= clamp_t(u32
, vbox
->num_crtcs
, 1, VBOX_MAX_SCREENS
);
149 if (!have_hgsmi_mode_hints(vbox
)) {
154 vbox
->last_mode_hints
= devm_kcalloc(vbox
->ddev
.dev
, vbox
->num_crtcs
,
155 sizeof(struct vbva_modehint
),
157 if (!vbox
->last_mode_hints
)
160 ret
= vbox_accel_init(vbox
);
167 void vbox_hw_fini(struct vbox_private
*vbox
)
169 vbox_accel_fini(vbox
);