Skip to content

Commit 75f53c4

Browse files
committed
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: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <mripard@redhat.com> Link: https://patch.msgid.link/20260402-vivid-perfect-caiman-ca055e@houat
2 parents 293fa6e + f8995c2 commit 75f53c4

7 files changed

Lines changed: 94 additions & 33 deletions

File tree

drivers/accel/qaic/qaic_control.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ static int decode_deactivate(struct qaic_device *qdev, void *trans, u32 *msg_len
914914
*/
915915
return -ENODEV;
916916

917-
if (status) {
917+
if (usr && status) {
918918
/*
919919
* Releasing resources failed on the device side, which puts
920920
* 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
11091109
mutex_lock(&qdev->cntl_mutex);
11101110
if (!list_empty(&elem.list))
11111111
list_del(&elem.list);
1112+
/* resp_worker() processed the response but the wait was interrupted */
1113+
else if (ret == -ERESTARTSYS)
1114+
ret = 0;
11121115
if (!ret && !elem.buf)
11131116
ret = -ETIMEDOUT;
11141117
else if (ret > 0 && !elem.buf)
@@ -1419,9 +1422,49 @@ static void resp_worker(struct work_struct *work)
14191422
}
14201423
mutex_unlock(&qdev->cntl_mutex);
14211424

1422-
if (!found)
1425+
if (!found) {
1426+
/*
1427+
* The user might have gone away at this point without waiting
1428+
* for QAIC_TRANS_DEACTIVATE_FROM_DEV transaction coming from
1429+
* the device. If this is not handled correctly, the host will
1430+
* not know that the DBC[n] has been freed on the device.
1431+
* Due to this failure in synchronization between the device and
1432+
* the host, if another user requests to activate a network, and
1433+
* the device assigns DBC[n] again, save_dbc_buf() will hang,
1434+
* waiting for dbc[n]->in_use to be set to false, which will not
1435+
* happen unless the qaic_dev_reset_clean_local_state() gets
1436+
* called by resetting the device (or re-inserting the module).
1437+
*
1438+
* As a solution, we look for QAIC_TRANS_DEACTIVATE_FROM_DEV
1439+
* transactions in the message before disposing of it, then
1440+
* handle releasing the DBC resources.
1441+
*
1442+
* Since the user has gone away, if the device could not
1443+
* deactivate the network (status != 0), there is no way to
1444+
* enable and reassign the DBC to the user. We can put trust in
1445+
* the device that it will release all the active DBCs in
1446+
* response to the QAIC_TRANS_TERMINATE_TO_DEV transaction,
1447+
* otherwise, the user can issue an soc_reset to the device.
1448+
*/
1449+
u32 msg_count = le32_to_cpu(msg->hdr.count);
1450+
u32 msg_len = le32_to_cpu(msg->hdr.len);
1451+
u32 len = 0;
1452+
int j;
1453+
1454+
for (j = 0; j < msg_count && len < msg_len; ++j) {
1455+
struct wire_trans_hdr *trans_hdr;
1456+
1457+
trans_hdr = (struct wire_trans_hdr *)(msg->data + len);
1458+
if (le32_to_cpu(trans_hdr->type) == QAIC_TRANS_DEACTIVATE_FROM_DEV) {
1459+
if (decode_deactivate(qdev, trans_hdr, &len, NULL))
1460+
len += le32_to_cpu(trans_hdr->len);
1461+
} else {
1462+
len += le32_to_cpu(trans_hdr->len);
1463+
}
1464+
}
14231465
/* request must have timed out, drop packet */
14241466
kfree(msg);
1467+
}
14251468

14261469
kfree(resp);
14271470
}

drivers/gpu/drm/ast/ast_dp501.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ static void ast_init_analog(struct ast_device *ast)
436436
/* Finally, clear bits [17:16] of SCU2c */
437437
data = ast_read32(ast, 0x1202c);
438438
data &= 0xfffcffff;
439-
ast_write32(ast, 0, data);
439+
ast_write32(ast, 0x1202c, data);
440440

441441
/* Disable DVO */
442442
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x00);

drivers/gpu/drm/drm_bridge.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,11 +1569,17 @@ EXPORT_SYMBOL(devm_drm_put_bridge);
15691569
static void drm_bridge_debugfs_show_bridge(struct drm_printer *p,
15701570
struct drm_bridge *bridge,
15711571
unsigned int idx,
1572-
bool lingering)
1572+
bool lingering,
1573+
bool scoped)
15731574
{
1575+
unsigned int refcount = kref_read(&bridge->refcount);
1576+
1577+
if (scoped)
1578+
refcount--;
1579+
15741580
drm_printf(p, "bridge[%u]: %ps\n", idx, bridge->funcs);
15751581

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

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

16091615
list_for_each_entry(bridge, &bridge_list, list)
1610-
drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false);
1616+
drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, false);
16111617

16121618
list_for_each_entry(bridge, &bridge_lingering_list, list)
1613-
drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true);
1619+
drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true, false);
16141620

16151621
mutex_unlock(&bridge_lock);
16161622

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

16271633
drm_for_each_bridge_in_chain_scoped(encoder, bridge)
1628-
drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false);
1634+
drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, true);
16291635

16301636
return 0;
16311637
}

drivers/gpu/drm/drm_file.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ static void drm_events_release(struct drm_file *file_priv)
233233
void drm_file_free(struct drm_file *file)
234234
{
235235
struct drm_device *dev;
236-
int idx;
237236

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

251250
drm_events_release(file);
252251

253-
if (drm_core_check_feature(dev, DRIVER_MODESET) &&
254-
drm_dev_enter(dev, &idx)) {
252+
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
255253
drm_fb_release(file);
256254
drm_property_destroy_user_blobs(dev, file);
257-
drm_dev_exit(idx);
258255
}
259256

260257
if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))

drivers/gpu/drm/drm_ioc32.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* IN THE SOFTWARE.
2929
*/
3030
#include <linux/compat.h>
31+
#include <linux/nospec.h>
3132
#include <linux/ratelimit.h>
3233
#include <linux/export.h>
3334

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

378+
nr = array_index_nospec(nr, ARRAY_SIZE(drm_compat_ioctls));
377379
fn = drm_compat_ioctls[nr].fn;
378380
if (!fn)
379381
return drm_ioctl(filp, cmd, arg);

drivers/gpu/drm/drm_mode_config.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -577,13 +577,10 @@ void drm_mode_config_cleanup(struct drm_device *dev)
577577
*/
578578
WARN_ON(!list_empty(&dev->mode_config.fb_list));
579579
list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
580-
if (list_empty(&fb->filp_head) || drm_framebuffer_read_refcount(fb) > 1) {
581-
struct drm_printer p = drm_dbg_printer(dev, DRM_UT_KMS, "[leaked fb]");
580+
struct drm_printer p = drm_dbg_printer(dev, DRM_UT_KMS, "[leaked fb]");
582581

583-
drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
584-
drm_framebuffer_print_info(&p, 1, fb);
585-
}
586-
list_del_init(&fb->filp_head);
582+
drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
583+
drm_framebuffer_print_info(&p, 1, fb);
587584
drm_framebuffer_free(&fb->base.refcount);
588585
}
589586

drivers/gpu/drm/sysfb/efidrm.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
151151
struct drm_sysfb_device *sysfb;
152152
struct drm_device *dev;
153153
struct resource *mem = NULL;
154-
void __iomem *screen_base = NULL;
155154
struct drm_plane *primary_plane;
156155
struct drm_crtc *crtc;
157156
struct drm_encoder *encoder;
@@ -238,21 +237,38 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
238237

239238
mem_flags = efidrm_get_mem_flags(dev, res->start, vsize);
240239

241-
if (mem_flags & EFI_MEMORY_WC)
242-
screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem));
243-
else if (mem_flags & EFI_MEMORY_UC)
244-
screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
245-
else if (mem_flags & EFI_MEMORY_WT)
246-
screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem),
247-
MEMREMAP_WT);
248-
else if (mem_flags & EFI_MEMORY_WB)
249-
screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem),
250-
MEMREMAP_WB);
251-
else
240+
if (mem_flags & EFI_MEMORY_WC) {
241+
void __iomem *screen_base = devm_ioremap_wc(&pdev->dev, mem->start,
242+
resource_size(mem));
243+
244+
if (!screen_base)
245+
return ERR_PTR(-ENXIO);
246+
iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
247+
} else if (mem_flags & EFI_MEMORY_UC) {
248+
void __iomem *screen_base = devm_ioremap(&pdev->dev, mem->start,
249+
resource_size(mem));
250+
251+
if (!screen_base)
252+
return ERR_PTR(-ENXIO);
253+
iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
254+
} else if (mem_flags & EFI_MEMORY_WT) {
255+
void *screen_base = devm_memremap(&pdev->dev, mem->start,
256+
resource_size(mem), MEMREMAP_WT);
257+
258+
if (IS_ERR(screen_base))
259+
return ERR_CAST(screen_base);
260+
iosys_map_set_vaddr(&sysfb->fb_addr, screen_base);
261+
} else if (mem_flags & EFI_MEMORY_WB) {
262+
void *screen_base = devm_memremap(&pdev->dev, mem->start,
263+
resource_size(mem), MEMREMAP_WB);
264+
265+
if (IS_ERR(screen_base))
266+
return ERR_CAST(screen_base);
267+
iosys_map_set_vaddr(&sysfb->fb_addr, screen_base);
268+
} else {
252269
drm_err(dev, "invalid mem_flags: 0x%llx\n", mem_flags);
253-
if (!screen_base)
254-
return ERR_PTR(-ENOMEM);
255-
iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
270+
return ERR_PTR(-EINVAL);
271+
}
256272

257273
/*
258274
* Modesetting

0 commit comments

Comments
 (0)