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

drm-misc-fixes for v6.16-rc6 or final:
- Fix nouveau fail on debugfs errors.
- Magic 50 ms to fix nouveau suspend.
- Call rust destructor on drm device release.
- Fix DMA api error handling in tegra/nvdec.
- Fix PVR device reset.
- Habanalabs maintainer update.
- Small memory leak fix when nouveau acpi init fails.
- Do not attempt to bind to any PCI device with AGP capability.
- Make FB's acquire handles on backing object, same as i915/xe already does.
- Fix race in drm_gem_handle_create_tail.

Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/e522cdc7-1787-48f2-97e5-0f94783970ab@linux.intel.com
This commit is contained in:
Simona Vetter 2025-07-11 14:11:18 +02:00
commit b7dc79a633
17 changed files with 130 additions and 62 deletions

View File

@ -10504,7 +10504,7 @@ S: Maintained
F: block/partitions/efi.*
HABANALABS PCI DRIVER
M: Ofir Bitton <obitton@habana.ai>
M: Yaron Avizrat <yaron.avizrat@intel.com>
L: dri-devel@lists.freedesktop.org
S: Supported
C: irc://irc.oftc.net/dri-devel

View File

@ -720,11 +720,6 @@ static const struct pci_device_id agp_amd64_pci_table[] = {
MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table);
static const struct pci_device_id agp_amd64_pci_promisc_table[] = {
{ PCI_DEVICE_CLASS(0, 0) },
{ }
};
static DEFINE_SIMPLE_DEV_PM_OPS(agp_amd64_pm_ops, NULL, agp_amd64_resume);
static struct pci_driver agp_amd64_pci_driver = {
@ -739,6 +734,7 @@ static struct pci_driver agp_amd64_pci_driver = {
/* Not static due to IOMMU code calling it early. */
int __init agp_amd64_init(void)
{
struct pci_dev *pdev = NULL;
int err = 0;
if (agp_off)
@ -767,9 +763,13 @@ int __init agp_amd64_init(void)
}
/* Look for any AGP bridge */
agp_amd64_pci_driver.id_table = agp_amd64_pci_promisc_table;
err = driver_attach(&agp_amd64_pci_driver.driver);
if (err == 0 && agp_bridges_found == 0) {
for_each_pci_dev(pdev)
if (pci_find_capability(pdev, PCI_CAP_ID_AGP))
pci_add_dynid(&agp_amd64_pci_driver,
pdev->vendor, pdev->device,
pdev->subsystem_vendor,
pdev->subsystem_device, 0, 0, 0);
if (agp_bridges_found == 0) {
pci_unregister_driver(&agp_amd64_pci_driver);
err = -ENODEV;
}

View File

@ -862,11 +862,23 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
const struct drm_framebuffer_funcs *funcs)
{
unsigned int i;
int ret;
bool exists;
if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
return -EINVAL;
for (i = 0; i < fb->format->num_planes; i++) {
if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)))
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
if (fb->obj[i]) {
exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
if (exists)
fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
}
}
INIT_LIST_HEAD(&fb->filp_head);
fb->funcs = funcs;
@ -875,7 +887,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
false, drm_framebuffer_free);
if (ret)
goto out;
goto err;
mutex_lock(&dev->mode_config.fb_lock);
dev->mode_config.num_fb++;
@ -883,7 +895,16 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
mutex_unlock(&dev->mode_config.fb_lock);
drm_mode_object_register(dev, &fb->base);
out:
return 0;
err:
for (i = 0; i < fb->format->num_planes; i++) {
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) {
drm_gem_object_handle_put_unlocked(fb->obj[i]);
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
}
}
return ret;
}
EXPORT_SYMBOL(drm_framebuffer_init);
@ -960,6 +981,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
{
struct drm_device *dev = fb->dev;
unsigned int i;
for (i = 0; i < fb->format->num_planes; i++) {
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))
drm_gem_object_handle_put_unlocked(fb->obj[i]);
}
mutex_lock(&dev->mode_config.fb_lock);
list_del(&fb->head);

View File

@ -223,23 +223,34 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
}
/**
* drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
* drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
* @obj: GEM object
*
* Acquires a reference on the GEM buffer object's handle. Required
* to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
* to release the reference.
* Acquires a reference on the GEM buffer object's handle. Required to keep
* the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
* to release the reference. Does nothing if the buffer object has no handle.
*
* Returns:
* True if a handle exists, or false otherwise
*/
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
guard(mutex)(&dev->object_name_lock);
drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
/*
* First ref taken during GEM object creation, if any. Some
* drivers set up internal framebuffers with GEM objects that
* do not have a GEM handle. Hence, this counter can be zero.
*/
if (!obj->handle_count)
return false;
drm_gem_object_handle_get(obj);
return true;
}
EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
/**
* drm_gem_object_handle_free - release resources bound to userspace handles
@ -272,7 +283,7 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
}
/**
* drm_gem_object_handle_put_unlocked - releases reference on user-space handles
* drm_gem_object_handle_put_unlocked - releases reference on user-space handle
* @obj: GEM object
*
* Releases a reference on the GEM buffer object's handle. Possibly releases
@ -283,14 +294,14 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
struct drm_device *dev = obj->dev;
bool final = false;
if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
return;
/*
* Must bump handle count first as this may be the last
* ref, in which case the object would disappear before we
* checked for a name
*/
* Must bump handle count first as this may be the last
* ref, in which case the object would disappear before
* we checked for a name.
*/
mutex_lock(&dev->object_name_lock);
if (--obj->handle_count == 0) {
@ -303,7 +314,6 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
if (final)
drm_gem_object_put(obj);
}
EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
/*
* Called at device or object close to release the file's
@ -315,6 +325,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
struct drm_file *file_priv = data;
struct drm_gem_object *obj = ptr;
if (drm_WARN_ON(obj->dev, !data))
return 0;
if (obj->funcs->close)
obj->funcs->close(obj, file_priv);
@ -435,7 +448,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
idr_preload(GFP_KERNEL);
spin_lock(&file_priv->table_lock);
ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
ret = idr_alloc(&file_priv->object_idr, NULL, 1, 0, GFP_NOWAIT);
spin_unlock(&file_priv->table_lock);
idr_preload_end();
@ -456,6 +469,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
goto err_revoke;
}
/* mirrors drm_gem_handle_delete to avoid races */
spin_lock(&file_priv->table_lock);
obj = idr_replace(&file_priv->object_idr, obj, handle);
WARN_ON(obj != NULL);
spin_unlock(&file_priv->table_lock);
*handlep = handle;
return 0;

View File

@ -99,7 +99,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
unsigned int i;
for (i = 0; i < fb->format->num_planes; i++)
drm_gem_object_handle_put_unlocked(fb->obj[i]);
drm_gem_object_put(fb->obj[i]);
drm_framebuffer_cleanup(fb);
kfree(fb);
@ -182,10 +182,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
if (!objs[i]) {
drm_dbg_kms(dev, "Failed to lookup GEM object\n");
ret = -ENOENT;
goto err_gem_object_handle_put_unlocked;
goto err_gem_object_put;
}
drm_gem_object_handle_get_unlocked(objs[i]);
drm_gem_object_put(objs[i]);
min_size = (height - 1) * mode_cmd->pitches[i]
+ drm_format_info_min_pitch(info, i, width)
@ -195,22 +193,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
drm_dbg_kms(dev,
"GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
objs[i]->size, min_size, i);
drm_gem_object_handle_put_unlocked(objs[i]);
drm_gem_object_put(objs[i]);
ret = -EINVAL;
goto err_gem_object_handle_put_unlocked;
goto err_gem_object_put;
}
}
ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
if (ret)
goto err_gem_object_handle_put_unlocked;
goto err_gem_object_put;
return 0;
err_gem_object_handle_put_unlocked:
err_gem_object_put:
while (i > 0) {
--i;
drm_gem_object_handle_put_unlocked(objs[i]);
drm_gem_object_put(objs[i]);
}
return ret;
}

View File

@ -161,7 +161,7 @@ void drm_sysfs_lease_event(struct drm_device *dev);
/* drm_gem.c */
int drm_gem_init(struct drm_device *dev);
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
int drm_gem_handle_create_tail(struct drm_file *file_priv,
struct drm_gem_object *obj,

View File

@ -27,7 +27,7 @@
//! * <https://github.com/erwanvivien/fast_qr>
//! * <https://github.com/bjguillot/qr>
use kernel::{prelude::*, str::CStr};
use kernel::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
struct Version(usize);

View File

@ -386,13 +386,13 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
if (!err) {
if (hard_reset) {
pvr_dev->fw_dev.booted = false;
WARN_ON(pm_runtime_force_suspend(from_pvr_device(pvr_dev)->dev));
WARN_ON(pvr_power_device_suspend(from_pvr_device(pvr_dev)->dev));
err = pvr_fw_hard_reset(pvr_dev);
if (err)
goto err_device_lost;
err = pm_runtime_force_resume(from_pvr_device(pvr_dev)->dev);
err = pvr_power_device_resume(from_pvr_device(pvr_dev)->dev);
pvr_dev->fw_dev.booted = true;
if (err)
goto err_device_lost;

View File

@ -314,14 +314,10 @@ nouveau_debugfs_fini(struct nouveau_drm *drm)
drm->debugfs = NULL;
}
int
void
nouveau_module_debugfs_init(void)
{
nouveau_debugfs_root = debugfs_create_dir("nouveau", NULL);
if (IS_ERR(nouveau_debugfs_root))
return PTR_ERR(nouveau_debugfs_root);
return 0;
}
void

View File

@ -24,7 +24,7 @@ extern void nouveau_debugfs_fini(struct nouveau_drm *);
extern struct dentry *nouveau_debugfs_root;
int nouveau_module_debugfs_init(void);
void nouveau_module_debugfs_init(void);
void nouveau_module_debugfs_fini(void);
#else
static inline void
@ -42,10 +42,9 @@ nouveau_debugfs_fini(struct nouveau_drm *drm)
{
}
static inline int
static inline void
nouveau_module_debugfs_init(void)
{
return 0;
}
static inline void

View File

@ -1461,9 +1461,7 @@ nouveau_drm_init(void)
if (!nouveau_modeset)
return 0;
ret = nouveau_module_debugfs_init();
if (ret)
return ret;
nouveau_module_debugfs_init();
#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
platform_driver_register(&nouveau_platform_driver);

View File

@ -719,7 +719,6 @@ r535_gsp_acpi_caps(acpi_handle handle, CAPS_METHOD_DATA *caps)
union acpi_object argv4 = {
.buffer.type = ACPI_TYPE_BUFFER,
.buffer.length = 4,
.buffer.pointer = kmalloc(argv4.buffer.length, GFP_KERNEL),
}, *obj;
caps->status = 0xffff;
@ -727,17 +726,22 @@ r535_gsp_acpi_caps(acpi_handle handle, CAPS_METHOD_DATA *caps)
if (!acpi_check_dsm(handle, &NVOP_DSM_GUID, NVOP_DSM_REV, BIT_ULL(0x1a)))
return;
argv4.buffer.pointer = kmalloc(argv4.buffer.length, GFP_KERNEL);
if (!argv4.buffer.pointer)
return;
obj = acpi_evaluate_dsm(handle, &NVOP_DSM_GUID, NVOP_DSM_REV, 0x1a, &argv4);
if (!obj)
return;
goto done;
if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
WARN_ON(obj->buffer.length != 4))
return;
goto done;
caps->status = 0;
caps->optimusCaps = *(u32 *)obj->buffer.pointer;
done:
ACPI_FREE(obj);
kfree(argv4.buffer.pointer);
@ -754,24 +758,28 @@ r535_gsp_acpi_jt(acpi_handle handle, JT_METHOD_DATA *jt)
union acpi_object argv4 = {
.buffer.type = ACPI_TYPE_BUFFER,
.buffer.length = sizeof(caps),
.buffer.pointer = kmalloc(argv4.buffer.length, GFP_KERNEL),
}, *obj;
jt->status = 0xffff;
argv4.buffer.pointer = kmalloc(argv4.buffer.length, GFP_KERNEL);
if (!argv4.buffer.pointer)
return;
obj = acpi_evaluate_dsm(handle, &JT_DSM_GUID, JT_DSM_REV, 0x1, &argv4);
if (!obj)
return;
goto done;
if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
WARN_ON(obj->buffer.length != 4))
return;
goto done;
jt->status = 0;
jt->jtCaps = *(u32 *)obj->buffer.pointer;
jt->jtRevId = (jt->jtCaps & 0xfff00000) >> 20;
jt->bSBIOSCaps = 0;
done:
ACPI_FREE(obj);
kfree(argv4.buffer.pointer);
@ -1744,6 +1752,13 @@ r535_gsp_fini(struct nvkm_gsp *gsp, bool suspend)
nvkm_gsp_sg_free(gsp->subdev.device, &gsp->sr.sgt);
return ret;
}
/*
* TODO: Debug the GSP firmware / RPC handling to find out why
* without this Turing (but none of the other architectures)
* ends up resetting all channels after resume.
*/
msleep(50);
}
ret = r535_gsp_rpc_unloading_guest_driver(gsp, suspend);

View File

@ -261,10 +261,8 @@ static int nvdec_load_falcon_firmware(struct nvdec *nvdec)
if (!client->group) {
virt = dma_alloc_coherent(nvdec->dev, size, &iova, GFP_KERNEL);
err = dma_mapping_error(nvdec->dev, iova);
if (err < 0)
return err;
if (!virt)
return -ENOMEM;
} else {
virt = tegra_drm_alloc(tegra, size, &iova);
if (IS_ERR(virt))

View File

@ -300,6 +300,9 @@ struct drm_file {
*
* Mapping of mm object handles to object pointers. Used by the GEM
* subsystem. Protected by @table_lock.
*
* Note that allocated entries might be NULL as a transient state when
* creating or deleting a handle.
*/
struct idr object_idr;

View File

@ -23,6 +23,7 @@
#ifndef __DRM_FRAMEBUFFER_H__
#define __DRM_FRAMEBUFFER_H__
#include <linux/bits.h>
#include <linux/ctype.h>
#include <linux/list.h>
#include <linux/sched.h>
@ -100,6 +101,8 @@ struct drm_framebuffer_funcs {
unsigned num_clips);
};
#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i) BIT(0u + (_i))
/**
* struct drm_framebuffer - frame buffer object
*
@ -188,6 +191,10 @@ struct drm_framebuffer {
* DRM_MODE_FB_MODIFIERS.
*/
int flags;
/**
* @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF.
*/
unsigned int internal_flags;
/**
* @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock.
*/

View File

@ -66,7 +66,7 @@ impl<T: drm::Driver> Device<T> {
open: Some(drm::File::<T::File>::open_callback),
postclose: Some(drm::File::<T::File>::postclose_callback),
unload: None,
release: None,
release: Some(Self::release),
master_set: None,
master_drop: None,
debugfs_init: None,
@ -162,6 +162,16 @@ impl<T: drm::Driver> Device<T> {
// SAFETY: `ptr` is valid by the safety requirements of this function.
unsafe { &*ptr.cast() }
}
extern "C" fn release(ptr: *mut bindings::drm_device) {
// SAFETY: `ptr` is a valid pointer to a `struct drm_device` and embedded in `Self`.
let this = unsafe { Self::from_drm_device(ptr) };
// SAFETY:
// - When `release` runs it is guaranteed that there is no further access to `this`.
// - `this` is valid for dropping.
unsafe { core::ptr::drop_in_place(this) };
}
}
impl<T: drm::Driver> Deref for Device<T> {

View File

@ -10,7 +10,6 @@ use crate::{
drm,
error::{to_result, Result},
prelude::*,
str::CStr,
types::ARef,
};
use macros::vtable;