aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/vmwgfx
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2022-04-12 17:39:45 +1000
committerDave Airlie <airlied@redhat.com>2022-04-12 17:44:27 +1000
commitb85ffe47c4ec172214a38b7e7087c60582c488f0 (patch)
tree128168c955a62a870f7da7cfda94e9299a076486 /drivers/gpu/drm/vmwgfx
parentce522ba9ef7e2d9fb22a39eb3371c0c64e2a433e (diff)
parentc8d4c18bfbc4ab467188dbe45cc8155759f49d9e (diff)
Merge tag 'drm-misc-next-2022-04-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.19: UAPI Changes: Cross-subsystem Changes: Core Changes: - atomic: Add atomic_print_state to private objects - edid: Constify the EDID parsing API, rework of the API - dma-buf: Add dma_resv_replace_fences, dma_resv_get_singleton, make dma_resv_excl_fence private - format: Support monochrome formats - fbdev: fixes for cfb_imageblit and sys_imageblit, pagelist corruption fix - selftests: several small fixes - ttm: Rework bulk move handling Driver Changes: - Switch all relevant drivers to drm_mode_copy or drm_mode_duplicate - bridge: conversions to devm_drm_of_get_bridge and panel_bridge, autosuspend for analogix_dp, audio support for it66121, DSI to DPI support for tc358767, PLL fixes and I2C support for icn6211 - bridge_connector: Enable HPD if supported - etnaviv: fencing improvements - gma500: GEM and GTT improvements, connector handling fixes - komeda: switch to plane reset helper - mediatek: MIPI DSI improvements - omapdrm: GEM improvements - panel: DT bindings fixes for st7735r, few fixes for ssd130x, new panels: ltk035c5444t, B133UAN01, NV3052C - qxl: Allow to run on arm64 - sysfb: Kconfig rework, support for VESA graphic mode selection - vc4: Add a tracepoint for CL submissions, HDMI YUV output, HDMI and clock improvements - virtio: Remove restriction of non-zero blob_flags, - vmwgfx: support for CursorMob and CursorBypass 4, various improvements and small fixes [airlied: fixup conflict with newvision panel callbacks] Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <maxime@cerno.tech> Link: https://patchwork.freedesktop.org/patch/msgid/20220407085940.pnflvjojs4qw4b77@houat
Diffstat (limited to 'drivers/gpu/drm/vmwgfx')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.c16
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c20
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h23
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c28
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c27
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_irq.c81
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c445
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h29
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c36
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c19
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c17
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c27
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c2
15 files changed, 583 insertions, 202 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 31aecc46624b..fe13aa8b4a64 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -747,16 +747,22 @@ void vmw_bo_fence_single(struct ttm_buffer_object *bo,
struct vmw_fence_obj *fence)
{
struct ttm_device *bdev = bo->bdev;
-
struct vmw_private *dev_priv =
container_of(bdev, struct vmw_private, bdev);
+ int ret;
- if (fence == NULL) {
+ if (fence == NULL)
vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
+ else
+ dma_fence_get(&fence->base);
+
+ ret = dma_resv_reserve_fences(bo->base.resv, 1);
+ if (!ret)
dma_resv_add_excl_fence(bo->base.resv, &fence->base);
- dma_fence_put(&fence->base);
- } else
- dma_resv_add_excl_fence(bo->base.resv, &fence->base);
+ else
+ /* Last resort fallback when we are OOM */
+ dma_fence_wait(&fence->base, false);
+ dma_fence_put(&fence->base);
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
index a3bfbb6c3e14..162dfeb1cc5a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
@@ -528,7 +528,7 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno)
*seqno = atomic_add_return(1, &dev_priv->marker_seq);
} while (*seqno == 0);
- if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE)) {
+ if (!vmw_has_fences(dev_priv)) {
/*
* Don't request hardware to send a fence. The
@@ -675,11 +675,14 @@ int vmw_cmd_emit_dummy_query(struct vmw_private *dev_priv,
*/
bool vmw_cmd_supported(struct vmw_private *vmw)
{
- if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
- SVGA_CAP_CMD_BUFFERS_2)) != 0)
- return true;
+ bool has_cmdbufs =
+ (vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
+ SVGA_CAP_CMD_BUFFERS_2)) != 0;
+ if (vmw_is_svga_v3(vmw))
+ return (has_cmdbufs &&
+ (vmw->capabilities & SVGA_CAP_GBOBJECTS) != 0);
/*
* We have FIFO cmd's
*/
- return vmw->fifo_mem != NULL;
+ return has_cmdbufs || vmw->fifo_mem != NULL;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 26eb5478394a..791f9a5f3868 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2016 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -848,12 +848,16 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
-
+ vmw_print_bitmap(&dev_priv->drm, "Capabilities",
+ dev_priv->capabilities,
+ cap1_names, ARRAY_SIZE(cap1_names));
if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) {
dev_priv->capabilities2 = vmw_read(dev_priv, SVGA_REG_CAP2);
+ vmw_print_bitmap(&dev_priv->drm, "Capabilities2",
+ dev_priv->capabilities2,
+ cap2_names, ARRAY_SIZE(cap2_names));
}
-
ret = vmw_dma_select_mode(dev_priv);
if (unlikely(ret != 0)) {
drm_info(&dev_priv->drm,
@@ -939,14 +943,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
"MOB limits: max mob size = %u kB, max mob pages = %u\n",
dev_priv->max_mob_size / 1024, dev_priv->max_mob_pages);
- vmw_print_bitmap(&dev_priv->drm, "Capabilities",
- dev_priv->capabilities,
- cap1_names, ARRAY_SIZE(cap1_names));
- if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER)
- vmw_print_bitmap(&dev_priv->drm, "Capabilities2",
- dev_priv->capabilities2,
- cap2_names, ARRAY_SIZE(cap2_names));
-
ret = vmw_dma_masks(dev_priv);
if (unlikely(ret != 0))
goto out_err0;
@@ -984,7 +980,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
}
if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
- ret = vmw_irq_install(&dev_priv->drm, pdev->irq);
+ ret = vmw_irq_install(dev_priv);
if (ret != 0) {
drm_err(&dev_priv->drm,
"Failed installing irq: %d\n", ret);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index ea3ecdda561d..be19aa6e1f13 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
- * Copyright 2009-2021 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -66,6 +66,11 @@
#define VMWGFX_PCI_ID_SVGA3 0x0406
/*
+ * This has to match get_count_order(SVGA_IRQFLAG_MAX)
+ */
+#define VMWGFX_MAX_NUM_IRQS 6
+
+/*
* Perhaps we should have sysfs entries for these.
*/
#define VMWGFX_NUM_GB_CONTEXT 256
@@ -101,6 +106,7 @@ struct vmw_fpriv {
* struct vmw_buffer_object - TTM buffer object with vmwgfx additions
* @base: The TTM buffer object
* @res_tree: RB tree of resources using this buffer object as a backing MOB
+ * @base_mapped_count: ttm BO mapping count; used by KMS atomic helpers.
* @cpu_writers: Number of synccpu write grabs. Protected by reservation when
* increased. May be decreased without reservation.
* @dx_query_ctx: DX context if this buffer object is used as a DX query MOB
@@ -111,6 +117,9 @@ struct vmw_fpriv {
struct vmw_buffer_object {
struct ttm_buffer_object base;
struct rb_root res_tree;
+ /* For KMS atomic helpers: ttm bo mapping count */
+ atomic_t base_mapped_count;
+
atomic_t cpu_writers;
/* Not ref-counted. Protected by binding_mutex */
struct vmw_resource *dx_query_ctx;
@@ -528,6 +537,8 @@ struct vmw_private {
bool has_mob;
spinlock_t hw_lock;
bool assume_16bpp;
+ u32 irqs[VMWGFX_MAX_NUM_IRQS];
+ u32 num_irq_vectors;
enum vmw_sm_type sm_type;
@@ -1154,7 +1165,7 @@ bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
* IRQs and wating - vmwgfx_irq.c
*/
-extern int vmw_irq_install(struct drm_device *dev, int irq);
+extern int vmw_irq_install(struct vmw_private *dev_priv);
extern void vmw_irq_uninstall(struct drm_device *dev);
extern bool vmw_seqno_passed(struct vmw_private *dev_priv,
uint32_t seqno);
@@ -1679,4 +1690,12 @@ static inline void vmw_irq_status_write(struct vmw_private *vmw,
outl(status, vmw->io_start + SVGA_IRQSTATUS_PORT);
}
+static inline bool vmw_has_fences(struct vmw_private *vmw)
+{
+ if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
+ SVGA_CAP_CMD_BUFFERS_2)) != 0)
+ return true;
+ return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0;
+}
+
#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 8ee34576c7d0..adf17c740656 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -483,7 +483,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
static int vmw_fb_kms_framebuffer(struct fb_info *info)
{
- struct drm_mode_fb_cmd2 mode_cmd;
+ struct drm_mode_fb_cmd2 mode_cmd = {0};
struct vmw_fb_par *par = info->par;
struct fb_var_screeninfo *var = &info->var;
struct drm_framebuffer *cur_fb;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 59d6a2dd4c2e..66cc35dc223e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -82,6 +82,22 @@ fman_from_fence(struct vmw_fence_obj *fence)
return container_of(fence->base.lock, struct vmw_fence_manager, lock);
}
+static u32 vmw_fence_goal_read(struct vmw_private *vmw)
+{
+ if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
+ return vmw_read(vmw, SVGA_REG_FENCE_GOAL);
+ else
+ return vmw_fifo_mem_read(vmw, SVGA_FIFO_FENCE_GOAL);
+}
+
+static void vmw_fence_goal_write(struct vmw_private *vmw, u32 value)
+{
+ if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
+ vmw_write(vmw, SVGA_REG_FENCE_GOAL, value);
+ else
+ vmw_fifo_mem_write(vmw, SVGA_FIFO_FENCE_GOAL, value);
+}
+
/*
* Note on fencing subsystem usage of irqs:
* Typically the vmw_fences_update function is called
@@ -392,7 +408,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
if (likely(!fman->seqno_valid))
return false;
- goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
+ goal_seqno = vmw_fence_goal_read(fman->dev_priv);
if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
return false;
@@ -400,9 +416,8 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
list_for_each_entry(fence, &fman->fence_list, head) {
if (!list_empty(&fence->seq_passed_actions)) {
fman->seqno_valid = true;
- vmw_fifo_mem_write(fman->dev_priv,
- SVGA_FIFO_FENCE_GOAL,
- fence->base.seqno);
+ vmw_fence_goal_write(fman->dev_priv,
+ fence->base.seqno);
break;
}
}
@@ -434,13 +449,12 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
if (dma_fence_is_signaled_locked(&fence->base))
return false;
- goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
+ goal_seqno = vmw_fence_goal_read(fman->dev_priv);
if (likely(fman->seqno_valid &&
goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
return false;
- vmw_fifo_mem_write(fman->dev_priv, SVGA_FIFO_FENCE_GOAL,
- fence->base.seqno);
+ vmw_fence_goal_write(fman->dev_priv, fence->base.seqno);
fman->seqno_valid = true;
return true;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 471da2b4c177..a1da5678c731 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -27,9 +27,11 @@
#include "vmwgfx_drv.h"
#include "vmwgfx_devcaps.h"
-#include <drm/vmwgfx_drm.h>
#include "vmwgfx_kms.h"
+#include <drm/vmwgfx_drm.h>
+#include <linux/pci.h>
+
int vmw_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -62,17 +64,15 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
break;
case DRM_VMW_PARAM_FIFO_HW_VERSION:
{
- if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) {
+ if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS))
param->value = SVGA3D_HWVERSION_WS8_B1;
- break;
- }
-
- param->value =
- vmw_fifo_mem_read(dev_priv,
- ((vmw_fifo_caps(dev_priv) &
- SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
- SVGA_FIFO_3D_HWVERSION_REVISED :
- SVGA_FIFO_3D_HWVERSION));
+ else
+ param->value = vmw_fifo_mem_read(
+ dev_priv,
+ ((vmw_fifo_caps(dev_priv) &
+ SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
+ SVGA_FIFO_3D_HWVERSION_REVISED :
+ SVGA_FIFO_3D_HWVERSION));
break;
}
case DRM_VMW_PARAM_MAX_SURF_MEMORY:
@@ -108,6 +108,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
case DRM_VMW_PARAM_GL43:
param->value = has_gl43_context(dev_priv);
break;
+ case DRM_VMW_PARAM_DEVICE_ID:
+ param->value = to_pci_dev(dev_priv->drm.dev)->device;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index c5191de365ca..086e69a130d4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -32,6 +32,14 @@
#define VMW_FENCE_WRAP (1 << 24)
+static u32 vmw_irqflag_fence_goal(struct vmw_private *vmw)
+{
+ if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
+ return SVGA_IRQFLAG_REG_FENCE_GOAL;
+ else
+ return SVGA_IRQFLAG_FENCE_GOAL;
+}
+
/**
* vmw_thread_fn - Deferred (process context) irq handler
*
@@ -96,7 +104,7 @@ static irqreturn_t vmw_irq_handler(int irq, void *arg)
wake_up_all(&dev_priv->fifo_queue);
if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE |
- SVGA_IRQFLAG_FENCE_GOAL)) &&
+ vmw_irqflag_fence_goal(dev_priv))) &&
!test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending))
ret = IRQ_WAKE_THREAD;
@@ -137,8 +145,7 @@ bool vmw_seqno_passed(struct vmw_private *dev_priv,
if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
return true;
- if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE) &&
- vmw_fifo_idle(dev_priv, seqno))
+ if (!vmw_has_fences(dev_priv) && vmw_fifo_idle(dev_priv, seqno))
return true;
/**
@@ -160,6 +167,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
unsigned long timeout)
{
struct vmw_fifo_state *fifo_state = dev_priv->fifo;
+ bool fifo_down = false;
uint32_t count = 0;
uint32_t signal_seq;
@@ -176,12 +184,14 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
*/
if (fifo_idle) {
- down_read(&fifo_state->rwsem);
if (dev_priv->cman) {
ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible,
10*HZ);
if (ret)
goto out_err;
+ } else if (fifo_state) {
+ down_read(&fifo_state->rwsem);
+ fifo_down = true;
}
}
@@ -218,12 +228,12 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
}
}
finish_wait(&dev_priv->fence_queue, &__wait);
- if (ret == 0 && fifo_idle)
+ if (ret == 0 && fifo_idle && fifo_state)
vmw_fence_write(dev_priv, signal_seq);
wake_up_all(&dev_priv->fence_queue);
out_err:
- if (fifo_idle)
+ if (fifo_down)
up_read(&fifo_state->rwsem);
return ret;
@@ -266,13 +276,13 @@ void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
void vmw_goal_waiter_add(struct vmw_private *dev_priv)
{
- vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
+ vmw_generic_waiter_add(dev_priv, vmw_irqflag_fence_goal(dev_priv),
&dev_priv->goal_queue_waiters);
}
void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
{
- vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
+ vmw_generic_waiter_remove(dev_priv, vmw_irqflag_fence_goal(dev_priv),
&dev_priv->goal_queue_waiters);
}
@@ -290,6 +300,7 @@ void vmw_irq_uninstall(struct drm_device *dev)
struct vmw_private *dev_priv = vmw_priv(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
uint32_t status;
+ u32 i;
if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
return;
@@ -299,20 +310,62 @@ void vmw_irq_uninstall(struct drm_device *dev)
status = vmw_irq_status_read(dev_priv);
vmw_irq_status_write(dev_priv, status);
- free_irq(pdev->irq, dev);
+ for (i = 0; i < dev_priv->num_irq_vectors; ++i)
+ free_irq(dev_priv->irqs[i], dev);
+
+ pci_free_irq_vectors(pdev);
+ dev_priv->num_irq_vectors = 0;
}
/**
* vmw_irq_install - Install the irq handlers
*
- * @dev: Pointer to the drm device.
- * @irq: The irq number.
+ * @dev_priv: Pointer to the vmw_private device.
* Return: Zero if successful. Negative number otherwise.
*/
-int vmw_irq_install(struct drm_device *dev, int irq)
+int vmw_irq_install(struct vmw_private *dev_priv)
{
+ struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
+ struct drm_device *dev = &dev_priv->drm;
+ int ret;
+ int nvec;
+ int i = 0;
+
+ BUILD_BUG_ON((SVGA_IRQFLAG_MAX >> VMWGFX_MAX_NUM_IRQS) != 1);
+ BUG_ON(VMWGFX_MAX_NUM_IRQS != get_count_order(SVGA_IRQFLAG_MAX));
+
+ nvec = pci_alloc_irq_vectors(pdev, 1, VMWGFX_MAX_NUM_IRQS,
+ PCI_IRQ_ALL_TYPES);
+
+ if (nvec <= 0) {
+ drm_err(&dev_priv->drm,
+ "IRQ's are unavailable, nvec: %d\n", nvec);
+ ret = nvec;
+ goto done;
+ }
+
vmw_irq_preinstall(dev);
- return request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn,
- IRQF_SHARED, VMWGFX_DRIVER_NAME, dev);
+ for (i = 0; i < nvec; ++i) {
+ ret = pci_irq_vector(pdev, i);
+ if (ret < 0) {
+ drm_err(&dev_priv->drm,
+ "failed getting irq vector: %d\n", ret);
+ goto done;
+ }
+ dev_priv->irqs[i] = ret;
+
+ ret = request_threaded_irq(dev_priv->irqs[i], vmw_irq_handler, vmw_thread_fn,
+ IRQF_SHARED, VMWGFX_DRIVER_NAME, dev);
+ if (ret != 0) {
+ drm_err(&dev_priv->drm,
+ "Failed installing irq(%d): %d\n",
+ dev_priv->irqs[i], ret);
+ goto done;
+ }
+ }
+
+done:
+ dev_priv->num_irq_vectors = i;
+ return ret;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index bbd2f4ec08ec..693028c31b6b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -41,7 +41,7 @@ void vmw_du_cleanup(struct vmw_display_unit *du)
struct vmw_private *dev_priv = vmw_priv(du->primary.dev);
drm_plane_cleanup(&du->primary);
if (vmw_cmd_supported(dev_priv))
- drm_plane_cleanup(&du->cursor);
+ drm_plane_cleanup(&du->cursor.base);
drm_connector_unregister(&du->connector);
drm_crtc_cleanup(&du->crtc);
@@ -53,23 +53,43 @@ void vmw_du_cleanup(struct vmw_display_unit *du)
* Display Unit Cursor functions
*/
-static int vmw_cursor_update_image(struct vmw_private *dev_priv,
- u32 *image, u32 width, u32 height,
- u32 hotspotX, u32 hotspotY)
+static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *bo,
+ struct ttm_bo_kmap_obj *map,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY);
+
+struct vmw_svga_fifo_cmd_define_cursor {
+ u32 cmd;
+ SVGAFifoCmdDefineAlphaCursor cursor;
+};
+
+static void vmw_cursor_update_image(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *cm_bo,
+ struct ttm_bo_kmap_obj *cm_map,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
{
- struct {
- u32 cmd;
- SVGAFifoCmdDefineAlphaCursor cursor;
- } *cmd;
- u32 image_size = width * height * 4;
- u32 cmd_size = sizeof(*cmd) + image_size;
+ struct vmw_svga_fifo_cmd_define_cursor *cmd;
+ const u32 image_size = width * height * sizeof(*image);
+ const u32 cmd_size = sizeof(*cmd) + image_size;
- if (!image)
- return -EINVAL;
+ if (cm_bo != NULL) {
+ vmw_cursor_update_mob(dev_priv, cm_bo, cm_map, image,
+ width, height,
+ hotspotX, hotspotY);
+ return;
+ }
+ /* Try to reserve fifocmd space and swallow any failures;
+ such reservations cannot be left unconsumed for long
+ under the risk of clogging other fifocmd users, so
+ we treat reservations separtely from the way we treat
+ other fallible KMS-atomic resources at prepare_fb */
cmd = VMW_CMD_RESERVE(dev_priv, cmd_size);
+
if (unlikely(cmd == NULL))
- return -ENOMEM;
+ return;
memset(cmd, 0, sizeof(*cmd));
@@ -83,55 +103,158 @@ static int vmw_cursor_update_image(struct vmw_private *dev_priv,
cmd->cursor.hotspotY = hotspotY;
vmw_cmd_commit_flush(dev_priv, cmd_size);
-
- return 0;
}
-static int vmw_cursor_update_bo(struct vmw_private *dev_priv,
- struct vmw_buffer_object *bo,
- u32 width, u32 height,
- u32 hotspotX, u32 hotspotY)
-{
- struct ttm_bo_kmap_obj map;
- unsigned long kmap_offset;
- unsigned long kmap_num;
- void *virtual;
+/**
+ * vmw_cursor_update_mob - Update cursor vis CursorMob mechanism
+ *
+ * @dev_priv: device to work with
+ * @bo: BO for the MOB
+ * @map: kmap obj for the BO
+ * @image: cursor source data to fill the MOB with
+ * @width: source data width
+ * @height: source data height
+ * @hotspotX: cursor hotspot x
+ * @hotspotY: cursor hotspot Y
+ */
+static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *bo,
+ struct ttm_bo_kmap_obj *map,
+ u32 *image, u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
+{
+ SVGAGBCursorHeader *header;
+ SVGAGBAlphaCursorHeader *alpha_header;
+ const u32 image_size = width * height * sizeof(*image);
bool dummy;
- int ret;
- kmap_offset = 0;
- kmap_num = PFN_UP(width*height*4);
+ BUG_ON(!image);
- ret = ttm_bo_reserve(&bo->base, true, false, NULL);
- if (unlikely(ret != 0)) {
- DRM_ERROR("reserve failed\n");
- return -EINVAL;
+ header = (SVGAGBCursorHeader *)ttm_kmap_obj_virtual(map, &dummy);
+ alpha_header = &header->header.alphaHeader;
+
+ header->type = SVGA_ALPHA_CURSOR;
+ header->sizeInBytes = image_size;
+
+ alpha_header->hotspotX = hotspotX;
+ alpha_header->hotspotY = hotspotY;
+ alpha_header->width = width;
+ alpha_header->height = height;
+
+ memcpy(header + 1, image, image_size);
+
+ vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start);
+}
+
+void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mob); i++) {
+ if (vcp->cursor_mob[i] != NULL) {
+ ttm_bo_unpin(vcp->cursor_mob[i]);
+ ttm_bo_put(vcp->cursor_mob[i]);
+ kfree(vcp->cursor_mob[i]);
+ vcp->cursor_mob[i] = NULL;
+ }
}
+}
- ret = ttm_bo_kmap(&bo->base, kmap_offset, kmap_num, &map);
- if (unlikely(ret != 0))
- goto err_unreserve;
+#define CURSOR_MOB_SIZE(dimension) \
+ ((dimension) * (dimension) * sizeof(u32) + sizeof(SVGAGBCursorHeader))
- virtual = ttm_kmap_obj_virtual(&map, &dummy);
- ret = vmw_cursor_update_image(dev_priv, virtual, width, height,
- hotspotX, hotspotY);
+int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *cursor)
+{
+ struct vmw_private *dev_priv = cursor->base.dev->dev_private;
+ uint32_t cursor_max_dim, mob_max_size;
+ int ret = 0;
+ size_t i;
- ttm_bo_kunmap(&map);
-err_unreserve:
- ttm_bo_unreserve(&bo->base);
+ if (!dev_priv->has_mob || (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0)
+ return -ENOSYS;
+
+ mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
+ cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION);
+
+ if (CURSOR_MOB_SIZE(cursor_max_dim) > mob_max_size)
+ cursor_max_dim = 64; /* Mandatorily-supported cursor dimension */
+
+ for (i = 0; i < ARRAY_SIZE(cursor->cursor_mob); i++) {
+ struct ttm_buffer_object **const bo = &cursor->cursor_mob[i];
+
+ ret = vmw_bo_create_kernel(dev_priv,
+ CURSOR_MOB_SIZE(cursor_max_dim),
+ &vmw_mob_placement, bo);
+
+ if (ret != 0)
+ goto teardown;
+
+ if ((*bo)->resource->mem_type != VMW_PL_MOB) {
+ DRM_ERROR("Obtained buffer object is not a MOB.\n");
+ ret = -ENOSYS;
+ goto teardown;
+ }
+
+ /* Fence the mob creation so we are guarateed to have the mob */
+ ret = ttm_bo_reserve(*bo, false, false, NULL);
+
+ if (ret != 0)
+ goto teardown;
+
+ vmw_bo_fence_single(*bo, NULL);
+
+ ttm_bo_unreserve(*bo);
+
+ drm_info(&dev_priv->drm, "Using CursorMob mobid %lu, max dimension %u\n",
+ (*bo)->resource->start, cursor_max_dim);
+ }
+
+ return 0;
+
+teardown:
+ vmw_du_destroy_cursor_mob_array(cursor);
return ret;
}
+#undef CURSOR_MOB_SIZE
+
+static void vmw_cursor_update_bo(struct vmw_private *dev_priv,
+ struct ttm_buffer_object *cm_bo,
+ struct ttm_bo_kmap_obj *cm_map,
+ struct vmw_buffer_object *bo,
+ u32 width, u32 height,
+ u32 hotspotX, u32 hotspotY)
+{
+ void *virtual;
+ bool dummy;
+
+ virtual = ttm_kmap_obj_virtual(&bo->map, &dummy);
+ if (virtual) {
+ vmw_cursor_update_image(dev_priv, cm_bo, cm_map, virtual,
+ width, height,
+ hotspotX, hotspotY);
+ atomic_dec(&bo->base_mapped_count);
+ }
+}
+
static void vmw_cursor_update_position(struct vmw_private *dev_priv,
bool show, int x, int y)
{
+ const uint32_t svga_cursor_on = show ? SVGA_CURSOR_ON_SHOW
+ : SVGA_CURSOR_ON_HIDE;
uint32_t count;
spin_lock(&dev_priv->cursor_lock);
- if (vmw_is_cursor_bypass3_enabled(dev_priv)) {
- vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, show ? 1 : 0);
+ if (dev_priv->capabilities2 & SVGA_CAP2_EXTRA_REGS) {
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_X, x);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_Y, y);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_SCREEN_ID, SVGA3D_INVALID_ID);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_ON, svga_cursor_on);
+ vmw_write(dev_priv, SVGA_REG_CURSOR4_SUBMIT, TRUE);
+ } else if (vmw_is_cursor_bypass3_enabled(dev_priv)) {
+ vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, svga_cursor_on);
vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x);
vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y);
count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT);
@@ -139,7 +262,7 @@ static void vmw_cursor_update_position(struct vmw_private *dev_priv,
} else {
vmw_write(dev_priv, SVGA_REG_CURSOR_X, x);
vmw_write(dev_priv, SVGA_REG_CURSOR_Y, y);
- vmw_write(dev_priv, SVGA_REG_CURSOR_ON, show ? 1 : 0);
+ vmw_write(dev_priv, SVGA_REG_CURSOR_ON, svga_cursor_on);
}
spin_unlock(&dev_priv->cursor_lock);
}
@@ -269,7 +392,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
continue;
du->cursor_age = du->cursor_surface->snooper.age;
- vmw_cursor_update_image(dev_priv,
+ vmw_cursor_update_image(dev_priv, NULL, NULL,
du->cursor_surface->snooper.image,
64, 64,
du->hotspot_x + du->core_hotspot_x,
@@ -283,7 +406,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
void vmw_du_cursor_plane_destroy(struct drm_plane *plane)
{
vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0);
-
+ vmw_du_destroy_cursor_mob_array(vmw_plane_to_vcp(plane));
drm_plane_cleanup(plane);
}
@@ -321,7 +444,7 @@ void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
/**
- * vmw_du_plane_cleanup_fb - Unpins the cursor
+ * vmw_du_plane_cleanup_fb - Unpins the plane surface
*
* @plane: display plane
* @old_state: Contains the FB to clean up
@@ -341,6 +464,55 @@ vmw_du_plane_cleanup_fb(struct drm_plane *plane,
/**
+ * vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface
+ *
+ * @plane: cursor plane
+ * @old_state: contains the state to clean up
+ *
+ * Unmaps all cursor bo mappings and unpins the cursor surface
+ *
+ * Returns 0 on success
+ */
+void
+vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
+ bool dummy;
+
+ if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) {
+ const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
+
+ if (likely(ret == 0)) {
+ if (atomic_read(&vps->bo->base_mapped_count) == 0)
+ ttm_bo_kunmap(&vps->bo->map);
+ ttm_bo_unreserve(&vps->bo->base);
+ }
+ }
+
+ if (vps->cm_bo != NULL && ttm_kmap_obj_virtual(&vps->cm_map, &dummy) != NULL) {
+ const int ret = ttm_bo_reserve(vps->cm_bo, true, false, NULL);
+
+ if (likely(ret == 0)) {
+ ttm_bo_kunmap(&vps->cm_map);
+ ttm_bo_unreserve(vps->cm_bo);
+ }
+ }
+
+ vmw_du_plane_unpin_surf(vps, false);
+
+ if (vps->surf) {
+ vmw_surface_unreference(&vps->surf);
+ vps->surf = NULL;
+ }
+
+ if (vps->bo) {
+ vmw_bo_unreference(&vps->bo);
+ vps->bo = NULL;
+ }
+}
+
+/**
* vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it
*
* @plane: display plane
@@ -353,14 +525,21 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
struct drm_framebuffer *fb = new_state->fb;
+ struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
+ struct ttm_buffer_object *cm_bo = NULL;
+ bool dummy;
+ int ret = 0;
-
- if (vps->surf)
+ if (vps->surf) {
vmw_surface_unreference(&vps->surf);
+ vps->surf = NULL;
+ }
- if (vps->bo)
+ if (vps->bo) {
vmw_bo_unreference(&vps->bo);
+ vps->bo = NULL;
+ }
if (fb) {
if (vmw_framebuffer_to_vfb(fb)->bo) {
@@ -372,7 +551,90 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
}
}
+ vps->cm_bo = NULL;
+
+ if (vps->surf == NULL && vps->bo != NULL) {
+ const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32);
+
+ /* Not using vmw_bo_map_and_cache() helper here as we need to reserve
+ the ttm_buffer_object first which wmw_bo_map_and_cache() omits. */
+ ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
+
+ if (unlikely(ret != 0))
+ return -ENOMEM;
+
+ ret = ttm_bo_kmap(&vps->bo->base, 0, PFN_UP(size), &vps->bo->map);
+
+ if (likely(ret == 0))
+ atomic_inc(&vps->bo->base_mapped_count);
+
+ ttm_bo_unreserve(&vps->bo->base);
+
+ if (unlikely(ret != 0))
+ return -ENOMEM;
+ }
+
+ if (vps->surf || vps->bo) {
+ unsigned cursor_mob_idx = vps->cursor_mob_idx;
+
+ /* Lazily set up cursor MOBs just once -- no reattempts. */
+ if (cursor_mob_idx == 0 && vcp->cursor_mob[0] == NULL)
+ if (vmw_du_create_cursor_mob_array(vcp) != 0)
+ vps->cursor_mob_idx = cursor_mob_idx = -1U;
+
+ if (cursor_mob_idx < ARRAY_SIZE(vcp->cursor_mob)) {
+ const u32 size = sizeof(SVGAGBCursorHeader) +
+ new_state->crtc_w * new_state->crtc_h * sizeof(u32);
+
+ cm_bo = vcp->cursor_mob[cursor_mob_idx];
+
+ if (cm_bo->resource->num_pages * PAGE_SIZE < size) {
+ ret = -EINVAL;
+ goto error_bo_unmap;
+ }
+
+ ret = ttm_bo_reserve(cm_bo, false, false, NULL);
+
+ if (unlikely(ret != 0)) {
+ ret = -ENOMEM;
+ goto error_bo_unmap;
+ }
+
+ ret = ttm_bo_kmap(cm_bo, 0, PFN_UP(size), &vps->cm_map);
+
+ /*
+ * We just want to try to get mob bind to finish
+ * so that the first write to SVGA_REG_CURSOR_MOBID
+ * is done with a buffer that the device has already
+ * seen
+ */
+ (void) ttm_bo_wait(cm_bo, false, false);
+
+ ttm_bo_unreserve(cm_bo);
+
+ if (unlikely(ret != 0)) {
+ ret = -ENOMEM;
+ goto error_bo_unmap;
+ }
+
+ vps->cursor_mob_idx = cursor_mob_idx ^ 1;
+ vps->cm_bo = cm_bo;
+ }
+ }
+
return 0;
+
+error_bo_unmap:
+ if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) {
+ const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
+ if (likely(ret == 0)) {
+ atomic_dec(&vps->bo->base_mapped_count);
+ ttm_bo_kunmap(&vps->bo->map);
+ ttm_bo_unreserve(&vps->bo->base);
+ }
+ }
+
+ return ret;
}
@@ -389,8 +651,6 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
s32 hotspot_x, hotspot_y;
- int ret = 0;
-
hotspot_x = du->hotspot_x;
hotspot_y = du->hotspot_y;
@@ -406,33 +666,31 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
if (vps->surf) {
du->cursor_age = du->cursor_surface->snooper.age;
- ret = vmw_cursor_update_image(dev_priv,
- vps->surf->snooper.image,
- 64, 64, hotspot_x,
- hotspot_y);
+ vmw_cursor_update_image(dev_priv, vps->cm_bo, &vps->cm_map,
+ vps->surf->snooper.image,
+ new_state->crtc_w,
+ new_state->crtc_h,
+ hotspot_x, hotspot_y);
} else if (vps->bo) {
- ret = vmw_cursor_update_bo(dev_priv, vps->bo,
- new_state->crtc_w,
- new_state->crtc_h,
- hotspot_x, hotspot_y);
+ vmw_cursor_update_bo(dev_priv, vps->cm_bo, &vps->cm_map,
+ vps->bo,
+ new_state->crtc_w,
+ new_state->crtc_h,
+ hotspot_x, hotspot_y);
} else {
vmw_cursor_update_position(dev_priv, false, 0, 0);
return;
}
- if (!ret) {
- du->cursor_x = new_state->crtc_x + du->set_gui_x;
- du->cursor_y = new_state->crtc_y + du->set_gui_y;
+ du->cursor_x = new_state->crtc_x + du->set_gui_x;
+ du->cursor_y = new_state->crtc_y + du->set_gui_y;
- vmw_cursor_update_position(dev_priv, true,
- du->cursor_x + hotspot_x,
- du->cursor_y + hotspot_y);
+ vmw_cursor_update_position(dev_priv, true,
+ du->cursor_x + hotspot_x,
+ du->cursor_y + hotspot_y);
- du->core_hotspot_x = hotspot_x - du->hotspot_x;
- du->core_hotspot_y = hotspot_y - du->hotspot_y;
- } else {
- DRM_ERROR("Failed to update cursor image\n");
- }
+ du->core_hotspot_x = hotspot_x - du->hotspot_x;
+ du->core_hotspot_y = hotspot_y - du->hotspot_y;
}
@@ -518,7 +776,7 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
if (new_state->crtc_w != 64 || new_state->crtc_h != 64) {
DRM_ERROR("Invalid cursor dimensions (%d, %d)\n",
new_state->crtc_w, new_state->crtc_h);
- ret = -EINVAL;
+ return -EINVAL;
}
if (!vmw_framebuffer_to_vfb(fb)->bo)
@@ -526,10 +784,10 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
if (surface && !surface->snooper.image) {
DRM_ERROR("surface not suitable for cursor\n");
- ret = -EINVAL;
+ return -EINVAL;
}
- return ret;
+ return 0;
}
@@ -712,7 +970,6 @@ void vmw_du_plane_reset(struct drm_plane *plane)
{
struct vmw_plane_state *vps;
-
if (plane->state)
vmw_du_plane_destroy_state(plane, plane->state);
@@ -914,6 +1171,15 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
* Sanity checks.
*/
+ if (!drm_any_plane_has_format(&dev_priv->drm,
+ mode_cmd->pixel_format,
+ mode_cmd->modifier[0])) {
+ drm_dbg(&dev_priv->drm,
+ "unsupported pixel format %p4cc / modifier 0x%llx\n",
+ &mode_cmd->pixel_format, mode_cmd->modifier[0]);
+ return -EINVAL;
+ }
+
/* Surface must be marked as a scanout. */
if (unlikely(!surface->metadata.scanout))
return -EINVAL;
@@ -1236,20 +1502,13 @@ static int vmw_kms_new_framebuffer_bo(struct vmw_private *dev_priv,
return -EINVAL;
}
- /* Limited framebuffer color depth support for screen objects */
- if (dev_priv->active_display_unit == vmw_du_screen_object) {
- switch (mode_cmd->pixel_format) {
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
- break;
- case DRM_FORMAT_XRGB1555:
- case DRM_FORMAT_RGB565:
- break;
- default:
- DRM_ERROR("Invalid pixel format: %p4cc\n",
- &mode_cmd->pixel_format);
- return -EINVAL;
- }
+ if (!drm_any_plane_has_format(&dev_priv->drm,
+ mode_cmd->pixel_format,
+ mode_cmd->modifier[0])) {
+ drm_dbg(&dev_priv->drm,
+ "unsupported pixel format %p4cc / modifier 0x%llx\n",
+ &mode_cmd->pixel_format, mode_cmd->modifier[0]);
+ return -EINVAL;
}
vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
@@ -1344,7 +1603,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
mode_cmd,
is_bo_proxy);
-
/*
* vmw_create_bo_proxy() adds a reference that is no longer
* needed
@@ -1385,13 +1643,16 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
ret = vmw_user_lookup_handle(dev_priv, file_priv,
mode_cmd->handles[0],
&surface, &bo);
- if (ret)
+ if (ret) {
+ DRM_ERROR("Invalid buffer object handle %u (0x%x).\n",
+ mode_cmd->handles[0], mode_cmd->handles[0]);
goto err_out;
+ }
if (!bo &&
!vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) {
- DRM_ERROR("Surface size cannot exceed %dx%d",
+ DRM_ERROR("Surface size cannot exceed %dx%d\n",
dev_priv->texture_max_width,
dev_priv->texture_max_height);
goto err_out;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 4d36e8507380..1d1c8b82c898 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -247,7 +247,6 @@ struct vmw_framebuffer_bo {
static const uint32_t __maybe_unused vmw_primary_plane_formats[] = {
DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
};
@@ -261,6 +260,7 @@ static const uint32_t __maybe_unused vmw_cursor_plane_formats[] = {
#define vmw_plane_state_to_vps(x) container_of(x, struct vmw_plane_state, base)
#define vmw_connector_state_to_vcs(x) \
container_of(x, struct vmw_connector_state, base)
+#define vmw_plane_to_vcp(x) container_of(x, struct vmw_cursor_plane, base)
/**
* Derived class for crtc state object
@@ -293,6 +293,14 @@ struct vmw_plane_state {
/* For CPU Blit */
unsigned int cpp;
+
+ /* CursorMob flipping index; -1 if cursor mobs not used */
+ unsigned int cursor_mob_idx;
+ /* Currently-active CursorMob */
+ struct ttm_buffer_object *cm_bo;
+ /* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update
+ IFF currently-active CursorMob above is valid */
+ struct ttm_bo_kmap_obj cm_map;
};
@@ -326,6 +334,17 @@ struct vmw_connector_state {
};
/**
+ * Derived class for cursor plane object
+ *
+ * @base DRM plane object
+ * @cursor_mob array of two MOBs for CursorMob flipping
+ */
+struct vmw_cursor_plane {
+ struct drm_plane base;
+ struct ttm_buffer_object *cursor_mob[2];
+};
+
+/**
* Base class display unit.
*
* Since the SVGA hw doesn't have a concept of a crtc, encoder or connector
@@ -337,7 +356,7 @@ struct vmw_display_unit {
struct drm_encoder encoder;
struct drm_connector connector;
struct drm_plane primary;
- struct drm_plane cursor;
+ struct vmw_cursor_plane cursor;
struct vmw_surface *cursor_surface;
struct vmw_buffer_object *cursor_bo;
@@ -452,6 +471,8 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
/* Universal Plane Helpers */
void vmw_du_primary_plane_destroy(struct drm_plane *plane);
void vmw_du_cursor_plane_destroy(struct drm_plane *plane);
+int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp);
+void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp);
/* Atomic Helpers */
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
@@ -462,6 +483,8 @@ void vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
struct drm_atomic_state *state);
int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state);
+void vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
+ struct drm_plane_state *old_state);
void vmw_du_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state);
void vmw_du_plane_reset(struct drm_plane *plane);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index fb58a71c458f..e4347faccee0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -338,7 +338,7 @@ drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = {
.atomic_check = vmw_du_cursor_plane_atomic_check,
.atomic_update = vmw_du_cursor_plane_atomic_update,
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
- .cleanup_fb = vmw_du_plane_cleanup_fb,
+ .cleanup_fb = vmw_du_cursor_plane_cleanup_fb,
};
static const struct
@@ -363,7 +363,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct drm_plane *primary, *cursor;
+ struct drm_plane *primary;
+ struct vmw_cursor_plane *cursor;
struct drm_crtc *crtc;
int ret;
@@ -392,7 +393,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
ldu->base.is_implicit = true;
/* Initialize primary plane */
- ret = drm_universal_plane_init(dev, &ldu->base.primary,
+ ret = drm_universal_plane_init(dev, primary,
0, &vmw_ldu_plane_funcs,
vmw_primary_plane_formats,
ARRAY_SIZE(vmw_primary_plane_formats),
@@ -409,7 +410,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
*/
if (vmw_cmd_supported(dev_priv)) {
/* Initialize cursor plane */
- ret = drm_universal_plane_init(dev, &ldu->base.cursor,
+ ret = drm_universal_plane_init(dev, &cursor->base,
0, &vmw_ldu_cursor_funcs,
vmw_cursor_plane_formats,
ARRAY_SIZE(vmw_cursor_plane_formats),
@@ -420,7 +421,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free;
}
- drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs);
+ drm_plane_helper_add(&cursor->base, &vmw_ldu_cursor_plane_helper_funcs);
}
ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
@@ -450,9 +451,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free_encoder;
}
- ret = drm_crtc_init_with_planes(
- dev, crtc, &ldu->base.primary,
- vmw_cmd_supported(dev_priv) ? &ldu->base.cursor : NULL,
+ ret = drm_crtc_init_with_planes(dev, crtc, primary,
+ vmw_cmd_supported(dev_priv) ? &cursor->base : NULL,
&vmw_legacy_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Failed to initialize CRTC\n");
@@ -492,6 +492,8 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
int i, ret;
+ int num_display_units = (dev_priv->capabilities & SVGA_CAP_MULTIMON) ?
+ VMWGFX_NUM_DISPLAY_UNITS : 1;
if (unlikely(dev_priv->ldu_priv)) {
return -EINVAL;
@@ -506,21 +508,17 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
dev_priv->ldu_priv->last_num_active = 0;
dev_priv->ldu_priv->fb = NULL;
- /* for old hardware without multimon only enable one display */
- if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
- ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
- else
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev, num_display_units);
if (ret != 0)
goto err_free;
vmw_kms_create_implicit_placement_property(dev_priv);
- if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
- for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
- vmw_ldu_init(dev_priv, i);
- else
- vmw_ldu_init(dev_priv, 0);
+ for (i = 0; i < num_display_units; ++i) {
+ ret = vmw_ldu_init(dev_priv, i);
+ if (ret != 0)
+ goto err_free;
+ }
dev_priv->active_display_unit = vmw_du_legacy;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 708899ba2102..626067104751 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -859,22 +859,21 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo,
struct ttm_device *bdev = bo->bdev;
struct vmw_private *dev_priv;
-
dev_priv = container_of(bdev, struct vmw_private, bdev);
mutex_lock(&dev_priv->binding_mutex);
- dx_query_mob = container_of(bo, struct vmw_buffer_object, base);
- if (!dx_query_mob || !dx_query_mob->dx_query_ctx) {
- mutex_unlock(&dev_priv->binding_mutex);
- return;
- }
-
/* If BO is being moved from MOB to system memory */
if (new_mem->mem_type == TTM_PL_SYSTEM &&
old_mem->mem_type == VMW_PL_MOB) {
struct vmw_fence_obj *fence;
+ dx_query_mob = container_of(bo, struct vmw_buffer_object, base);
+ if (!dx_query_mob || !dx_query_mob->dx_query_ctx) {
+ mutex_unlock(&dev_priv->binding_mutex);
+ return;
+ }
+
(void) vmw_query_readback_all(dx_query_mob);
mutex_unlock(&dev_priv->binding_mutex);
@@ -888,7 +887,6 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo,
(void) ttm_bo_wait(bo, false, false);
} else
mutex_unlock(&dev_priv->binding_mutex);
-
}
/**
@@ -1165,8 +1163,9 @@ int vmw_resources_clean(struct vmw_buffer_object *vbo, pgoff_t start,
vmw_bo_fence_single(bo, NULL);
if (bo->moving)
dma_fence_put(bo->moving);
- bo->moving = dma_fence_get
- (dma_resv_excl_fence(bo->base.resv));
+
+ return dma_resv_get_singleton(bo->base.resv, false,
+ &bo->moving);
}
return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 3004c7a719e9..c89ad3a2d141 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
- * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA
+ * Copyright 2011-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -804,7 +804,7 @@ drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = {
.atomic_check = vmw_du_cursor_plane_atomic_check,
.atomic_update = vmw_du_cursor_plane_atomic_update,
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
- .cleanup_fb = vmw_du_plane_cleanup_fb,
+ .cleanup_fb = vmw_du_cursor_plane_cleanup_fb,
};
static const struct
@@ -832,7 +832,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct drm_plane *primary, *cursor;
+ struct drm_plane *primary;
+ struct vmw_cursor_plane *cursor;
struct drm_crtc *crtc;
int ret;
@@ -859,7 +860,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
sou->base.is_implicit = false;
/* Initialize primary plane */
- ret = drm_universal_plane_init(dev, &sou->base.primary,
+ ret = drm_universal_plane_init(dev, primary,
0, &vmw_sou_plane_funcs,
vmw_primary_plane_formats,
ARRAY_SIZE(vmw_primary_plane_formats),
@@ -873,7 +874,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
drm_plane_enable_fb_damage_clips(primary);
/* Initialize cursor plane */
- ret = drm_universal_plane_init(dev, &sou->base.cursor,
+ ret = drm_universal_plane_init(dev, &cursor->base,
0, &vmw_sou_cursor_funcs,
vmw_cursor_plane_formats,
ARRAY_SIZE(vmw_cursor_plane_formats),
@@ -884,7 +885,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free;
}
- drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs);
+ drm_plane_helper_add(&cursor->base, &vmw_sou_cursor_plane_helper_funcs);
ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL);
@@ -913,8 +914,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free_encoder;
}
- ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary,
- &sou->base.cursor,
+ ret = drm_crtc_init_with_planes(dev, crtc, primary,
+ &cursor->base,
&vmw_screen_object_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Failed to initialize CRTC\n");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index ae9a6044d448..eb014b97d156 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/******************************************************************************
*
- * COPYRIGHT (C) 2014-2015 VMware, Inc., Palo Alto, CA., USA
+ * COPYRIGHT (C) 2014-2022 VMware, Inc., Palo Alto, CA., USA
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -138,6 +138,11 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu);
* Screen Target Display Unit CRTC Functions
*****************************************************************************/
+static bool vmw_stdu_use_cpu_blit(const struct vmw_private *vmw)
+{
+ return !(vmw->capabilities & SVGA_CAP_3D) || vmw->vram_size < (32 * 1024 * 1024);
+}
+
/**
* vmw_stdu_crtc_destroy - cleans up the STDU
@@ -689,7 +694,7 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
container_of(vfb, struct vmw_framebuffer_bo, base)->buffer;
struct vmw_stdu_dirty ddirty;
int ret;
- bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
+ bool cpu_blit = vmw_stdu_use_cpu_blit(dev_priv);
DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
/*
@@ -1164,7 +1169,7 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
* so cache these mappings
*/
if (vps->content_fb_type == SEPARATE_BO &&
- !(dev_priv->capabilities & SVGA_CAP_3D))
+ vmw_stdu_use_cpu_blit(dev_priv))
vps->cpp = new_fb->pitches[0] / new_fb->width;
return 0;
@@ -1368,7 +1373,7 @@ static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
bo_update.base.vfb = vfb;
bo_update.base.out_fence = out_fence;
bo_update.base.mutex = NULL;
- bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
+ bo_update.base.cpu_blit = vmw_stdu_use_cpu_blit(dev_priv);
bo_update.base.intr = false;
/*
@@ -1685,7 +1690,7 @@ drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = {
.atomic_check = vmw_du_cursor_plane_atomic_check,
.atomic_update = vmw_du_cursor_plane_atomic_update,
.prepare_fb = vmw_du_cursor_plane_prepare_fb,
- .cleanup_fb = vmw_du_plane_cleanup_fb,
+ .cleanup_fb = vmw_du_cursor_plane_cleanup_fb,
};
static const struct
@@ -1723,11 +1728,11 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
struct drm_device *dev = &dev_priv->drm;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct drm_plane *primary, *cursor;
+ struct drm_plane *primary;
+ struct vmw_cursor_plane *cursor;
struct drm_crtc *crtc;
int ret;
-
stdu = kzalloc(sizeof(*stdu), GFP_KERNEL);
if (!stdu)
return -ENOMEM;
@@ -1759,7 +1764,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
drm_plane_enable_fb_damage_clips(primary);
/* Initialize cursor plane */
- ret = drm_universal_plane_init(dev, cursor,
+ ret = drm_universal_plane_init(dev, &cursor->base,
0, &vmw_stdu_cursor_funcs,
vmw_cursor_plane_formats,
ARRAY_SIZE(vmw_cursor_plane_formats),
@@ -1770,7 +1775,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free;
}
- drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs);
+ drm_plane_helper_add(&cursor->base, &vmw_stdu_cursor_plane_helper_funcs);
ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL);
@@ -1799,8 +1804,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
goto err_free_encoder;
}
- ret = drm_crtc_init_with_planes(dev, crtc, &stdu->base.primary,
- &stdu->base.cursor,
+ ret = drm_crtc_init_with_planes(dev, crtc, primary,
+ &cursor->base,
&vmw_stdu_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Failed to initialize CRTC\n");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
index b84ecc6d6611..4e3938e62c08 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
@@ -517,7 +517,7 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
ttm_cached);
else
ret = ttm_tt_init(&vmw_be->dma_ttm, bo, page_flags,
- ttm_cached);
+ ttm_cached, 0);
if (unlikely(ret != 0))
goto out_no_init;