A fair amount of fixes this week as well:

- create blend mode property for more driver planes
 - Kconfig cleanups across the board
 - sched: null pointer dereference fix in kunit tests
 - ethosu misc fixes about error handling and corner cases handling
 - ivpu fixes about buffer and metadata validation
 - rockchip: fixes around buffer overflow and kconfig
 - tc358768: fix bus flags and error handling
 -----BEGIN PGP SIGNATURE-----
 
 iJUEABMJAB0WIQTkHFbLp4ejekA/qfgnX84Zoj2+dgUCaqJd2wAKCRAnX84Zoj2+
 dqFCAYDycQJGGWRAjUwfVS8pQApFdY1kWJ6UA6L4kl+luQbO9g2/T6ZnrCMKtfCD
 GcRzt9kBgLggzOf1hApF+o1fqSldKEqVQm17sGChXfU4p4c2XgUrAjgB5SuL7pIi
 InrtooUpiw==
 =xFoP
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-fixes-2026-09-10' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes

A fair amount of fixes this week as well:

- create blend mode property for more driver planes
- Kconfig cleanups across the board
- sched: null pointer dereference fix in kunit tests
- ethosu misc fixes about error handling and corner cases handling
- ivpu fixes about buffer and metadata validation
- rockchip: fixes around buffer overflow and kconfig
- tc358768: fix bus flags and error handling

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/aqJd5TPXpwqwsM0F@houat
This commit is contained in:
Dave Airlie 2026-09-11 10:55:23 +10:00
commit 2991f9f794
19 changed files with 145 additions and 64 deletions

View File

@ -87,6 +87,7 @@ struct gen_pool;
#define PMU_EV_TYPE_IDLE 0x20
enum ethosu_cmds {
NPU_OP_STOP = 0x0,
NPU_OP_CONV = 0x2,
NPU_OP_DEPTHWISE = 0x3,
NPU_OP_POOL = 0x5,

View File

@ -281,8 +281,6 @@ static int ethosu_device_suspend(struct device *dev)
static int ethosu_sram_init(struct ethosu_device *ethosudev)
{
ethosudev->npu_info.sram_size = 0;
ethosudev->srampool = of_gen_pool_get(ethosudev->base.dev->of_node, "sram", 0);
if (!ethosudev->srampool)
return 0;
@ -293,6 +291,7 @@ static int ethosu_sram_init(struct ethosu_device *ethosudev)
ethosudev->npu_info.sram_size,
&ethosudev->sramphys);
if (!ethosudev->sram) {
ethosudev->npu_info.sram_size = 0;
dev_err(ethosudev->base.dev, "failed to allocate from SRAM pool\n");
return -ENOMEM;
}

View File

@ -390,6 +390,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
struct ethosu_validated_cmdstream_info __free(kfree) *info = kzalloc_obj(*info);
struct ethosu_device *edev = to_ethosu_device(ddev);
u32 *bocmds = bo->base.vaddr;
bool ends_with_stop = false;
struct cmd_state st;
int i, ret;
@ -426,6 +427,11 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
}
switch (cmd) {
case NPU_OP_STOP:
if (i != size / 4 - 1)
return -EINVAL;
ends_with_stop = true;
break;
case NPU_OP_DMA_START:
srclen = dma_length(info, &st.dma, &st.dma.src);
dstlen = dma_length(info, &st.dma, &st.dma.dst);
@ -688,6 +694,9 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
}
}
if (!ends_with_stop)
return -EINVAL;
for (i = 0; i < NPU_BASEP_REGION_MAX; i++) {
if (!info->region_size[i])
continue;

View File

@ -343,7 +343,7 @@ int ethosu_job_init(struct ethosu_device *edev)
ret = devm_request_threaded_irq(dev, edev->irq,
ethosu_job_irq_handler,
ethosu_job_irq_handler_thread,
IRQF_SHARED, KBUILD_MODNAME,
0, KBUILD_MODNAME,
edev);
if (ret) {
dev_err(dev, "failed to request irq\n");
@ -374,12 +374,10 @@ int ethosu_job_open(struct ethosu_file_priv *ethosu_priv)
{
struct ethosu_device *dev = ethosu_priv->edev;
struct drm_gpu_scheduler *sched = &dev->sched;
int ret;
ret = drm_sched_entity_init(&ethosu_priv->sched_entity,
DRM_SCHED_PRIORITY_NORMAL,
&sched, 1, NULL);
return WARN_ON(ret);
return drm_sched_entity_init(&ethosu_priv->sched_entity,
DRM_SCHED_PRIORITY_NORMAL,
&sched, 1, NULL);
}
void ethosu_job_close(struct ethosu_file_priv *ethosu_priv)
@ -449,13 +447,13 @@ static int ethosu_ioctl_submit_job(struct drm_device *dev, struct drm_file *file
if (!cmd_info->region_size[i])
continue;
if (i == ETHOSU_SRAM_REGION) {
if (cmd_info->region_size[i] <= edev->npu_info.sram_size)
if (cmd_info->region_size[i] <= ejob->sram_size)
continue;
dev_err(dev->dev,
"cmd stream region %d size greater than SRAM size (%llu > %u)\n",
"cmd stream region %d size greater than job SRAM size (%llu > %u)\n",
i, cmd_info->region_size[i],
edev->npu_info.sram_size);
ejob->sram_size);
ret = -EINVAL;
goto out_cleanup_job;
}

View File

@ -26,10 +26,17 @@ MODULE_PARM_DESC(fw_log_level,
" error=" __stringify(IVPU_FW_LOG_ERROR)
" fatal=" __stringify(IVPU_FW_LOG_FATAL));
struct ivpu_fw_log_desc {
struct vpu_tracing_buffer_header *log;
u32 header_size;
u32 size;
};
static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset,
struct vpu_tracing_buffer_header **out_log)
struct ivpu_fw_log_desc *desc)
{
struct vpu_tracing_buffer_header *log;
u32 header_size, size;
if ((*offset + sizeof(*log)) > ivpu_bo_size(bo))
return -EINVAL;
@ -39,26 +46,32 @@ static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *off
if (log->vpu_canary_start != VPU_TRACING_BUFFER_CANARY)
return -EINVAL;
if (log->header_size < sizeof(*log) || log->header_size > 1024) {
ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size);
header_size = READ_ONCE(log->header_size);
size = READ_ONCE(log->size);
if (header_size < sizeof(*log) || header_size > 1024) {
ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", header_size);
return -EINVAL;
}
if (log->size < log->header_size) {
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
if ((char *)log + size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", size);
return -EINVAL;
}
if ((char *)log + log->size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
if (size < header_size) {
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x < header size 0x%x\n",
size, header_size);
return -EINVAL;
}
*out_log = log;
*offset += log->size;
desc->log = log;
desc->header_size = header_size;
desc->size = size;
*offset += size;
ivpu_dbg(vdev, FW_BOOT,
"FW log name \"%s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d",
log->name, log->write_index, log->size, log->wrap_count, log->header_version,
log->header_size, log->format, log->alignment);
"FW log name \"%.*s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d",
(int)ARRAY_SIZE(log->name), log->name, log->write_index, size, log->wrap_count,
log->header_version, header_size, log->format, log->alignment);
return 0;
}
@ -94,11 +107,12 @@ static void fw_log_print_lines(char *buffer, u32 size, struct drm_printer *p)
drm_printf(p, "%s", line);
}
static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const char *prefix,
static void fw_log_print_buffer(struct ivpu_fw_log_desc *desc, const char *prefix,
bool only_new_msgs, struct drm_printer *p)
{
char *log_data = (void *)log + log->header_size;
u32 data_size = log->size - log->header_size;
struct vpu_tracing_buffer_header *log = desc->log;
char *log_data = (void *)log + desc->header_size;
u32 data_size = desc->size - desc->header_size;
u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0;
u32 log_end = READ_ONCE(log->write_index);
@ -109,7 +123,8 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
if (log->wrap_count == log->read_wrap_count) {
if (log_end <= log_start) {
drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name);
drm_printf(p, "==== %s \"%.*s\" log empty ====\n", prefix,
(int)ARRAY_SIZE(log->name), log->name);
return;
}
} else if (log->wrap_count == log->read_wrap_count + 1) {
@ -119,7 +134,8 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
log_start = log_end;
}
drm_printf(p, "==== %s \"%s\" log start ====\n", prefix, log->name);
drm_printf(p, "==== %s \"%.*s\" log start ====\n", prefix, (int)ARRAY_SIZE(log->name),
log->name);
if (log_end > log_start) {
fw_log_print_lines(log_data + log_start, log_end - log_start, p);
} else {
@ -127,18 +143,19 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
fw_log_print_lines(log_data, log_end, p);
}
drm_printf(p, "\n\x1b[0m"); /* add new line and clear formatting */
drm_printf(p, "==== %s \"%s\" log end ====\n", prefix, log->name);
drm_printf(p, "==== %s \"%.*s\" log end ====\n", prefix, (int)ARRAY_SIZE(log->name),
log->name);
}
static void
fw_log_print_all_in_bo(struct ivpu_device *vdev, const char *name,
struct ivpu_bo *bo, bool only_new_msgs, struct drm_printer *p)
{
struct vpu_tracing_buffer_header *log;
struct ivpu_fw_log_desc desc;
u32 next = 0;
while (fw_log_from_bo(vdev, bo, &next, &log) == 0)
fw_log_print_buffer(log, name, only_new_msgs, p);
while (fw_log_from_bo(vdev, bo, &next, &desc) == 0)
fw_log_print_buffer(&desc, name, only_new_msgs, p);
}
void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p)
@ -149,36 +166,36 @@ void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_
void ivpu_fw_log_mark_read(struct ivpu_device *vdev)
{
struct vpu_tracing_buffer_header *log;
struct ivpu_fw_log_desc desc;
u32 next;
next = 0;
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) {
log->read_index = READ_ONCE(log->write_index);
log->read_wrap_count = READ_ONCE(log->wrap_count);
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) {
desc.log->read_index = READ_ONCE(desc.log->write_index);
desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count);
}
next = 0;
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) {
log->read_index = READ_ONCE(log->write_index);
log->read_wrap_count = READ_ONCE(log->wrap_count);
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) {
desc.log->read_index = READ_ONCE(desc.log->write_index);
desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count);
}
}
void ivpu_fw_log_reset(struct ivpu_device *vdev)
{
struct vpu_tracing_buffer_header *log;
struct ivpu_fw_log_desc desc;
u32 next;
next = 0;
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) {
log->read_index = 0;
log->read_wrap_count = 0;
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) {
desc.log->read_index = 0;
desc.log->read_wrap_count = 0;
}
next = 0;
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) {
log->read_index = 0;
log->read_wrap_count = 0;
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) {
desc.log->read_index = 0;
desc.log->read_wrap_count = 0;
}
}

View File

@ -87,15 +87,23 @@ static inline bool ivpu_bo_is_resident(struct ivpu_bo *bo)
return !!bo->base.pages;
}
static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr)
static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u64 vpu_addr, u64 size)
{
u64 bo_size = ivpu_bo_size(bo);
u64 offset;
if (vpu_addr < bo->vpu_addr)
return NULL;
if (vpu_addr >= (bo->vpu_addr + ivpu_bo_size(bo)))
if (size > bo_size)
return NULL;
return ivpu_bo_vaddr(bo) + (vpu_addr - bo->vpu_addr);
offset = vpu_addr - bo->vpu_addr;
if (offset > bo_size - size)
return NULL;
return ivpu_bo_vaddr(bo) + offset;
}
static inline u32 cpu_to_vpu_addr(struct ivpu_bo *bo, void *cpu_addr)

View File

@ -79,7 +79,7 @@ ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
return -ENOMEM;
}
tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr);
tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr, sizeof(*tx_buf));
if (drm_WARN_ON(&vdev->drm, !tx_buf)) {
gen_pool_free(ipc->mm_tx, tx_buf_vpu_addr, sizeof(*tx_buf));
return -EIO;
@ -420,7 +420,7 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
return;
}
ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr);
ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr, sizeof(*ipc_hdr));
if (!ipc_hdr) {
ivpu_warn_ratelimited(vdev, "IPC msg 0x%x out of range\n", vpu_addr);
continue;
@ -429,7 +429,8 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
jsm_msg = NULL;
if (ipc_hdr->channel != IVPU_IPC_CHAN_BOOT_MSG) {
jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr);
jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr,
sizeof(*jsm_msg));
if (!jsm_msg) {
ivpu_warn_ratelimited(vdev, "JSM msg 0x%x out of range\n",
ipc_hdr->data_addr);

View File

@ -6,7 +6,6 @@ config DRM_ADP
select DRM_KMS_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_DISPLAY_HELPER
select DRM_KMS_DMA_HELPER
select DRM_GEM_DMA_HELPER
select DRM_PANEL_BRIDGE
select VIDEOMODE_HELPERS

View File

@ -25,6 +25,7 @@
#include <linux/sizes.h>
#include <drm/drm_atomic.h>
#include <drm/drm_blend.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_gem_atomic_helper.h>
@ -355,6 +356,8 @@ int ast_cursor_plane_init(struct ast_device *ast)
}
drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs);
drm_plane_enable_fb_damage_clips(cursor_plane);
drm_plane_create_blend_mode_property(cursor_plane,
BIT(DRM_MODE_BLEND_COVERAGE));
return 0;
}

View File

@ -1263,10 +1263,13 @@ tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
static bool tc358768_mode_fixup(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
static int tc358768_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
/* Default to positive sync */
if (!(adjusted_mode->flags &
@ -1277,13 +1280,15 @@ static bool tc358768_mode_fixup(struct drm_bridge *bridge,
(DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC;
return true;
bridge_state->input_bus_cfg.flags = bridge->timings->input_bus_flags;
return 0;
}
static const struct drm_bridge_funcs tc358768_bridge_funcs = {
.attach = tc358768_bridge_attach,
.mode_valid = tc358768_bridge_mode_valid,
.mode_fixup = tc358768_mode_fixup,
.atomic_check = tc358768_bridge_atomic_check,
.atomic_pre_enable = tc358768_bridge_atomic_pre_enable,
.atomic_enable = tc358768_bridge_atomic_enable,
.atomic_disable = tc358768_bridge_atomic_disable,

View File

@ -403,7 +403,7 @@ static int sn65dsi83_reset_pipe(struct sn65dsi83 *sn65dsi83)
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
return 0;
return err;
}
static void sn65dsi83_reset_work(struct work_struct *ws)
@ -419,11 +419,13 @@ static void sn65dsi83_reset_work(struct work_struct *ws)
ret = sn65dsi83_reset_pipe(ctx);
if (ret) {
dev_err(ctx->dev, "reset pipe failed %pe\n", ERR_PTR(ret));
return;
goto bridge_exit;
}
if (ctx->irq)
enable_irq(ctx->irq);
bridge_exit:
drm_bridge_exit(idx);
}

View File

@ -322,6 +322,19 @@ int drm_exec_prepare_array(struct drm_exec *exec,
{
int ret;
/*
* Make sure to lock a contended object even when no objects are
* given, otherwise drm_exec_retry_on_contention() would loop
* forever on patterns like:
*
* ret = drm_exec_prepare_array(exec, objs, num_objects, ...);
* drm_exec_retry_on_contention(exec);
*
* with num_objects == 0.
*/
if (!num_objects)
return drm_exec_lock_contended(exec);
for (unsigned int i = 0; i < num_objects; ++i) {
ret = drm_exec_prepare_obj(exec, objects[i], num_fences);
if (unlikely(ret))

View File

@ -4,7 +4,6 @@ config DRM_LOGICVC
depends on OF || COMPILE_TEST
select DRM_CLIENT_SELECTION
select DRM_KMS_HELPER
select DRM_KMS_DMA_HELPER
select DRM_GEM_DMA_HELPER
select REGMAP
select REGMAP_MMIO

View File

@ -30,6 +30,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_framebuffer.h>
@ -993,6 +994,9 @@ static struct drm_plane *qxl_create_plane(struct qxl_device *qdev,
drm_plane_helper_add(plane, helper_funcs);
drm_plane_create_blend_mode_property(plane,
BIT(DRM_MODE_BLEND_PREMULTI));
return plane;
free_plane:

View File

@ -68,6 +68,7 @@ config ROCKCHIP_CDN_DP
config ROCKCHIP_DW_DP
bool "Rockchip specific extensions for Synopsys DW DP"
select DRM_BRIDGE_CONNECTOR
help
This selects support for Rockchip SoC specific extensions
to enable Synopsys DesignWare Cores based DisplayPort transmit
@ -145,6 +146,8 @@ config ROCKCHIP_RGB
config ROCKCHIP_RK3066_HDMI
bool "Rockchip specific extensions for RK3066 HDMI"
depends on DRM_ROCKCHIP
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
help
This selects support for Rockchip SoC specific extensions
for the RK3066 HDMI driver. If you want to enable

View File

@ -241,10 +241,11 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder,
of_graph_get_remote_port(endpoint.local_node);
of_property_read_u32(remote_port, "reg", &port_id);
sprintf(name, "%s vp%d", remote_port_parent->full_name, port_id);
snprintf(name, sizeof(name), "%s vp%d",
remote_port_parent->full_name, port_id);
} else {
sprintf(name, "%s %s",
remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb");
snprintf(name, sizeof(name), "%s %s",
remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb");
}
DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Valve Corporation */
#include <kunit/device.h>
#include "sched_tests.h"
/*
@ -288,6 +290,7 @@ static const struct drm_sched_backend_ops drm_mock_scheduler_ops = {
*/
struct drm_mock_scheduler *drm_mock_sched_new(struct kunit *test, long timeout)
{
static unsigned int instance;
struct drm_sched_init_args args = {
.ops = &drm_mock_scheduler_ops,
.num_rqs = DRM_SCHED_PRIORITY_COUNT,
@ -297,11 +300,19 @@ struct drm_mock_scheduler *drm_mock_sched_new(struct kunit *test, long timeout)
.name = "drm-mock-scheduler",
};
struct drm_mock_scheduler *sched;
struct device *dev;
char name[64];
int ret;
sched = kunit_kzalloc(test, sizeof(*sched), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, sched);
snprintf(name, sizeof(name), "%s-%u", args.name, instance++);
dev = kunit_device_register(test, name);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
args.dev = dev;
ret = drm_sched_init(&sched->base, &args);
KUNIT_ASSERT_EQ(test, ret, 0);

View File

@ -15,6 +15,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_edid.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
@ -540,6 +541,9 @@ static struct drm_plane *vbox_create_plane(struct vbox_private *vbox,
drm_plane_helper_add(plane, helper_funcs);
drm_plane_create_blend_mode_property(plane,
BIT(DRM_MODE_BLEND_COVERAGE));
return plane;
free_plane:

View File

@ -24,6 +24,7 @@
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_atomic_helper.h>
@ -609,6 +610,9 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
if (type == DRM_PLANE_TYPE_PRIMARY)
drm_plane_enable_fb_damage_clips(plane);
else if (type == DRM_PLANE_TYPE_CURSOR)
drm_plane_create_blend_mode_property(plane,
BIT(DRM_MODE_BLEND_PREMULTI));
return plane;
}