1131abc56SHans de Goede // SPDX-License-Identifier: MIT 2131abc56SHans de Goede /* 3131abc56SHans de Goede * Copyright (C) 2013-2017 Oracle Corporation 4131abc56SHans de Goede * This file is based on ast_main.c 5131abc56SHans de Goede * Copyright 2012 Red Hat Inc. 6131abc56SHans de Goede * Authors: Dave Airlie <airlied@redhat.com>, 7131abc56SHans de Goede * Michael Thayer <michael.thayer@oracle.com, 8131abc56SHans de Goede * Hans de Goede <hdegoede@redhat.com> 9131abc56SHans de Goede */ 10131abc56SHans de Goede 1156492fe9SThomas Zimmermann #include <linux/pci.h> 12131abc56SHans de Goede #include <linux/vbox_err.h> 1356492fe9SThomas Zimmermann 14131abc56SHans de Goede #include <drm/drm_fb_helper.h> 15131abc56SHans de Goede #include <drm/drm_crtc_helper.h> 161a74ccfaSThomas Zimmermann #include <drm/drm_damage_helper.h> 17131abc56SHans de Goede 18131abc56SHans de Goede #include "vbox_drv.h" 19131abc56SHans de Goede #include "vboxvideo_guest.h" 20131abc56SHans de Goede #include "vboxvideo_vbe.h" 21131abc56SHans de Goede 22131abc56SHans de Goede void vbox_report_caps(struct vbox_private *vbox) 23131abc56SHans de Goede { 24131abc56SHans de Goede u32 caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION | 25131abc56SHans de Goede VBVACAPS_IRQ | VBVACAPS_USE_VBVA_ONLY; 26131abc56SHans de Goede 27131abc56SHans de Goede /* The host only accepts VIDEO_MODE_HINTS if it is send separately. */ 28131abc56SHans de Goede hgsmi_send_caps_info(vbox->guest_pool, caps); 29131abc56SHans de Goede caps |= VBVACAPS_VIDEO_MODE_HINTS; 30131abc56SHans de Goede hgsmi_send_caps_info(vbox->guest_pool, caps); 31131abc56SHans de Goede } 32131abc56SHans de Goede 33131abc56SHans de Goede static int vbox_accel_init(struct vbox_private *vbox) 34131abc56SHans de Goede { 3556492fe9SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(vbox->ddev.dev); 36131abc56SHans de Goede struct vbva_buffer *vbva; 37131abc56SHans de Goede unsigned int i; 38131abc56SHans de Goede 39131abc56SHans de Goede vbox->vbva_info = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs, 40131abc56SHans de Goede sizeof(*vbox->vbva_info), GFP_KERNEL); 41131abc56SHans de Goede if (!vbox->vbva_info) 42131abc56SHans de Goede return -ENOMEM; 43131abc56SHans de Goede 44131abc56SHans de Goede /* Take a command buffer for each screen from the end of usable VRAM. */ 45131abc56SHans de Goede vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE; 46131abc56SHans de Goede 4756492fe9SThomas Zimmermann vbox->vbva_buffers = pci_iomap_range(pdev, 0, 48131abc56SHans de Goede vbox->available_vram_size, 49131abc56SHans de Goede vbox->num_crtcs * 50131abc56SHans de Goede VBVA_MIN_BUFFER_SIZE); 51131abc56SHans de Goede if (!vbox->vbva_buffers) 52131abc56SHans de Goede return -ENOMEM; 53131abc56SHans de Goede 54131abc56SHans de Goede for (i = 0; i < vbox->num_crtcs; ++i) { 55131abc56SHans de Goede vbva_setup_buffer_context(&vbox->vbva_info[i], 56131abc56SHans de Goede vbox->available_vram_size + 57131abc56SHans de Goede i * VBVA_MIN_BUFFER_SIZE, 58131abc56SHans de Goede VBVA_MIN_BUFFER_SIZE); 59131abc56SHans de Goede vbva = (void __force *)vbox->vbva_buffers + 60131abc56SHans de Goede i * VBVA_MIN_BUFFER_SIZE; 61131abc56SHans de Goede if (!vbva_enable(&vbox->vbva_info[i], 62131abc56SHans de Goede vbox->guest_pool, vbva, i)) { 63131abc56SHans de Goede /* very old host or driver error. */ 64131abc56SHans de Goede DRM_ERROR("vboxvideo: vbva_enable failed\n"); 65131abc56SHans de Goede } 66131abc56SHans de Goede } 67131abc56SHans de Goede 68131abc56SHans de Goede return 0; 69131abc56SHans de Goede } 70131abc56SHans de Goede 71131abc56SHans de Goede static void vbox_accel_fini(struct vbox_private *vbox) 72131abc56SHans de Goede { 73131abc56SHans de Goede unsigned int i; 74131abc56SHans de Goede 75131abc56SHans de Goede for (i = 0; i < vbox->num_crtcs; ++i) 76131abc56SHans de Goede vbva_disable(&vbox->vbva_info[i], vbox->guest_pool, i); 77131abc56SHans de Goede } 78131abc56SHans de Goede 79131abc56SHans de Goede /* Do we support the 4.3 plus mode hint reporting interface? */ 80131abc56SHans de Goede static bool have_hgsmi_mode_hints(struct vbox_private *vbox) 81131abc56SHans de Goede { 82131abc56SHans de Goede u32 have_hints, have_cursor; 83131abc56SHans de Goede int ret; 84131abc56SHans de Goede 85131abc56SHans de Goede ret = hgsmi_query_conf(vbox->guest_pool, 86131abc56SHans de Goede VBOX_VBVA_CONF32_MODE_HINT_REPORTING, 87131abc56SHans de Goede &have_hints); 88131abc56SHans de Goede if (ret) 89131abc56SHans de Goede return false; 90131abc56SHans de Goede 91131abc56SHans de Goede ret = hgsmi_query_conf(vbox->guest_pool, 92131abc56SHans de Goede VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING, 93131abc56SHans de Goede &have_cursor); 94131abc56SHans de Goede if (ret) 95131abc56SHans de Goede return false; 96131abc56SHans de Goede 97131abc56SHans de Goede return have_hints == VINF_SUCCESS && have_cursor == VINF_SUCCESS; 98131abc56SHans de Goede } 99131abc56SHans de Goede 100131abc56SHans de Goede bool vbox_check_supported(u16 id) 101131abc56SHans de Goede { 102131abc56SHans de Goede u16 dispi_id; 103131abc56SHans de Goede 104131abc56SHans de Goede vbox_write_ioport(VBE_DISPI_INDEX_ID, id); 105131abc56SHans de Goede dispi_id = inw(VBE_DISPI_IOPORT_DATA); 106131abc56SHans de Goede 107131abc56SHans de Goede return dispi_id == id; 108131abc56SHans de Goede } 109131abc56SHans de Goede 110131abc56SHans de Goede int vbox_hw_init(struct vbox_private *vbox) 111131abc56SHans de Goede { 11256492fe9SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(vbox->ddev.dev); 113131abc56SHans de Goede int ret = -ENOMEM; 114131abc56SHans de Goede 115131abc56SHans de Goede vbox->full_vram_size = inl(VBE_DISPI_IOPORT_DATA); 116131abc56SHans de Goede vbox->any_pitch = vbox_check_supported(VBE_DISPI_ID_ANYX); 117131abc56SHans de Goede 118131abc56SHans de Goede DRM_INFO("VRAM %08x\n", vbox->full_vram_size); 119131abc56SHans de Goede 120131abc56SHans de Goede /* Map guest-heap at end of vram */ 121131abc56SHans de Goede vbox->guest_heap = 12256492fe9SThomas Zimmermann pci_iomap_range(pdev, 0, GUEST_HEAP_OFFSET(vbox), 123131abc56SHans de Goede GUEST_HEAP_SIZE); 124131abc56SHans de Goede if (!vbox->guest_heap) 125131abc56SHans de Goede return -ENOMEM; 126131abc56SHans de Goede 127131abc56SHans de Goede /* Create guest-heap mem-pool use 2^4 = 16 byte chunks */ 1284cc9b565SDaniel Vetter vbox->guest_pool = devm_gen_pool_create(vbox->ddev.dev, 4, -1, 1294cc9b565SDaniel Vetter "vboxvideo-accel"); 130*cebbb5c4SDan Carpenter if (IS_ERR(vbox->guest_pool)) 131*cebbb5c4SDan Carpenter return PTR_ERR(vbox->guest_pool); 132131abc56SHans de Goede 133131abc56SHans de Goede ret = gen_pool_add_virt(vbox->guest_pool, 134131abc56SHans de Goede (unsigned long)vbox->guest_heap, 135131abc56SHans de Goede GUEST_HEAP_OFFSET(vbox), 136131abc56SHans de Goede GUEST_HEAP_USABLE_SIZE, -1); 137131abc56SHans de Goede if (ret) 1384cc9b565SDaniel Vetter return ret; 139131abc56SHans de Goede 140131abc56SHans de Goede ret = hgsmi_test_query_conf(vbox->guest_pool); 141131abc56SHans de Goede if (ret) { 142131abc56SHans de Goede DRM_ERROR("vboxvideo: hgsmi_test_query_conf failed\n"); 1434cc9b565SDaniel Vetter return ret; 144131abc56SHans de Goede } 145131abc56SHans de Goede 146131abc56SHans de Goede /* Reduce available VRAM size to reflect the guest heap. */ 147131abc56SHans de Goede vbox->available_vram_size = GUEST_HEAP_OFFSET(vbox); 148131abc56SHans de Goede /* Linux drm represents monitors as a 32-bit array. */ 149131abc56SHans de Goede hgsmi_query_conf(vbox->guest_pool, VBOX_VBVA_CONF32_MONITOR_COUNT, 150131abc56SHans de Goede &vbox->num_crtcs); 151131abc56SHans de Goede vbox->num_crtcs = clamp_t(u32, vbox->num_crtcs, 1, VBOX_MAX_SCREENS); 152131abc56SHans de Goede 153131abc56SHans de Goede if (!have_hgsmi_mode_hints(vbox)) { 154131abc56SHans de Goede ret = -ENOTSUPP; 1554cc9b565SDaniel Vetter return ret; 156131abc56SHans de Goede } 157131abc56SHans de Goede 158131abc56SHans de Goede vbox->last_mode_hints = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs, 159131abc56SHans de Goede sizeof(struct vbva_modehint), 160131abc56SHans de Goede GFP_KERNEL); 1614cc9b565SDaniel Vetter if (!vbox->last_mode_hints) 1624cc9b565SDaniel Vetter return -ENOMEM; 163131abc56SHans de Goede 164131abc56SHans de Goede ret = vbox_accel_init(vbox); 165131abc56SHans de Goede if (ret) 1664cc9b565SDaniel Vetter return ret; 167131abc56SHans de Goede 168131abc56SHans de Goede return 0; 169131abc56SHans de Goede } 170131abc56SHans de Goede 171131abc56SHans de Goede void vbox_hw_fini(struct vbox_private *vbox) 172131abc56SHans de Goede { 173131abc56SHans de Goede vbox_accel_fini(vbox); 174131abc56SHans de Goede } 175