Commit dd55d44f authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman

staging: vboxvideo: Add vboxvideo to drivers/staging

This commit adds the vboxvideo drm/kms driver for the virtual graphics
card used in Virtual Box virtual machines to drivers/staging.

Why drivers/staging? This driver is already being patched into the kernel
by several distros, thus it is good to get this driver upstream soon, so
that work on the driver can be easily shared.

At the same time we want to take our time to get this driver properly
cleaned up (mainly converted to the new atomic modesetting APIs) before
submitting it as a normal driver under drivers/gpu/drm, putting this
driver in staging for now allows both.

Note this driver has already been significantly cleaned up, when I started
working on this the files under /usr/src/vboxguest/vboxvideo as installed
by Virtual Box 5.1.18 Guest Additions had a total linecount of 52681
lines. The version in this commit has 4874 lines.

Cc: vbox-dev@virtualbox.org
Cc: Michael Thayer <michael.thayer@oracle.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMichael Thayer <michael.thayer@oracle.com>
Acked-by: default avatarDaniel Vetter <daniel@ffwll.ch>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 677e6a1a
...@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig" ...@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"
source "drivers/staging/typec/Kconfig" source "drivers/staging/typec/Kconfig"
source "drivers/staging/vboxvideo/Kconfig"
endif # STAGING endif # STAGING
...@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010) += ks7010/ ...@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010) += ks7010/
obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_GREYBUS) += greybus/
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/ obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/
config DRM_VBOXVIDEO
tristate "Virtual Box Graphics Card"
depends on DRM && X86 && PCI
select DRM_KMS_HELPER
help
This is a KMS driver for the virtual Graphics Card used in
Virtual Box virtual machines.
Although it is possible to builtin this module, it is advised
to build this driver as a module, so that it can be updated
independently of the kernel. Select M to built this driver as a
module and add support for these devices via drm/kms interfaces.
ccflags-y := -Iinclude/drm
vboxvideo-y := hgsmi_base.o modesetting.o vbva_base.o \
vbox_drv.o vbox_fb.o vbox_hgsmi.o vbox_irq.o vbox_main.o \
vbox_mode.o vbox_prime.o vbox_ttm.o
obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo.o
TODO:
-Move the driver over to the atomic API
-Stop using old load / unload drm_driver hooks
-Get a full review from the drm-maintainers on dri-devel done on this driver
-Extend this TODO with the results of that review
Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Hans de Goede <hdegoede@redhat.com> and
Michael Thayer <michael.thayer@oracle.com>.
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "vbox_drv.h"
#include "vbox_err.h"
#include "vboxvideo_guest.h"
#include "vboxvideo_vbe.h"
#include "hgsmi_channels.h"
#include "hgsmi_ch_setup.h"
/**
* Inform the host of the location of the host flags in VRAM via an HGSMI cmd.
* @param ctx the context of the guest heap to use.
* @param location the offset chosen for the flags within guest VRAM.
* @returns 0 on success, -errno on failure
*/
int hgsmi_report_flags_location(struct gen_pool *ctx, u32 location)
{
struct hgsmi_buffer_location *p;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_HGSMI,
HGSMI_CC_HOST_FLAGS_LOCATION);
if (!p)
return -ENOMEM;
p->buf_location = location;
p->buf_len = sizeof(struct hgsmi_host_flags);
hgsmi_buffer_submit(ctx, p);
hgsmi_buffer_free(ctx, p);
return 0;
}
/**
* Notify the host of HGSMI-related guest capabilities via an HGSMI command.
* @param ctx the context of the guest heap to use.
* @param caps the capabilities to report, see vbva_caps.
* @returns 0 on success, -errno on failure
*/
int hgsmi_send_caps_info(struct gen_pool *ctx, u32 caps)
{
struct vbva_caps *p;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_INFO_CAPS);
if (!p)
return -ENOMEM;
p->rc = VERR_NOT_IMPLEMENTED;
p->caps = caps;
hgsmi_buffer_submit(ctx, p);
WARN_ON_ONCE(RT_FAILURE(p->rc));
hgsmi_buffer_free(ctx, p);
return 0;
}
int hgsmi_test_query_conf(struct gen_pool *ctx)
{
u32 value = 0;
int ret;
ret = hgsmi_query_conf(ctx, U32_MAX, &value);
if (ret)
return ret;
return value == U32_MAX ? 0 : -EIO;
}
/**
* Query the host for an HGSMI configuration parameter via an HGSMI command.
* @param ctx the context containing the heap used
* @param index the index of the parameter to query,
* @see vbva_conf32::index
* @param value_ret where to store the value of the parameter on success
* @returns 0 on success, -errno on failure
*/
int hgsmi_query_conf(struct gen_pool *ctx, u32 index, u32 *value_ret)
{
struct vbva_conf32 *p;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
VBVA_QUERY_CONF32);
if (!p)
return -ENOMEM;
p->index = index;
p->value = U32_MAX;
hgsmi_buffer_submit(ctx, p);
*value_ret = p->value;
hgsmi_buffer_free(ctx, p);
return 0;
}
/**
* Pass the host a new mouse pointer shape via an HGSMI command.
*
* @param ctx the context containing the heap to be used
* @param flags cursor flags, @see VMMDevReqMousePointer::flags
* @param hot_x horizontal position of the hot spot
* @param hot_y vertical position of the hot spot
* @param width width in pixels of the cursor
* @param height height in pixels of the cursor
* @param pixels pixel data, @see VMMDevReqMousePointer for the format
* @param len size in bytes of the pixel data
* @returns 0 on success, -errno on failure
*/
int hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
u32 hot_x, u32 hot_y, u32 width, u32 height,
u8 *pixels, u32 len)
{
struct vbva_mouse_pointer_shape *p;
u32 pixel_len = 0;
int rc;
if (flags & VBOX_MOUSE_POINTER_SHAPE) {
/*
* Size of the pointer data:
* sizeof (AND mask) + sizeof (XOR_MASK)
*/
pixel_len = ((((width + 7) / 8) * height + 3) & ~3) +
width * 4 * height;
if (pixel_len > len)
return -EINVAL;
/*
* If shape is supplied, then always create the pointer visible.
* See comments in 'vboxUpdatePointerShape'
*/
flags |= VBOX_MOUSE_POINTER_VISIBLE;
}
p = hgsmi_buffer_alloc(ctx, sizeof(*p) + pixel_len, HGSMI_CH_VBVA,
VBVA_MOUSE_POINTER_SHAPE);
if (!p)
return -ENOMEM;
p->result = VINF_SUCCESS;
p->flags = flags;
p->hot_X = hot_x;
p->hot_y = hot_y;
p->width = width;
p->height = height;
if (pixel_len)
memcpy(p->data, pixels, pixel_len);
hgsmi_buffer_submit(ctx, p);
switch (p->result) {
case VINF_SUCCESS:
rc = 0;
break;
case VERR_NO_MEMORY:
rc = -ENOMEM;
break;
case VERR_NOT_SUPPORTED:
rc = -EBUSY;
break;
default:
rc = -EINVAL;
}
hgsmi_buffer_free(ctx, p);
return rc;
}
/**
* Report the guest cursor position. The host may wish to use this information
* to re-position its own cursor (though this is currently unlikely). The
* current host cursor position is returned.
* @param ctx The context containing the heap used.
* @param report_position Are we reporting a position?
* @param x Guest cursor X position.
* @param y Guest cursor Y position.
* @param x_host Host cursor X position is stored here. Optional.
* @param y_host Host cursor Y position is stored here. Optional.
* @returns 0 on success, -errno on failure
*/
int hgsmi_cursor_position(struct gen_pool *ctx, bool report_position,
u32 x, u32 y, u32 *x_host, u32 *y_host)
{
struct vbva_cursor_position *p;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
VBVA_CURSOR_POSITION);
if (!p)
return -ENOMEM;
p->report_position = report_position;
p->x = x;
p->y = y;
hgsmi_buffer_submit(ctx, p);
*x_host = p->x;
*y_host = p->y;
hgsmi_buffer_free(ctx, p);
return 0;
}
/**
* @todo Mouse pointer position to be read from VMMDev memory, address of the
* memory region can be queried from VMMDev via an IOCTL. This VMMDev memory
* region will contain host information which is needed by the guest.
*
* Reading will not cause a switch to the host.
*
* Have to take into account:
* * synchronization: host must write to the memory only from EMT,
* large structures must be read under flag, which tells the host
* that the guest is currently reading the memory (OWNER flag?).
* * guest writes: may be allocate a page for the host info and make
* the page readonly for the guest.
* * the information should be available only for additions drivers.
* * VMMDev additions driver will inform the host which version of the info
* it expects, host must support all versions.
*/
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __HGSMI_CH_SETUP_H__
#define __HGSMI_CH_SETUP_H__
/*
* Tell the host the location of hgsmi_host_flags structure, where the host
* can write information about pending buffers, etc, and which can be quickly
* polled by the guest without a need to port IO.
*/
#define HGSMI_CC_HOST_FLAGS_LOCATION 0
struct hgsmi_buffer_location {
u32 buf_location;
u32 buf_len;
} __packed;
/* HGSMI setup and configuration data structures. */
/* host->guest commands pending, should be accessed under FIFO lock only */
#define HGSMIHOSTFLAGS_COMMANDS_PENDING 0x01u
/* IRQ is fired, should be accessed under VGAState::lock only */
#define HGSMIHOSTFLAGS_IRQ 0x02u
/* vsync interrupt flag, should be accessed under VGAState::lock only */
#define HGSMIHOSTFLAGS_VSYNC 0x10u
/** monitor hotplug flag, should be accessed under VGAState::lock only */
#define HGSMIHOSTFLAGS_HOTPLUG 0x20u
/**
* Cursor capability state change flag, should be accessed under
* VGAState::lock only. @see vbva_conf32.
*/
#define HGSMIHOSTFLAGS_CURSOR_CAPABILITIES 0x40u
struct hgsmi_host_flags {
/*
* Host flags can be accessed and modified in multiple threads
* concurrently, e.g. CrOpenGL HGCM and GUI threads when completing
* HGSMI 3D and Video Accel respectively, EMT thread when dealing with
* HGSMI command processing, etc.
* Besides settings/cleaning flags atomically, some flags have their
* own special sync restrictions, see comments for flags above.
*/
u32 host_flags;
u32 reserved[3];
} __packed;
#endif
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __HGSMI_CHANNELS_H__
#define __HGSMI_CHANNELS_H__
/*
* Each channel has an 8 bit identifier. There are a number of predefined
* (hardcoded) channels.
*
* HGSMI_CH_HGSMI channel can be used to map a string channel identifier
* to a free 16 bit numerical value. values are allocated in range
* [HGSMI_CH_STRING_FIRST;HGSMI_CH_STRING_LAST].
*/
/* A reserved channel value */
#define HGSMI_CH_RESERVED 0x00
/* HGCMI: setup and configuration */
#define HGSMI_CH_HGSMI 0x01
/* Graphics: VBVA */
#define HGSMI_CH_VBVA 0x02
/* Graphics: Seamless with a single guest region */
#define HGSMI_CH_SEAMLESS 0x03
/* Graphics: Seamless with separate host windows */
#define HGSMI_CH_SEAMLESS2 0x04
/* Graphics: OpenGL HW acceleration */
#define HGSMI_CH_OPENGL 0x05
/* The first channel index to be used for string mappings (inclusive) */
#define HGSMI_CH_STRING_FIRST 0x20
/* The last channel index for string mappings (inclusive) */
#define HGSMI_CH_STRING_LAST 0xff
#endif
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __HGSMI_DEFS_H__
#define __HGSMI_DEFS_H__
/* Buffer sequence type mask. */
#define HGSMI_BUFFER_HEADER_F_SEQ_MASK 0x03
/* Single buffer, not a part of a sequence. */
#define HGSMI_BUFFER_HEADER_F_SEQ_SINGLE 0x00
/* The first buffer in a sequence. */
#define HGSMI_BUFFER_HEADER_F_SEQ_START 0x01
/* A middle buffer in a sequence. */
#define HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE 0x02
/* The last buffer in a sequence. */
#define HGSMI_BUFFER_HEADER_F_SEQ_END 0x03
/* 16 bytes buffer header. */
struct hgsmi_buffer_header {
u32 data_size; /* Size of data that follows the header. */
u8 flags; /* HGSMI_BUFFER_HEADER_F_* */
u8 channel; /* The channel the data must be routed to. */
u16 channel_info; /* Opaque to the HGSMI, used by the channel. */
union {
/* Opaque placeholder to make the union 8 bytes. */
u8 header_data[8];
/* HGSMI_BUFFER_HEADER_F_SEQ_SINGLE */
struct {
u32 reserved1; /* A reserved field, initialize to 0. */
u32 reserved2; /* A reserved field, initialize to 0. */
} buffer;
/* HGSMI_BUFFER_HEADER_F_SEQ_START */
struct {
/* Must be the same for all buffers in the sequence. */
u32 sequence_number;
/* The total size of the sequence. */
u32 sequence_size;
} sequence_start;
/*
* HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE and
* HGSMI_BUFFER_HEADER_F_SEQ_END
*/
struct {
/* Must be the same for all buffers in the sequence. */
u32 sequence_number;
/* Data offset in the entire sequence. */
u32 sequence_offset;
} sequence_continue;
} u;
} __packed;
/* 8 bytes buffer tail. */
struct hgsmi_buffer_tail {
/* Reserved, must be initialized to 0. */
u32 reserved;
/*
* One-at-a-Time Hash: http://www.burtleburtle.net/bob/hash/doobs.html
* Over the header, offset and for first 4 bytes of the tail.
*/
u32 checksum;
} __packed;
/*
* The size of the array of channels. Array indexes are u8.
* Note: the value must not be changed.
*/
#define HGSMI_NUMBER_OF_CHANNELS 0x100
#endif
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "vbox_drv.h"
#include "vbox_err.h"
#include "vboxvideo_guest.h"
#include "vboxvideo_vbe.h"
#include "hgsmi_channels.h"
/**
* Set a video mode via an HGSMI request. The views must have been
* initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
* set on the first display then it must be set first using registers.
* @param ctx The context containing the heap to use
* @param display The screen number
* @param origin_x The horizontal displacement relative to the first scrn
* @param origin_y The vertical displacement relative to the first screen
* @param start_offset The offset of the visible area of the framebuffer
* relative to the framebuffer start
* @param pitch The offset in bytes between the starts of two adjecent
* scan lines in video RAM
* @param width The mode width
* @param height The mode height
* @param bpp The colour depth of the mode
* @param flags Flags
*/
void hgsmi_process_display_info(struct gen_pool *ctx, u32 display,
s32 origin_x, s32 origin_y, u32 start_offset,
u32 pitch, u32 width, u32 height,
u16 bpp, u16 flags)
{
struct vbva_infoscreen *p;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
VBVA_INFO_SCREEN);
if (!p)
return;
p->view_index = display;
p->origin_x = origin_x;
p->origin_y = origin_y;
p->start_offset = start_offset;
p->line_size = pitch;
p->width = width;
p->height = height;
p->bits_per_pixel = bpp;
p->flags = flags;
hgsmi_buffer_submit(ctx, p);
hgsmi_buffer_free(ctx, p);
}
/**
* Report the rectangle relative to which absolute pointer events should be
* expressed. This information remains valid until the next VBVA resize event
* for any screen, at which time it is reset to the bounding rectangle of all
* virtual screens.
* @param ctx The context containing the heap to use.
* @param origin_x Upper left X co-ordinate relative to the first screen.
* @param origin_y Upper left Y co-ordinate relative to the first screen.
* @param width Rectangle width.
* @param height Rectangle height.
* @returns 0 on success, -errno on failure
*/
int hgsmi_update_input_mapping(struct gen_pool *ctx, s32 origin_x, s32 origin_y,
u32 width, u32 height)
{
struct vbva_report_input_mapping *p;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
VBVA_REPORT_INPUT_MAPPING);
if (!p)
return -ENOMEM;
p->x = origin_x;
p->y = origin_y;
p->cx = width;
p->cy = height;
hgsmi_buffer_submit(ctx, p);
hgsmi_buffer_free(ctx, p);
return 0;
}
/**
* Get most recent video mode hints.
* @param ctx The context containing the heap to use.
* @param screens The number of screens to query hints for, starting at 0.
* @param hints Array of vbva_modehint structures for receiving the hints.
* @returns 0 on success, -errno on failure
*/
int hgsmi_get_mode_hints(struct gen_pool *ctx, unsigned int screens,
struct vbva_modehint *hints)
{
struct vbva_query_mode_hints *p;
size_t size;
if (WARN_ON(!hints))
return -EINVAL;
size = screens * sizeof(struct vbva_modehint);
p = hgsmi_buffer_alloc(ctx, sizeof(*p) + size, HGSMI_CH_VBVA,
VBVA_QUERY_MODE_HINTS);
if (!p)
return -ENOMEM;
p->hints_queried_count = screens;
p->hint_structure_guest_size = sizeof(struct vbva_modehint);
p->rc = VERR_NOT_SUPPORTED;
hgsmi_buffer_submit(ctx, p);
if (RT_FAILURE(p->rc)) {
hgsmi_buffer_free(ctx, p);
return -EIO;
}
memcpy(hints, ((u8 *)p) + sizeof(struct vbva_query_mode_hints), size);
hgsmi_buffer_free(ctx, p);
return 0;
}
/*
* Copyright (C) 2013-2017 Oracle Corporation
* This file is based on ast_drv.c
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* Authors: Dave Airlie <airlied@redhat.com>
* Michael Thayer <michael.thayer@oracle.com,
* Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/module.h>
#include <linux/console.h>
#include <linux/vt_kern.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "vbox_drv.h"
int vbox_modeset = -1;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, vbox_modeset, int, 0400);
static struct drm_driver driver;
static const struct pci_device_id pciidlist[] = {
{ 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0, 0, 0},
};
MODULE_DEVICE_TABLE(pci, pciidlist);
static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
return drm_get_pci_dev(pdev, ent, &driver);
}
static void vbox_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
drm_put_dev(dev);
}
static int vbox_drm_freeze(struct drm_device *dev)
{
struct vbox_private *vbox = dev->dev_private;
drm_kms_helper_poll_disable(dev);
pci_save_state(dev->pdev);
drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
return 0;
}
static int vbox_drm_thaw(struct drm_device *dev)
{
struct vbox_private *vbox = dev->dev_private;
drm_mode_config_reset(dev);
drm_helper_resume_force_mode(dev);
drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
return 0;
}
static int vbox_drm_resume(struct drm_device *dev)
{
int ret;
if (pci_enable_device(dev->pdev))
return -EIO;
ret = vbox_drm_thaw(dev);
if (ret)
return ret;
drm_kms_helper_poll_enable(dev);
return 0;
}
static int vbox_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *ddev = pci_get_drvdata(pdev);
int error;
error = vbox_drm_freeze(ddev);
if (error)
return error;
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int vbox_pm_resume(struct device *dev)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
return vbox_drm_resume(ddev);
}
static int vbox_pm_freeze(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *ddev = pci_get_drvdata(pdev);
if (!ddev || !ddev->dev_private)
return -ENODEV;
return vbox_drm_freeze(ddev);
}
static int vbox_pm_thaw(struct device *dev)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
return vbox_drm_thaw(ddev);
}
static int vbox_pm_poweroff(struct device *dev)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
return vbox_drm_freeze(ddev);
}
static const struct dev_pm_ops vbox_pm_ops = {
.suspend = vbox_pm_suspend,
.resume = vbox_pm_resume,
.freeze = vbox_pm_freeze,
.thaw = vbox_pm_thaw,
.poweroff = vbox_pm_poweroff,
.restore = vbox_pm_resume,
};
static struct pci_driver vbox_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = vbox_pci_probe,
.remove = vbox_pci_remove,
.driver.pm = &vbox_pm_ops,
};
static const struct file_operations vbox_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
.unlocked_ioctl = drm_ioctl,
.mmap = vbox_mmap,
.poll = drm_poll,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
.read = drm_read,
};
static int vbox_master_set(struct drm_device *dev,
struct drm_file *file_priv, bool from_open)
{
struct vbox_private *vbox = dev->dev_private;
/*
* We do not yet know whether the new owner can handle hotplug, so we
* do not advertise dynamic modes on the first query and send a
* tentative hotplug notification after that to see if they query again.
*/
vbox->initial_mode_queried = false;
mutex_lock(&vbox->hw_mutex);
/*
* Disable VBVA when someone releases master in case the next person
* tries tries to do VESA.
*/
/** @todo work out if anyone is likely to and whether it will work. */
/*
* Update: we also disable it because if the new master does not do
* dirty rectangle reporting (e.g. old versions of Plymouth) then at
* least the first screen will still be updated. We enable it as soon
* as we receive a dirty rectangle report.
*/
vbox_disable_accel(vbox);
mutex_unlock(&vbox->hw_mutex);
return 0;
}
static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
{
struct vbox_private *vbox = dev->dev_private;
/* See vbox_master_set() */
vbox->initial_mode_queried = false;
mutex_lock(&vbox->hw_mutex);
vbox_disable_accel(vbox);
mutex_unlock(&vbox->hw_mutex);
}
static struct drm_driver driver = {
.driver_features =
DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
DRIVER_PRIME,
.dev_priv_size = 0,
.load = vbox_driver_load,
.unload = vbox_driver_unload,
.lastclose = vbox_driver_lastclose,
.master_set = vbox_master_set,
.master_drop = vbox_master_drop,
.set_busid = drm_pci_set_busid,
.fops = &vbox_fops,
.irq_handler = vbox_irq_handler,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
.gem_free_object = vbox_gem_free_object,
.dumb_create = vbox_dumb_create,
.dumb_map_offset = vbox_dumb_mmap_offset,
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_pin = vbox_gem_prime_pin,
.gem_prime_unpin = vbox_gem_prime_unpin,
.gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
.gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
.gem_prime_vmap = vbox_gem_prime_vmap,
.gem_prime_vunmap = vbox_gem_prime_vunmap,
.gem_prime_mmap = vbox_gem_prime_mmap,
};
static int __init vbox_init(void)
{
#ifdef CONFIG_VGA_CONSOLE
if (vgacon_text_force() && vbox_modeset == -1)
return -EINVAL;
#endif
if (vbox_modeset == 0)
return -EINVAL;
return drm_pci_init(&driver, &vbox_pci_driver);
}
static void __exit vbox_exit(void)
{
drm_pci_exit(&driver, &vbox_pci_driver);
}
module_init(vbox_init);
module_exit(vbox_exit);
MODULE_AUTHOR("Oracle Corporation");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL and additional rights");
/*
* Copyright (C) 2013-2017 Oracle Corporation
* This file is based on ast_drv.h
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* Authors: Dave Airlie <airlied@redhat.com>
* Michael Thayer <michael.thayer@oracle.com,
* Hans de Goede <hdegoede@redhat.com>
*/
#ifndef __VBOX_DRV_H__
#define __VBOX_DRV_H__
#include <linux/genalloc.h>
#include <linux/io.h>
#include <linux/string.h>
#include <linux/version.h>
#include <drm/drmP.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_memory.h>
#include <drm/ttm/ttm_module.h>
#include "vboxvideo_guest.h"
#include "vboxvideo_vbe.h"
#include "hgsmi_ch_setup.h"
#define DRIVER_NAME "vboxvideo"
#define DRIVER_DESC "Oracle VM VirtualBox Graphics Card"
#define DRIVER_DATE "20130823"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0
#define VBOX_MAX_CURSOR_WIDTH 64
#define VBOX_MAX_CURSOR_HEIGHT 64
#define CURSOR_PIXEL_COUNT (VBOX_MAX_CURSOR_WIDTH * VBOX_MAX_CURSOR_HEIGHT)
#define CURSOR_DATA_SIZE (CURSOR_PIXEL_COUNT * 4 + CURSOR_PIXEL_COUNT / 8)
#define VBOX_MAX_SCREENS 32
#define GUEST_HEAP_OFFSET(vbox) ((vbox)->full_vram_size - \
VBVA_ADAPTER_INFORMATION_SIZE)
#define GUEST_HEAP_SIZE VBVA_ADAPTER_INFORMATION_SIZE
#define GUEST_HEAP_USABLE_SIZE (VBVA_ADAPTER_INFORMATION_SIZE - \
sizeof(struct hgsmi_host_flags))
#define HOST_FLAGS_OFFSET GUEST_HEAP_USABLE_SIZE
struct vbox_fbdev;
struct vbox_private {
struct drm_device *dev;
u8 __iomem *guest_heap;
u8 __iomem *vbva_buffers;
struct gen_pool *guest_pool;
struct vbva_buf_ctx *vbva_info;
bool any_pitch;
u32 num_crtcs;
/** Amount of available VRAM, including space used for buffers. */
u32 full_vram_size;
/** Amount of available VRAM, not including space used for buffers. */
u32 available_vram_size;
/** Array of structures for receiving mode hints. */
struct vbva_modehint *last_mode_hints;
struct vbox_fbdev *fbdev;
int fb_mtrr;
struct {
struct drm_global_reference mem_global_ref;
struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
} ttm;
struct mutex hw_mutex; /* protects modeset and accel/vbva accesses */
/**
* We decide whether or not user-space supports display hot-plug
* depending on whether they react to a hot-plug event after the initial
* mode query.
*/
bool initial_mode_queried;
struct work_struct hotplug_work;
u32 input_mapping_width;
u32 input_mapping_height;
/**
* Is user-space using an X.Org-style layout of one large frame-buffer
* encompassing all screen ones or is the fbdev console active?
*/
bool single_framebuffer;
u32 cursor_width;
u32 cursor_height;
u32 cursor_hot_x;
u32 cursor_hot_y;
size_t cursor_data_size;
u8 cursor_data[CURSOR_DATA_SIZE];
};
#undef CURSOR_PIXEL_COUNT
#undef CURSOR_DATA_SIZE
int vbox_driver_load(struct drm_device *dev, unsigned long flags);
void vbox_driver_unload(struct drm_device *dev);
void vbox_driver_lastclose(struct drm_device *dev);
struct vbox_gem_object;
struct vbox_connector {
struct drm_connector base;
char name[32];
struct vbox_crtc *vbox_crtc;
struct {
u16 width;
u16 height;
bool disconnected;
} mode_hint;
};
struct vbox_crtc {
struct drm_crtc base;
bool blanked;
bool disconnected;
unsigned int crtc_id;
u32 fb_offset;
bool cursor_enabled;
u16 x_hint;
u16 y_hint;
};
struct vbox_encoder {
struct drm_encoder base;
};
struct vbox_framebuffer {
struct drm_framebuffer base;
struct drm_gem_object *obj;
};
struct vbox_fbdev {
struct drm_fb_helper helper;
struct vbox_framebuffer afb;
int size;
struct ttm_bo_kmap_obj mapping;
int x1, y1, x2, y2; /* dirty rect */
spinlock_t dirty_lock;
};
#define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base)
#define to_vbox_connector(x) container_of(x, struct vbox_connector, base)
#define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base)
#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base)
int vbox_mode_init(struct drm_device *dev);
void vbox_mode_fini(struct drm_device *dev);
#define DRM_MODE_FB_CMD drm_mode_fb_cmd2
#define CRTC_FB(crtc) ((crtc)->primary->fb)
void vbox_enable_accel(struct vbox_private *vbox);
void vbox_disable_accel(struct vbox_private *vbox);
void vbox_report_caps(struct vbox_private *vbox);
void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
struct drm_clip_rect *rects,
unsigned int num_rects);
int vbox_framebuffer_init(struct drm_device *dev,
struct vbox_framebuffer *vbox_fb,
const struct DRM_MODE_FB_CMD *mode_cmd,
struct drm_gem_object *obj);
int vbox_fbdev_init(struct drm_device *dev);
void vbox_fbdev_fini(struct drm_device *dev);
void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr);
struct vbox_bo {
struct ttm_buffer_object bo;
struct ttm_placement placement;
struct ttm_bo_kmap_obj kmap;
struct drm_gem_object gem;
struct ttm_place placements[3];
int pin_count;
};
#define gem_to_vbox_bo(gobj) container_of((gobj), struct vbox_bo, gem)
static inline struct vbox_bo *vbox_bo(struct ttm_buffer_object *bo)
{
return container_of(bo, struct vbox_bo, bo);
}
#define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base)
int vbox_dumb_create(struct drm_file *file,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
void vbox_gem_free_object(struct drm_gem_object *obj);
int vbox_dumb_mmap_offset(struct drm_file *file,
struct drm_device *dev,
u32 handle, u64 *offset);
#define DRM_FILE_PAGE_OFFSET (0x10000000ULL >> PAGE_SHIFT)
int vbox_mm_init(struct vbox_private *vbox);
void vbox_mm_fini(struct vbox_private *vbox);
int vbox_bo_create(struct drm_device *dev, int size, int align,
u32 flags, struct vbox_bo **pvboxbo);
int vbox_gem_create(struct drm_device *dev,
u32 size, bool iskernel, struct drm_gem_object **obj);
int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr);
int vbox_bo_unpin(struct vbox_bo *bo);
static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait)
{
int ret;
ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL);
if (ret) {
if (ret != -ERESTARTSYS && ret != -EBUSY)
DRM_ERROR("reserve failed %p\n", bo);
return ret;
}
return 0;
}
static inline void vbox_bo_unreserve(struct vbox_bo *bo)
{
ttm_bo_unreserve(&bo->bo);
}
void vbox_ttm_placement(struct vbox_bo *bo, int domain);
int vbox_bo_push_sysram(struct vbox_bo *bo);
int vbox_mmap(struct file *filp, struct vm_area_struct *vma);
/* vbox_prime.c */
int vbox_gem_prime_pin(struct drm_gem_object *obj);
void vbox_gem_prime_unpin(struct drm_gem_object *obj);
struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object *vbox_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *table);
void *vbox_gem_prime_vmap(struct drm_gem_object *obj);
void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
int vbox_gem_prime_mmap(struct drm_gem_object *obj,
struct vm_area_struct *area);
/* vbox_irq.c */
int vbox_irq_init(struct vbox_private *vbox);
void vbox_irq_fini(struct vbox_private *vbox);
void vbox_report_hotplug(struct vbox_private *vbox);
irqreturn_t vbox_irq_handler(int irq, void *arg);
/* vbox_hgsmi.c */
void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
u8 channel, u16 channel_info);
void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf);
int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf);
static inline void vbox_write_ioport(u16 index, u16 data)
{
outw(index, VBE_DISPI_IOPORT_INDEX);
outw(data, VBE_DISPI_IOPORT_DATA);
}
#endif
/*
* Copyright (C) 2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __VBOX_ERR_H__
#define __VBOX_ERR_H__
/**
* @name VirtualBox virtual-hardware error macros
* @{
*/
#define VINF_SUCCESS 0
#define VERR_INVALID_PARAMETER (-2)
#define VERR_INVALID_POINTER (-6)
#define VERR_NO_MEMORY (-8)
#define VERR_NOT_IMPLEMENTED (-12)
#define VERR_INVALID_FUNCTION (-36)
#define VERR_NOT_SUPPORTED (-37)
#define VERR_TOO_MUCH_DATA (-42)
#define VERR_INVALID_STATE (-79)
#define VERR_OUT_OF_RESOURCES (-80)
#define VERR_ALREADY_EXISTS (-105)
#define VERR_INTERNAL_ERROR (-225)
#define RT_SUCCESS_NP(rc) ((int)(rc) >= VINF_SUCCESS)
#define RT_SUCCESS(rc) (likely(RT_SUCCESS_NP(rc)))
#define RT_FAILURE(rc) (unlikely(!RT_SUCCESS_NP(rc)))
/** @} */
#endif
This diff is collapsed.
/*
* Copyright (C) 2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* Authors: Hans de Goede <hdegoede@redhat.com>
*/
#include "vbox_drv.h"
#include "vboxvideo_vbe.h"
#include "hgsmi_defs.h"
/* One-at-a-Time Hash from http://www.burtleburtle.net/bob/hash/doobs.html */
static u32 hgsmi_hash_process(u32 hash, const u8 *data, int size)
{
while (size--) {
hash += *data++;
hash += (hash << 10);
hash ^= (hash >> 6);
}
return hash;
}
static u32 hgsmi_hash_end(u32 hash)
{
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
/* Not really a checksum but that is the naming used in all vbox code */
static u32 hgsmi_checksum(u32 offset,
const struct hgsmi_buffer_header *header,
const struct hgsmi_buffer_tail *tail)
{
u32 checksum;
checksum = hgsmi_hash_process(0, (u8 *)&offset, sizeof(offset));
checksum = hgsmi_hash_process(checksum, (u8 *)header, sizeof(*header));
/* 4 -> Do not checksum the checksum itself */
checksum = hgsmi_hash_process(checksum, (u8 *)tail, 4);
return hgsmi_hash_end(checksum);
}
void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
u8 channel, u16 channel_info)
{
struct hgsmi_buffer_header *h;
struct hgsmi_buffer_tail *t;
size_t total_size;
dma_addr_t offset;
total_size = size + sizeof(*h) + sizeof(*t);
h = gen_pool_dma_alloc(guest_pool, total_size, &offset);
if (!h)
return NULL;
t = (struct hgsmi_buffer_tail *)((u8 *)h + sizeof(*h) + size);
h->flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
h->data_size = size;
h->channel = channel;
h->channel_info = channel_info;
memset(&h->u.header_data, 0, sizeof(h->u.header_data));
t->reserved = 0;
t->checksum = hgsmi_checksum(offset, h, t);
return (u8 *)h + sizeof(*h);
}
void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf)
{
struct hgsmi_buffer_header *h =
(struct hgsmi_buffer_header *)((u8 *)buf - sizeof(*h));
size_t total_size = h->data_size + sizeof(*h) +
sizeof(struct hgsmi_buffer_tail);
gen_pool_free(guest_pool, (unsigned long)h, total_size);
}
int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf)
{
phys_addr_t offset;
offset = gen_pool_virt_to_phys(guest_pool, (unsigned long)buf -
sizeof(struct hgsmi_buffer_header));
outl(offset, VGA_PORT_HGSMI_GUEST);
/* Make the compiler aware that the host has changed memory. */
mb();
return 0;
}
/*
* Copyright (C) 2016-2017 Oracle Corporation
* This file is based on qxl_irq.c
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Dave Airlie
* Alon Levy
* Michael Thayer <michael.thayer@oracle.com,
* Hans de Goede <hdegoede@redhat.com>
*/
#include <drm/drm_crtc_helper.h>
#include "vbox_drv.h"
#include "vboxvideo.h"
static void vbox_clear_irq(void)
{
outl((u32)~0, VGA_PORT_HGSMI_HOST);
}
static u32 vbox_get_flags(struct vbox_private *vbox)
{
return readl(vbox->guest_heap + HOST_FLAGS_OFFSET);
}
void vbox_report_hotplug(struct vbox_private *vbox)
{
schedule_work(&vbox->hotplug_work);
}
irqreturn_t vbox_irq_handler(int irq, void *arg)
{
struct drm_device *dev = (struct drm_device *)arg;
struct vbox_private *vbox = (struct vbox_private *)dev->dev_private;
u32 host_flags = vbox_get_flags(vbox);
if (!(host_flags & HGSMIHOSTFLAGS_IRQ))
return IRQ_NONE;
/*
* Due to a bug in the initial host implementation of hot-plug irqs,
* the hot-plug and cursor capability flags were never cleared.
* Fortunately we can tell when they would have been set by checking
* that the VSYNC flag is not set.
*/
if (host_flags &
(HGSMIHOSTFLAGS_HOTPLUG | HGSMIHOSTFLAGS_CURSOR_CAPABILITIES) &&
!(host_flags & HGSMIHOSTFLAGS_VSYNC))
vbox_report_hotplug(vbox);
vbox_clear_irq();
return IRQ_HANDLED;
}
/**
* Check that the position hints provided by the host are suitable for GNOME
* shell (i.e. all screens disjoint and hints for all enabled screens) and if
* not replace them with default ones. Providing valid hints improves the
* chances that we will get a known screen layout for pointer mapping.
*/
static void validate_or_set_position_hints(struct vbox_private *vbox)
{
struct vbva_modehint *hintsi, *hintsj;
bool valid = true;
u16 currentx = 0;
int i, j;
for (i = 0; i < vbox->num_crtcs; ++i) {
for (j = 0; j < i; ++j) {
hintsi = &vbox->last_mode_hints[i];
hintsj = &vbox->last_mode_hints[j];
if (hintsi->enabled && hintsj->enabled) {
if (hintsi->dx >= 0xffff ||
hintsi->dy >= 0xffff ||
hintsj->dx >= 0xffff ||
hintsj->dy >= 0xffff ||
(hintsi->dx <
hintsj->dx + (hintsj->cx & 0x8fff) &&
hintsi->dx + (hintsi->cx & 0x8fff) >
hintsj->dx) ||
(hintsi->dy <
hintsj->dy + (hintsj->cy & 0x8fff) &&
hintsi->dy + (hintsi->cy & 0x8fff) >
hintsj->dy))
valid = false;
}
}
}
if (!valid)
for (i = 0; i < vbox->num_crtcs; ++i) {
if (vbox->last_mode_hints[i].enabled) {
vbox->last_mode_hints[i].dx = currentx;
vbox->last_mode_hints[i].dy = 0;
currentx +=
vbox->last_mode_hints[i].cx & 0x8fff;
}
}
}
/**
* Query the host for the most recent video mode hints.
*/
static void vbox_update_mode_hints(struct vbox_private *vbox)
{
struct drm_device *dev = vbox->dev;
struct drm_connector *connector;
struct vbox_connector *vbox_conn;
struct vbva_modehint *hints;
u16 flags;
bool disconnected;
unsigned int crtc_id;
int ret;
ret = hgsmi_get_mode_hints(vbox->guest_pool, vbox->num_crtcs,
vbox->last_mode_hints);
if (ret) {
DRM_ERROR("vboxvideo: hgsmi_get_mode_hints failed: %d\n", ret);
return;
}
validate_or_set_position_hints(vbox);
drm_modeset_lock_all(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
vbox_conn = to_vbox_connector(connector);
hints = &vbox->last_mode_hints[vbox_conn->vbox_crtc->crtc_id];
if (hints->magic != VBVAMODEHINT_MAGIC)
continue;
disconnected = !(hints->enabled);
crtc_id = vbox_conn->vbox_crtc->crtc_id;
vbox_conn->mode_hint.width = hints->cx & 0x8fff;
vbox_conn->mode_hint.height = hints->cy & 0x8fff;
vbox_conn->vbox_crtc->x_hint = hints->dx;
vbox_conn->vbox_crtc->y_hint = hints->dy;
vbox_conn->mode_hint.disconnected = disconnected;
if (vbox_conn->vbox_crtc->disconnected == disconnected)
continue;
if (disconnected)
flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED;
else
flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_BLANK;
hgsmi_process_display_info(vbox->guest_pool, crtc_id, 0, 0, 0,
hints->cx * 4, hints->cx,
hints->cy, 0, flags);
vbox_conn->vbox_crtc->disconnected = disconnected;
}
drm_modeset_unlock_all(dev);
}
static void vbox_hotplug_worker(struct work_struct *work)
{
struct vbox_private *vbox = container_of(work, struct vbox_private,
hotplug_work);
vbox_update_mode_hints(vbox);
drm_kms_helper_hotplug_event(vbox->dev);
}
int vbox_irq_init(struct vbox_private *vbox)
{
INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
vbox_update_mode_hints(vbox);
return drm_irq_install(vbox->dev, vbox->dev->pdev->irq);
}
void vbox_irq_fini(struct vbox_private *vbox)
{
drm_irq_uninstall(vbox->dev);
flush_work(&vbox->hotplug_work);
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2017 Oracle Corporation
* Copyright 2017 Canonical
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Andreas Pokorny
*/
#include "vbox_drv.h"
/*
* Based on qxl_prime.c:
* Empty Implementations as there should not be any other driver for a virtual
* device that might share buffers with vboxvideo
*/
int vbox_gem_prime_pin(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
return -ENOSYS;
}
void vbox_gem_prime_unpin(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
}
struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
return ERR_PTR(-ENOSYS);
}
struct drm_gem_object *vbox_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *table)
{
WARN_ONCE(1, "not implemented");
return ERR_PTR(-ENOSYS);
}
void *vbox_gem_prime_vmap(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
return ERR_PTR(-ENOSYS);
}
void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{
WARN_ONCE(1, "not implemented");
}
int vbox_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *area)
{
WARN_ONCE(1, "not implemented");
return -ENOSYS;
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __VBOXVIDEO_GUEST_H__
#define __VBOXVIDEO_GUEST_H__
#include <linux/genalloc.h>
#include "vboxvideo.h"
/**
* Structure grouping the context needed for sending graphics acceleration
* information to the host via VBVA. Each screen has its own VBVA buffer.
*/
struct vbva_buf_ctx {
/** Offset of the buffer in the VRAM section for the screen */
u32 buffer_offset;
/** Length of the buffer in bytes */
u32 buffer_length;
/** Set if we wrote to the buffer faster than the host could read it */
bool buffer_overflow;
/** VBVA record that we are currently preparing for the host, or NULL */
struct vbva_record *record;
/**
* Pointer to the VBVA buffer mapped into the current address space.
* Will be NULL if VBVA is not enabled.
*/
struct vbva_buffer *vbva;
};
/**
* @name Base HGSMI APIs
* @{
*/
int hgsmi_report_flags_location(struct gen_pool *ctx, u32 location);
int hgsmi_send_caps_info(struct gen_pool *ctx, u32 caps);
int hgsmi_test_query_conf(struct gen_pool *ctx);
int hgsmi_query_conf(struct gen_pool *ctx, u32 index, u32 *value_ret);
int hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
u32 hot_x, u32 hot_y, u32 width, u32 height,
u8 *pixels, u32 len);
int hgsmi_cursor_position(struct gen_pool *ctx, bool report_position,
u32 x, u32 y, u32 *x_host, u32 *y_host);
/** @} */
/**
* @name VBVA APIs
* @{
*/
bool vbva_enable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
struct vbva_buffer *vbva, s32 screen);
void vbva_disable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
s32 screen);
bool vbva_buffer_begin_update(struct vbva_buf_ctx *vbva_ctx,
struct gen_pool *ctx);
void vbva_buffer_end_update(struct vbva_buf_ctx *vbva_ctx);
bool vbva_write(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
const void *p, u32 len);
void vbva_setup_buffer_context(struct vbva_buf_ctx *vbva_ctx,
u32 buffer_offset, u32 buffer_length);
/** @} */
/**
* @name Modesetting APIs
* @{
*/
void hgsmi_process_display_info(struct gen_pool *ctx, u32 display,
s32 origin_x, s32 origin_y, u32 start_offset,
u32 pitch, u32 width, u32 height,
u16 bpp, u16 flags);
int hgsmi_update_input_mapping(struct gen_pool *ctx, s32 origin_x, s32 origin_y,
u32 width, u32 height);
int hgsmi_get_mode_hints(struct gen_pool *ctx, unsigned int screens,
struct vbva_modehint *hints);
/** @} */
#endif
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __VBOXVIDEO_VBE_H__
#define __VBOXVIDEO_VBE_H__
/* GUEST <-> HOST Communication API */
/**
* @todo FIXME: Either dynamicly ask host for this or put somewhere high in
* physical memory like 0xE0000000.
*/
#define VBE_DISPI_BANK_ADDRESS 0xA0000
#define VBE_DISPI_BANK_SIZE_KB 64
#define VBE_DISPI_MAX_XRES 16384
#define VBE_DISPI_MAX_YRES 16384
#define VBE_DISPI_MAX_BPP 32
#define VBE_DISPI_IOPORT_INDEX 0x01CE
#define VBE_DISPI_IOPORT_DATA 0x01CF
#define VBE_DISPI_IOPORT_DAC_WRITE_INDEX 0x03C8
#define VBE_DISPI_IOPORT_DAC_DATA 0x03C9
#define VBE_DISPI_INDEX_ID 0x0
#define VBE_DISPI_INDEX_XRES 0x1
#define VBE_DISPI_INDEX_YRES 0x2
#define VBE_DISPI_INDEX_BPP 0x3
#define VBE_DISPI_INDEX_ENABLE 0x4
#define VBE_DISPI_INDEX_BANK 0x5
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
#define VBE_DISPI_INDEX_X_OFFSET 0x8
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
#define VBE_DISPI_INDEX_VBOX_VIDEO 0xa
#define VBE_DISPI_INDEX_FB_BASE_HI 0xb
#define VBE_DISPI_ID0 0xB0C0
#define VBE_DISPI_ID1 0xB0C1
#define VBE_DISPI_ID2 0xB0C2
#define VBE_DISPI_ID3 0xB0C3
#define VBE_DISPI_ID4 0xB0C4
#define VBE_DISPI_ID_VBOX_VIDEO 0xBE00
/* The VBOX interface id. Indicates support for VBVA shared memory interface. */
#define VBE_DISPI_ID_HGSMI 0xBE01
#define VBE_DISPI_ID_ANYX 0xBE02
#define VBE_DISPI_DISABLED 0x00
#define VBE_DISPI_ENABLED 0x01
#define VBE_DISPI_GETCAPS 0x02
#define VBE_DISPI_8BIT_DAC 0x20
/**
* @note this definition is a BOCHS legacy, used only in the video BIOS
* code and ignored by the emulated hardware.
*/
#define VBE_DISPI_LFB_ENABLED 0x40
#define VBE_DISPI_NOCLEARMEM 0x80
#define VGA_PORT_HGSMI_HOST 0x3b0
#define VGA_PORT_HGSMI_GUEST 0x3d0
#endif
/*
* Copyright (C) 2006-2017 Oracle Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "vbox_drv.h"
#include "vbox_err.h"
#include "vboxvideo_guest.h"
#include "hgsmi_channels.h"
/*
* There is a hardware ring buffer in the graphics device video RAM, formerly
* in the VBox VMMDev PCI memory space.
* All graphics commands go there serialized by vbva_buffer_begin_update.
* and vbva_buffer_end_update.
*
* free_offset is writing position. data_offset is reading position.
* free_offset == data_offset means buffer is empty.
* There must be always gap between data_offset and free_offset when data
* are in the buffer.
* Guest only changes free_offset, host changes data_offset.
*/
static u32 vbva_buffer_available(const struct vbva_buffer *vbva)
{
s32 diff = vbva->data_offset - vbva->free_offset;
return diff > 0 ? diff : vbva->data_len + diff;
}
static void vbva_buffer_place_data_at(struct vbva_buf_ctx *vbva_ctx,
const void *p, u32 len, u32 offset)
{
struct vbva_buffer *vbva = vbva_ctx->vbva;
u32 bytes_till_boundary = vbva->data_len - offset;
u8 *dst = &vbva->data[offset];
s32 diff = len - bytes_till_boundary;
if (diff <= 0) {
/* Chunk will not cross buffer boundary. */
memcpy(dst, p, len);
} else {
/* Chunk crosses buffer boundary. */
memcpy(dst, p, bytes_till_boundary);
memcpy(&vbva->data[0], (u8 *)p + bytes_till_boundary, diff);
}
}
static void vbva_buffer_flush(struct gen_pool *ctx)
{
struct vbva_flush *p;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_FLUSH);
if (!p)
return;
p->reserved = 0;
hgsmi_buffer_submit(ctx, p);
hgsmi_buffer_free(ctx, p);
}
bool vbva_write(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
const void *p, u32 len)
{
struct vbva_record *record;
struct vbva_buffer *vbva;
u32 available;
vbva = vbva_ctx->vbva;
record = vbva_ctx->record;
if (!vbva || vbva_ctx->buffer_overflow ||
!record || !(record->len_and_flags & VBVA_F_RECORD_PARTIAL))
return false;
available = vbva_buffer_available(vbva);
while (len > 0) {
u32 chunk = len;
if (chunk >= available) {
vbva_buffer_flush(ctx);
available = vbva_buffer_available(vbva);
}
if (chunk >= available) {
if (WARN_ON(available <= vbva->partial_write_tresh)) {
vbva_ctx->buffer_overflow = true;
return false;
}
chunk = available - vbva->partial_write_tresh;
}
vbva_buffer_place_data_at(vbva_ctx, p, chunk,
vbva->free_offset);
vbva->free_offset = (vbva->free_offset + chunk) %
vbva->data_len;
record->len_and_flags += chunk;
available -= chunk;
len -= chunk;
p += chunk;
}
return true;
}
static bool vbva_inform_host(struct vbva_buf_ctx *vbva_ctx,
struct gen_pool *ctx, s32 screen, bool enable)
{
struct vbva_enable_ex *p;
bool ret;
p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_ENABLE);
if (!p)
return false;
p->base.flags = enable ? VBVA_F_ENABLE : VBVA_F_DISABLE;
p->base.offset = vbva_ctx->buffer_offset;
p->base.result = VERR_NOT_SUPPORTED;
if (screen >= 0) {
p->base.flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
p->screen_id = screen;
}
hgsmi_buffer_submit(ctx, p);
if (enable)
ret = RT_SUCCESS(p->base.result);
else
ret = true;
hgsmi_buffer_free(ctx, p);
return ret;
}
bool vbva_enable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
struct vbva_buffer *vbva, s32 screen)
{
bool ret = false;
memset(vbva, 0, sizeof(*vbva));
vbva->partial_write_tresh = 256;
vbva->data_len = vbva_ctx->buffer_length - sizeof(struct vbva_buffer);
vbva_ctx->vbva = vbva;
ret = vbva_inform_host(vbva_ctx, ctx, screen, true);
if (!ret)
vbva_disable(vbva_ctx, ctx, screen);
return ret;
}
void vbva_disable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
s32 screen)
{
vbva_ctx->buffer_overflow = false;
vbva_ctx->record = NULL;
vbva_ctx->vbva = NULL;
vbva_inform_host(vbva_ctx, ctx, screen, false);
}
bool vbva_buffer_begin_update(struct vbva_buf_ctx *vbva_ctx,
struct gen_pool *ctx)
{
struct vbva_record *record;
u32 next;
if (!vbva_ctx->vbva ||
!(vbva_ctx->vbva->host_flags.host_events & VBVA_F_MODE_ENABLED))
return false;
WARN_ON(vbva_ctx->buffer_overflow || vbva_ctx->record);
next = (vbva_ctx->vbva->record_free_index + 1) % VBVA_MAX_RECORDS;
/* Flush if all slots in the records queue are used */
if (next == vbva_ctx->vbva->record_first_index)
vbva_buffer_flush(ctx);
/* If even after flush there is no place then fail the request */
if (next == vbva_ctx->vbva->record_first_index)
return false;
record = &vbva_ctx->vbva->records[vbva_ctx->vbva->record_free_index];
record->len_and_flags = VBVA_F_RECORD_PARTIAL;
vbva_ctx->vbva->record_free_index = next;
/* Remember which record we are using. */
vbva_ctx->record = record;
return true;
}
void vbva_buffer_end_update(struct vbva_buf_ctx *vbva_ctx)
{
struct vbva_record *record = vbva_ctx->record;
WARN_ON(!vbva_ctx->vbva || !record ||
!(record->len_and_flags & VBVA_F_RECORD_PARTIAL));
/* Mark the record completed. */
record->len_and_flags &= ~VBVA_F_RECORD_PARTIAL;
vbva_ctx->buffer_overflow = false;
vbva_ctx->record = NULL;
}
void vbva_setup_buffer_context(struct vbva_buf_ctx *vbva_ctx,
u32 buffer_offset, u32 buffer_length)
{
vbva_ctx->buffer_offset = buffer_offset;
vbva_ctx->buffer_length = buffer_length;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment