mirror of
https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
synced 2025-09-27 11:09:04 +10:00
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:
commit
b7dc79a633
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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> {
|
||||
|
@ -10,7 +10,6 @@ use crate::{
|
||||
drm,
|
||||
error::{to_result, Result},
|
||||
prelude::*,
|
||||
str::CStr,
|
||||
types::ARef,
|
||||
};
|
||||
use macros::vtable;
|
||||
|
Loading…
Reference in New Issue
Block a user