linux_dsm_epyc7002/drivers/gpu/drm/vboxvideo/vbox_irq.c

184 lines
4.9 KiB
C
Raw Normal View History

// SPDX-License-Identifier: MIT
/*
* Copyright (C) 2016-2017 Oracle Corporation
* This file is based on qxl_irq.c
* Copyright 2013 Red Hat Inc.
* Authors: Dave Airlie
* Alon Levy
* Michael Thayer <michael.thayer@oracle.com,
* Hans de Goede <hdegoede@redhat.com>
*/
drm: Split out drm_probe_helper.h Having the probe helper stuff (which pretty much everyone needs) in the drm_crtc_helper.h file (which atomic drivers should never need) is confusing. Split them out. To make sure I actually achieved the goal here I went through all drivers. And indeed, all atomic drivers are now free of drm_crtc_helper.h includes. v2: Make it compile. There was so much compile fail on arm drivers that I figured I'll better not include any of the acks on v1. v3: Massive rebase because i915 has lost a lot of drmP.h includes, but not all: Through drm_crtc_helper.h > drm_modeset_helper.h -> drmP.h there was still one, which this patch largely removes. Which means rolling out lots more includes all over. This will also conflict with ongoing drmP.h cleanup by others I expect. v3: Rebase on top of atomic bochs. v4: Review from Laurent for bridge/rcar/omap/shmob/core bits: - (re)move some of the added includes, use the better include files in other places (all suggested from Laurent adopted unchanged). - sort alphabetically v5: Actually try to sort them, and while at it, sort all the ones I touch. v6: Rebase onto i915 changes. v7: Rebase once more. Acked-by: Harry Wentland <harry.wentland@amd.com> Acked-by: Sam Ravnborg <sam@ravnborg.org> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Acked-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Acked-by: Jani Nikula <jani.nikula@intel.com> Acked-by: Neil Armstrong <narmstrong@baylibre.com> Acked-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Acked-by: CK Hu <ck.hu@mediatek.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Sam Ravnborg <sam@ravnborg.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Cc: linux-arm-kernel@lists.infradead.org Cc: virtualization@lists.linux-foundation.org Cc: etnaviv@lists.freedesktop.org Cc: linux-samsung-soc@vger.kernel.org Cc: intel-gfx@lists.freedesktop.org Cc: linux-mediatek@lists.infradead.org Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Cc: nouveau@lists.freedesktop.org Cc: spice-devel@lists.freedesktop.org Cc: amd-gfx@lists.freedesktop.org Cc: linux-renesas-soc@vger.kernel.org Cc: linux-rockchip@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com Cc: linux-tegra@vger.kernel.org Cc: xen-devel@lists.xen.org Link: https://patchwork.freedesktop.org/patch/msgid/20190117210334.13234-1-daniel.vetter@ffwll.ch
2019-01-18 04:03:34 +07:00
#include <linux/pci.h>
#include <drm/drm_irq.h>
#include <drm/drm_probe_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_connector_list_iter conn_iter;
struct drm_device *dev = &vbox->ddev;
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(&dev->mode_config.connection_mutex, NULL);
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
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;
vbox_conn->mode_hint.height = hints->cy;
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_connector_list_iter_end(&conn_iter);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
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->ddev);
}
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->ddev, vbox->ddev.pdev->irq);
}
void vbox_irq_fini(struct vbox_private *vbox)
{
drm_irq_uninstall(&vbox->ddev);
flush_work(&vbox->hotplug_work);
}