mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 10:00:03 -04:00
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:
@@ -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;
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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(§ion->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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user