Commit 75f53c4b authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-misc-fixes-2026-04-02' of...

Merge tag 'drm-misc-fixes-2026-04-02' of https://gitlab.freedesktop.org/drm/misc/kernel

 into drm-fixes

A refcounting fix for bridges, revert a previous framebuffer
use-after-free fix that turned out to be causing more problems, a hang
fix for qaic, an initialization fix for ast, a error handling fix for
sysfb, and a speculation fix for drm_compat_ioctl.

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

From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20260402-vivid-perfect-caiman-ca055e@houat
parents 293fa6eb f8995c2d
Loading
Loading
Loading
Loading
+45 −2
Original line number Diff line number Diff line
@@ -914,7 +914,7 @@ static int decode_deactivate(struct qaic_device *qdev, void *trans, u32 *msg_len
		 */
		return -ENODEV;

	if (status) {
	if (usr && status) {
		/*
		 * Releasing resources failed on the device side, which puts
		 * us in a bind since they may still be in use, so enable the
@@ -1109,6 +1109,9 @@ static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u
	mutex_lock(&qdev->cntl_mutex);
	if (!list_empty(&elem.list))
		list_del(&elem.list);
	/* resp_worker() processed the response but the wait was interrupted */
	else if (ret == -ERESTARTSYS)
		ret = 0;
	if (!ret && !elem.buf)
		ret = -ETIMEDOUT;
	else if (ret > 0 && !elem.buf)
@@ -1419,9 +1422,49 @@ static void resp_worker(struct work_struct *work)
	}
	mutex_unlock(&qdev->cntl_mutex);

	if (!found)
	if (!found) {
		/*
		 * The user might have gone away at this point without waiting
		 * for QAIC_TRANS_DEACTIVATE_FROM_DEV transaction coming from
		 * the device. If this is not handled correctly, the host will
		 * not know that the DBC[n] has been freed on the device.
		 * Due to this failure in synchronization between the device and
		 * the host, if another user requests to activate a network, and
		 * the device assigns DBC[n] again, save_dbc_buf() will hang,
		 * waiting for dbc[n]->in_use to be set to false, which will not
		 * happen unless the qaic_dev_reset_clean_local_state() gets
		 * called by resetting the device (or re-inserting the module).
		 *
		 * As a solution, we look for QAIC_TRANS_DEACTIVATE_FROM_DEV
		 * transactions in the message before disposing of it, then
		 * handle releasing the DBC resources.
		 *
		 * Since the user has gone away, if the device could not
		 * deactivate the network (status != 0), there is no way to
		 * enable and reassign the DBC to the user. We can put trust in
		 * the device that it will release all the active DBCs in
		 * response to the QAIC_TRANS_TERMINATE_TO_DEV transaction,
		 * otherwise, the user can issue an soc_reset to the device.
		 */
		u32 msg_count = le32_to_cpu(msg->hdr.count);
		u32 msg_len = le32_to_cpu(msg->hdr.len);
		u32 len = 0;
		int j;

		for (j = 0; j < msg_count && len < msg_len; ++j) {
			struct wire_trans_hdr *trans_hdr;

			trans_hdr = (struct wire_trans_hdr *)(msg->data + len);
			if (le32_to_cpu(trans_hdr->type) == QAIC_TRANS_DEACTIVATE_FROM_DEV) {
				if (decode_deactivate(qdev, trans_hdr, &len, NULL))
					len += le32_to_cpu(trans_hdr->len);
			} else {
				len += le32_to_cpu(trans_hdr->len);
			}
		}
		/* request must have timed out, drop packet */
		kfree(msg);
	}

	kfree(resp);
}
+1 −1
Original line number Diff line number Diff line
@@ -436,7 +436,7 @@ static void ast_init_analog(struct ast_device *ast)
	/* Finally, clear bits [17:16] of SCU2c */
	data = ast_read32(ast, 0x1202c);
	data &= 0xfffcffff;
	ast_write32(ast, 0, data);
	ast_write32(ast, 0x1202c, data);

	/* Disable DVO */
	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x00);
+11 −5
Original line number Diff line number Diff line
@@ -1569,11 +1569,17 @@ EXPORT_SYMBOL(devm_drm_put_bridge);
static void drm_bridge_debugfs_show_bridge(struct drm_printer *p,
					   struct drm_bridge *bridge,
					   unsigned int idx,
					   bool lingering)
					   bool lingering,
					   bool scoped)
{
	unsigned int refcount = kref_read(&bridge->refcount);

	if (scoped)
		refcount--;

	drm_printf(p, "bridge[%u]: %ps\n", idx, bridge->funcs);

	drm_printf(p, "\trefcount: %u%s\n", kref_read(&bridge->refcount),
	drm_printf(p, "\trefcount: %u%s\n", refcount,
		   lingering ? " [lingering]" : "");

	drm_printf(p, "\ttype: [%d] %s\n",
@@ -1607,10 +1613,10 @@ static int allbridges_show(struct seq_file *m, void *data)
	mutex_lock(&bridge_lock);

	list_for_each_entry(bridge, &bridge_list, list)
		drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false);
		drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, false);

	list_for_each_entry(bridge, &bridge_lingering_list, list)
		drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true);
		drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true, false);

	mutex_unlock(&bridge_lock);

@@ -1625,7 +1631,7 @@ static int encoder_bridges_show(struct seq_file *m, void *data)
	unsigned int idx = 0;

	drm_for_each_bridge_in_chain_scoped(encoder, bridge)
		drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false);
		drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, true);

	return 0;
}
+1 −4
Original line number Diff line number Diff line
@@ -233,7 +233,6 @@ static void drm_events_release(struct drm_file *file_priv)
void drm_file_free(struct drm_file *file)
{
	struct drm_device *dev;
	int idx;

	if (!file)
		return;
@@ -250,11 +249,9 @@ void drm_file_free(struct drm_file *file)

	drm_events_release(file);

	if (drm_core_check_feature(dev, DRIVER_MODESET) &&
	    drm_dev_enter(dev, &idx)) {
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		drm_fb_release(file);
		drm_property_destroy_user_blobs(dev, file);
		drm_dev_exit(idx);
	}

	if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
 * IN THE SOFTWARE.
 */
#include <linux/compat.h>
#include <linux/nospec.h>
#include <linux/ratelimit.h>
#include <linux/export.h>

@@ -374,6 +375,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
	if (nr >= ARRAY_SIZE(drm_compat_ioctls))
		return drm_ioctl(filp, cmd, arg);

	nr = array_index_nospec(nr, ARRAY_SIZE(drm_compat_ioctls));
	fn = drm_compat_ioctls[nr].fn;
	if (!fn)
		return drm_ioctl(filp, cmd, arg);
Loading