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

drm-misc-fies for v7.2-rc6:
- vmwgfx:
  - Improve various size checks and limit checks.
  - Fix oops when submitting  invalid execbuf ioctl.
  - Correctly lock in vmfwgx fence signaling path.
  - More validation of execbuf ioctl.
  - Fix oops in vmwgfx vkms init failure path.
  - Overflow handling in shader path.
- Improve firmware validation in panthor.
- Fix small leak in bridge/display-connector
- Improve imagination trace points.
- Fix QAIC transaction length check.
- Restrict some DP bandwidth calculations to HDMI DFP.

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

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/178a513f-2d7f-4e3a-811b-cd0d9dc309eb@linux.intel.com
This commit is contained in:
Dave Airlie
2026-07-31 14:33:49 +10:00
18 changed files with 230 additions and 65 deletions

View File

@@ -786,7 +786,7 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
break;
}
trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len);
if (trans_hdr->len < sizeof(trans_hdr) ||
if (trans_hdr->len < sizeof(*trans_hdr) ||
size_add(user_len, trans_hdr->len) > user_msg->len) {
ret = -EINVAL;
break;

View File

@@ -40,6 +40,13 @@ static int display_connector_attach(struct drm_bridge *bridge,
return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
}
static void display_connector_destroy(struct drm_bridge *bridge)
{
struct display_connector *conn = to_display_connector(bridge);
i2c_put_adapter(conn->bridge.ddc);
}
static enum drm_connector_status display_connector_detect(struct drm_bridge *bridge)
{
struct display_connector *conn = to_display_connector(bridge);
@@ -177,6 +184,7 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge,
static const struct drm_bridge_funcs display_connector_bridge_funcs = {
.attach = display_connector_attach,
.destroy = display_connector_destroy,
.detect = display_connector_bridge_detect,
.edid_read = display_connector_edid_read,
.atomic_get_output_bus_fmts = display_connector_get_output_bus_fmts,
@@ -403,9 +411,6 @@ static void display_connector_remove(struct platform_device *pdev)
regulator_disable(conn->supply);
drm_bridge_remove(&conn->bridge);
if (!IS_ERR(conn->bridge.ddc))
i2c_put_adapter(conn->bridge.ddc);
}
static const struct of_device_id display_connector_match[] = {

View File

@@ -3686,6 +3686,18 @@ int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
int bw;
u8 buf;
if (!drm_dp_is_branch(dpcd))
return 0;
if (dpcd[DP_DPCD_REV] < 0x11)
return 0;
if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
return 0;
if ((port_cap[0] & DP_DS_PORT_TYPE_MASK) != DP_DS_PORT_TYPE_HDMI)
return 0;
buf = port_cap[2];
bw = buf & DP_PCON_MAX_FRL_BW;

View File

@@ -726,8 +726,6 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job)
cmd->partial_render_geom_frag_fence.value = job->done_fence->seqno - 1;
}
trace_pvr_job_submit_fw(job);
/* Submit job to FW */
pvr_cccb_write_command_with_header(cccb, job->fw_ccb_cmd_type, job->cmd_len, job->cmd,
job->id, job->id);
@@ -802,6 +800,9 @@ static struct dma_fence *pvr_queue_run_job(struct drm_sched_job *sched_job)
job->hwrt,
frag_job->fw_ccb_cmd_type ==
ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR);
trace_pvr_job_submit_fw(geom_job);
trace_pvr_job_submit_fw(frag_job);
} else {
struct pvr_queue *queue = container_of(job->base.sched,
struct pvr_queue, scheduler);
@@ -809,6 +810,8 @@ static struct dma_fence *pvr_queue_run_job(struct drm_sched_job *sched_job)
pvr_cccb_send_kccb_kick(pvr_dev, &queue->cccb,
pvr_context_get_fw_addr(job->ctx) + queue->ctx_offset,
job->hwrt);
trace_pvr_job_submit_fw(job);
}
return dma_fence_get(job->done_fence);

View File

@@ -41,6 +41,17 @@ TRACE_EVENT(pvr_job_submit_ioctl,
__entry->count)
);
#define PVR_JOB_GET_HWRT_FW_ADDR(job) \
({ \
struct pvr_job *_job = (job); \
u32 _hwrt_fw_addr = 0; \
\
if (_job && _job->hwrt) \
pvr_fw_object_get_fw_addr(_job->hwrt->fw_obj, &_hwrt_fw_addr); \
\
_hwrt_fw_addr; \
})
#define PVR_JOB_TYPE_TO_STR(val) \
__print_symbolic(val, \
{ DRM_PVR_JOB_TYPE_GEOMETRY, "geometry" }, \
@@ -64,9 +75,7 @@ TRACE_EVENT(pvr_job_create,
__entry->ctx = job->ctx;
__entry->fw_obj = job->ctx->fw_obj;
pvr_fw_object_get_fw_addr(job->ctx->fw_obj, &__entry->fw_addr);
__entry->hwrt_addr = job->hwrt ?
job->hwrt->fw_obj->fw_addr_offset :
0;
__entry->hwrt_addr = PVR_JOB_GET_HWRT_FW_ADDR(job);
__entry->job = job;
__entry->job_type = job->type;
__entry->sync_op_count = sync_op_count;),
@@ -82,6 +91,7 @@ TRACE_EVENT(pvr_job_create,
);
#undef PVR_JOB_TYPE_TO_STR
#undef PVR_JOB_GET_HWRT_FW_ADDR
TRACE_EVENT(pvr_job_submit_fw,
TP_PROTO(struct pvr_job *job),

View File

@@ -545,6 +545,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
struct panthor_fw_binary_section_entry_hdr hdr;
struct panthor_fw_section *section;
u32 section_size;
u32 data_size;
u32 name_len;
int ret;
@@ -595,6 +596,13 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
return -EINVAL;
}
section_size = hdr.va.end - hdr.va.start;
data_size = hdr.data.end - hdr.data.start;
if (data_size > section_size) {
drm_err(&ptdev->base, "Firmware corrupted, section data exceeds section size\n");
return -EINVAL;
}
name_len = iter->size - iter->offset;
section = drmm_kzalloc(&ptdev->base, sizeof(*section), GFP_KERNEL);
@@ -603,7 +611,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
list_add_tail(&section->node, &ptdev->fw->sections);
section->flags = hdr.flags;
section->data.size = hdr.data.end - hdr.data.start;
section->data.size = data_size;
if (section->data.size > 0) {
void *data = drmm_kmalloc(&ptdev->base, section->data.size, GFP_KERNEL);
@@ -626,7 +634,6 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
section->name = name;
}
section_size = hdr.va.end - hdr.va.start;
if (section_size) {
u32 cache_mode = hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_MASK;
struct panthor_gem_object *bo;
@@ -857,18 +864,24 @@ static int panthor_fw_load(struct panthor_device *ptdev)
* iface_fw_to_cpu_addr() - Turn an MCU address into a CPU address
* @ptdev: Device.
* @mcu_va: MCU address.
* @size: Size of the object pointed to by @mcu_va.
*
* Return: NULL if the address is not part of the shared section, non-NULL otherwise.
* Return: NULL if the object is not part of the shared section, non-NULL otherwise.
*/
static void *iface_fw_to_cpu_addr(struct panthor_device *ptdev, u32 mcu_va)
static void *iface_fw_to_cpu_addr(struct panthor_device *ptdev, u32 mcu_va, size_t size)
{
u64 shared_mem_start = panthor_kernel_bo_gpuva(ptdev->fw->shared_section->mem);
u64 shared_mem_end = shared_mem_start +
panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
if (mcu_va < shared_mem_start || mcu_va >= shared_mem_end)
size_t shared_mem_size = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
u64 offset;
if (mcu_va < shared_mem_start)
return NULL;
return ptdev->fw->shared_section->mem->kmap + (mcu_va - shared_mem_start);
offset = mcu_va - shared_mem_start;
if (offset > shared_mem_size || size > shared_mem_size - offset)
return NULL;
return ptdev->fw->shared_section->mem->kmap + offset;
}
static int panthor_init_cs_iface(struct panthor_device *ptdev,
@@ -890,8 +903,10 @@ static int panthor_init_cs_iface(struct panthor_device *ptdev,
spin_lock_init(&cs_iface->lock);
cs_iface->control = ptdev->fw->shared_section->mem->kmap + iface_offset;
cs_iface->input = iface_fw_to_cpu_addr(ptdev, cs_iface->control->input_va);
cs_iface->output = iface_fw_to_cpu_addr(ptdev, cs_iface->control->output_va);
cs_iface->input = iface_fw_to_cpu_addr(ptdev, cs_iface->control->input_va,
sizeof(*cs_iface->input));
cs_iface->output = iface_fw_to_cpu_addr(ptdev, cs_iface->control->output_va,
sizeof(*cs_iface->output));
if (!cs_iface->input || !cs_iface->output) {
drm_err(&ptdev->base, "Invalid stream control interface input/output VA");
@@ -941,8 +956,10 @@ static int panthor_init_csg_iface(struct panthor_device *ptdev,
spin_lock_init(&csg_iface->lock);
csg_iface->control = ptdev->fw->shared_section->mem->kmap + iface_offset;
csg_iface->input = iface_fw_to_cpu_addr(ptdev, csg_iface->control->input_va);
csg_iface->output = iface_fw_to_cpu_addr(ptdev, csg_iface->control->output_va);
csg_iface->input = iface_fw_to_cpu_addr(ptdev, csg_iface->control->input_va,
sizeof(*csg_iface->input));
csg_iface->output = iface_fw_to_cpu_addr(ptdev, csg_iface->control->output_va,
sizeof(*csg_iface->output));
if (csg_iface->control->stream_num < MIN_CS_PER_CSG ||
csg_iface->control->stream_num > MAX_CS_PER_CSG)
@@ -999,8 +1016,10 @@ static int panthor_fw_init_ifaces(struct panthor_device *ptdev)
return -EINVAL;
}
glb_iface->input = iface_fw_to_cpu_addr(ptdev, glb_iface->control->input_va);
glb_iface->output = iface_fw_to_cpu_addr(ptdev, glb_iface->control->output_va);
glb_iface->input = iface_fw_to_cpu_addr(ptdev, glb_iface->control->input_va,
sizeof(*glb_iface->input));
glb_iface->output = iface_fw_to_cpu_addr(ptdev, glb_iface->control->output_va,
sizeof(*glb_iface->output));
if (!glb_iface->input || !glb_iface->output) {
drm_err(&ptdev->base, "Invalid global control interface input/output VA");
return -EINVAL;

View File

@@ -104,7 +104,7 @@ vc4_overflow_mem_work(struct work_struct *work)
vc4->bin_alloc_overflow = BIT(bin_bo_slot);
V3D_WRITE(V3D_BPOA, bo->base.dma_addr + bin_bo_slot * vc4->bin_alloc_size);
V3D_WRITE(V3D_BPOS, bo->base.base.size);
V3D_WRITE(V3D_BPOS, vc4->bin_alloc_size);
V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM);
V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM);
spin_unlock_irqrestore(&vc4->job_lock, irqflags);

View File

@@ -385,6 +385,23 @@ validate_tile_binning_config(VALIDATE_ARGS)
return -EINVAL;
}
/* The tile state data array is 48 bytes per tile, and we put it at
* the start of a BO containing both it and the tile alloc.
*/
tile_state_size = 48 * tile_count;
/* Since the tile alloc array will follow us, align. */
tile_state_size = roundup(tile_state_size, 4096);
/* Reject configurations whose tile state would leave no room for
* the tile alloc pool that follows it in the slot.
*/
if (tile_state_size >= vc4->bin_alloc_size) {
DRM_DEBUG("Tile binning config of %dx%d too large\n",
exec->bin_tiles_x, exec->bin_tiles_y);
return -EINVAL;
}
bin_slot = vc4_v3d_get_bin_slot(vc4);
if (bin_slot < 0) {
if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {
@@ -400,13 +417,13 @@ validate_tile_binning_config(VALIDATE_ARGS)
exec->bin_slots |= BIT(bin_slot);
bin_addr = vc4->bin_bo->base.dma_addr + bin_slot * vc4->bin_alloc_size;
/* The tile state data array is 48 bytes per tile, and we put it at
* the start of a BO containing both it and the tile alloc.
*/
tile_state_size = 48 * tile_count;
exec->tile_alloc_offset = bin_addr + tile_state_size;
/* Since the tile alloc array will follow us, align. */
exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096);
/* The TSDA area must be zeroed out before use, otherwise the PTB might
* consume a stale tile state.
*/
memset(vc4->bin_bo->base.vaddr + bin_slot * vc4->bin_alloc_size, 0,
tile_state_size);
*(uint8_t *)(validated + 14) =
((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |

View File

@@ -547,14 +547,17 @@ int ttm_prime_fd_to_handle(struct ttm_object_file *tfile,
if (IS_ERR(dma_buf))
return PTR_ERR(dma_buf);
if (dma_buf->ops != &tdev->ops)
return -ENOSYS;
if (dma_buf->ops != &tdev->ops) {
ret = -ENOSYS;
goto out;
}
prime = (struct ttm_prime_object *) dma_buf->priv;
base = &prime->base;
*handle = base->handle;
ret = ttm_ref_object_add(tfile, base, NULL, false);
out:
dma_buf_put(dma_buf);
return ret;

View File

@@ -30,6 +30,7 @@
#include "vmwgfx_bo.h"
#include <linux/highmem.h>
#include <linux/overflow.h>
/*
* Template that implements find_first_diff() for a generic
@@ -463,19 +464,42 @@ static int vmw_external_bo_copy(struct vmw_bo *dst, u32 dst_offset,
container_of(dst->tbo.bdev, struct vmw_private, bdev);
size_t dst_size = dst->tbo.resource->size;
size_t src_size = src->tbo.resource->size;
size_t dst_end, src_end;
struct iosys_map dst_map = {0};
struct iosys_map src_map = {0};
bool dst_mapped = false;
bool src_mapped = false;
int ret, i;
int x_in_bytes;
u8 *vsrc;
u8 *vdst;
if (!height || !width_in_bytes)
return 0;
if (!dst_stride || !src_stride)
return -EINVAL;
if (dst_stride < width_in_bytes || src_stride < width_in_bytes)
return -EINVAL;
if (check_mul_overflow((size_t)dst_stride, (size_t)height - 1, &dst_end) ||
check_add_overflow(dst_end, (size_t)width_in_bytes, &dst_end) ||
check_add_overflow((size_t)dst_offset, dst_end, &dst_end) ||
dst_end > dst_size ||
check_mul_overflow((size_t)src_stride, (size_t)height - 1, &src_end) ||
check_add_overflow(src_end, (size_t)width_in_bytes, &src_end) ||
check_add_overflow((size_t)src_offset, src_end, &src_end) ||
src_end > src_size) {
drm_dbg_driver(&vmw->drm, "Out-of-bounds external BO copy\n");
return -EINVAL;
}
vsrc = map_external(src, &src_map);
if (!vsrc) {
drm_dbg_driver(&vmw->drm, "Wasn't able to map src\n");
ret = -ENOMEM;
goto out;
}
src_mapped = true;
vdst = map_external(dst, &dst_map);
if (!vdst) {
@@ -483,16 +507,13 @@ static int vmw_external_bo_copy(struct vmw_bo *dst, u32 dst_offset,
ret = -ENOMEM;
goto out;
}
dst_mapped = true;
vsrc += src_offset;
vdst += dst_offset;
if (src_stride == dst_stride) {
dst_size -= dst_offset;
src_size -= src_offset;
memcpy(vdst, vsrc,
min(dst_stride * height, min(dst_size, src_size)));
if (src_stride == dst_stride && width_in_bytes == dst_stride) {
memcpy(vdst, vsrc, dst_stride * (size_t)height);
} else {
WARN_ON(dst_stride < width_in_bytes);
for (i = 0; i < height; ++i) {
memcpy(vdst, vsrc, width_in_bytes);
vsrc += src_stride;
@@ -508,8 +529,10 @@ static int vmw_external_bo_copy(struct vmw_bo *dst, u32 dst_offset,
ret = 0;
out:
unmap_external(src, &src_map);
unmap_external(dst, &dst_map);
if (src_mapped)
unmap_external(src, &src_map);
if (dst_mapped)
unmap_external(dst, &dst_map);
return ret;
}

View File

@@ -432,6 +432,7 @@ vmw_cursor_mob_map(struct vmw_plane_state *vps)
u32 size = vmw_cursor_mob_size(vps->cursor.update_type,
vps->base.crtc_w, vps->base.crtc_h);
struct vmw_bo *vbo = vps->cursor.mob;
void *map;
if (!vbo)
return -EINVAL;
@@ -446,11 +447,15 @@ vmw_cursor_mob_map(struct vmw_plane_state *vps)
if (unlikely(ret != 0))
return -ENOMEM;
vmw_bo_map_and_cache(vbo);
map = vmw_bo_map_and_cache(vbo);
if (!map) {
vmw_bo_unmap(vbo);
ret = -ENOMEM;
}
ttm_bo_unreserve(&vbo->tbo);
return 0;
return ret;
}
/**
@@ -663,9 +668,15 @@ int vmw_cursor_plane_prepare_fb(struct drm_plane *plane,
!vmw_cursor_buffer_changed(vps, old_vps)) {
vps->cursor.update_type =
VMW_CURSOR_UPDATE_NONE;
} else {
vmw_cursor_mob_get(vcp, vps);
vmw_cursor_mob_map(vps);
} else if (vps->cursor.update_type ==
VMW_CURSOR_UPDATE_MOB &&
(vmw_cursor_mob_get(vcp, vps) ||
vmw_cursor_mob_map(vps))) {
/*
* Reset the cursor to avoid crashes later.
*/
vps->cursor.update_type =
VMW_CURSOR_UPDATE_NONE;
}
}
}
@@ -732,6 +743,34 @@ int vmw_cursor_plane_atomic_check(struct drm_plane *plane,
"surface not suitable for cursor\n");
return -EINVAL;
}
} else if (update_type == VMW_CURSOR_UPDATE_GB_ONLY ||
update_type == VMW_CURSOR_UPDATE_MOB) {
u32 cursor_max_dim =
vmw_read(vmw, SVGA_REG_CURSOR_MAX_DIMENSION);
if (new_state->crtc_w > cursor_max_dim ||
new_state->crtc_h > cursor_max_dim) {
drm_warn(&vmw->drm,
"Cursor dimensions (%d, %d) exceed device max %u\n",
new_state->crtc_w, new_state->crtc_h,
cursor_max_dim);
return -EINVAL;
}
if (update_type == VMW_CURSOR_UPDATE_MOB) {
u32 mob_max_size =
vmw_read(vmw, SVGA_REG_MOB_MAX_SIZE);
u64 mob_size = (u64)new_state->crtc_w *
new_state->crtc_h * sizeof(u32) +
sizeof(SVGAGBCursorHeader);
if (mob_size > mob_max_size) {
drm_warn(&vmw->drm,
"Cursor MOB size %llu exceeds device max %u\n",
mob_size, mob_max_size);
return -EINVAL;
}
}
}
return 0;

View File

@@ -1272,9 +1272,13 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
SVGA3dCmdHeader *header)
{
VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXBindQuery);
struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
struct vmw_bo *vmw_bo;
int ret;
if (!ctx_node)
return -EINVAL;
cmd = container_of(header, typeof(*cmd), header);
/*
@@ -1288,7 +1292,7 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
return ret;
sw_context->dx_query_mob = vmw_bo;
sw_context->dx_query_ctx = sw_context->dx_ctx_node->ctx;
sw_context->dx_query_ctx = ctx_node->ctx;
return 0;
}
@@ -1506,6 +1510,12 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
bool dirty;
cmd = container_of(header, typeof(*cmd), header);
if (unlikely(header->size < sizeof(cmd->body) + sizeof(*suffix))) {
VMW_DEBUG_USER("Illegal SVGA_3D_CMD_SURFACE_DMA size.\n");
return -EINVAL;
}
suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->body +
header->size - sizeof(*suffix));
@@ -1567,11 +1577,17 @@ static int vmw_cmd_draw(struct vmw_private *dev_priv,
uint32_t maxnum;
int ret;
cmd = container_of(header, typeof(*cmd), header);
if (unlikely(header->size < sizeof(cmd->body))) {
VMW_DEBUG_USER("Illegal DRAW_PRIMITIVES header size.\n");
return -EINVAL;
}
ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
if (unlikely(ret != 0))
return ret;
cmd = container_of(header, typeof(*cmd), header);
maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);
if (unlikely(cmd->body.numVertexDecls > maxnum)) {

View File

@@ -367,13 +367,24 @@ void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
ret = vmw_fence_obj_wait(fence, false, false,
VMW_FENCE_WAIT_TIMEOUT);
spin_lock(&fman->lock);
if (unlikely(ret != 0)) {
bool cookie = dma_fence_begin_signalling();
list_del_init(&fence->head);
dma_fence_signal(&fence->base);
if (fence->waiter_added) {
vmw_seqno_waiter_remove(fman->dev_priv);
fence->waiter_added = false;
}
dma_fence_signal_locked(&fence->base);
dma_fence_end_signalling(cookie);
}
BUG_ON(!list_empty(&fence->head));
spin_unlock(&fman->lock);
dma_fence_put(&fence->base);
spin_lock(&fman->lock);
}
spin_unlock(&fman->lock);

View File

@@ -311,7 +311,7 @@ void vmw_bo_dirty_transfer_to_res(struct vmw_resource *res)
return;
cur = max(res_start, dirty->start);
res_end = max(res_end, dirty->end);
res_end = min(res_end, dirty->end);
while (cur < res_end) {
unsigned long num;
@@ -347,7 +347,7 @@ void vmw_bo_dirty_clear(struct vmw_bo *vbo)
return;
cur = max(res_start, dirty->start);
res_end = max(res_end, dirty->end);
res_end = min(res_end, dirty->end);
while (cur < res_end) {
unsigned long num;

View File

@@ -136,7 +136,7 @@ static void vmw_resource_release(struct kref *kref)
val_buf.num_shared = 0;
res->func->unbind(res, false, &val_buf);
}
res->guest_memory_size = false;
res->guest_memory_dirty = false;
vmw_resource_mob_detach(res);
if (res->dirty)
res->func->dirty_free(res);
@@ -773,7 +773,7 @@ void vmw_resource_unbind_list(struct vmw_bo *vbo)
if (!WARN_ON_ONCE(!res->func->unbind))
(void) res->func->unbind(res, res->res_dirty, &val_buf);
res->guest_memory_size = true;
res->guest_memory_dirty = true;
res->res_dirty = false;
vmw_resource_mob_detach(res);
}

View File

@@ -25,6 +25,8 @@
*
**************************************************************************/
#include <linux/overflow.h>
#include <drm/ttm/ttm_placement.h>
#include "vmwgfx_binding.h"
@@ -685,7 +687,7 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
struct vmw_bo *buffer,
size_t shader_size,
size_t offset,
u64 offset,
SVGA3dShaderType shader_type,
uint8_t num_input_sig,
uint8_t num_output_sig,
@@ -739,7 +741,7 @@ static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
struct vmw_bo *buffer,
size_t shader_size,
size_t offset,
u64 offset,
SVGA3dShaderType shader_type)
{
struct vmw_shader *shader;
@@ -768,7 +770,7 @@ static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
enum drm_vmw_shader_type shader_type_drm,
u32 buffer_handle, size_t size, size_t offset,
u32 buffer_handle, size_t size, u64 offset,
uint8_t num_input_sig, uint8_t num_output_sig,
uint32_t *shader_handle)
{
@@ -779,13 +781,16 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
int ret;
if (buffer_handle != SVGA3D_INVALID_ID) {
u64 end;
ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer);
if (unlikely(ret != 0)) {
VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
return ret;
}
if ((u64)buffer->tbo.base.size < (u64)size + (u64)offset) {
if (check_add_overflow((u64)size, (u64)offset, &end) ||
end > buffer->tbo.base.size) {
VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
ret = -EINVAL;
goto out_bad_arg;

View File

@@ -309,7 +309,8 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
}
node->res = vmw_resource_reference_unless_doomed(res);
if (!node->res) {
hash_del_rcu(&node->hash.head);
if (ctx->sw_context)
hash_del_rcu(&node->hash.head);
return -ESRCH;
}

View File

@@ -206,14 +206,14 @@ vmw_vkms_init(struct vmw_private *vmw)
vmw->vkms_enabled = false;
ret = vmw_host_get_guestinfo(GUESTINFO_VBLANK, buffer, &buf_len);
if (ret || buf_len > max_buf_len)
return;
buffer[buf_len] = '\0';
if (!ret && buf_len <= max_buf_len) {
buffer[buf_len] = '\0';
ret = kstrtobool(buffer, &vmw->vkms_enabled);
if (!ret && vmw->vkms_enabled) {
ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS);
vmw->vkms_enabled = (ret == 0);
ret = kstrtobool(buffer, &vmw->vkms_enabled);
if (!ret && vmw->vkms_enabled) {
ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS);
vmw->vkms_enabled = (ret == 0);
}
}
vmw->crc_workq = alloc_ordered_workqueue("vmwgfx_crc_generator", 0);
@@ -228,7 +228,8 @@ vmw_vkms_init(struct vmw_private *vmw)
void
vmw_vkms_cleanup(struct vmw_private *vmw)
{
destroy_workqueue(vmw->crc_workq);
if (vmw->crc_workq)
destroy_workqueue(vmw->crc_workq);
}
bool