157 lines
3.2 KiB
C
157 lines
3.2 KiB
C
/* Public domain. */
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
#include <linux/list.h>
|
|
|
|
#include <drm/drm_device.h>
|
|
#include <drm/drm_managed.h>
|
|
|
|
struct drmm_node {
|
|
void *p;
|
|
size_t size;
|
|
drmm_func_t func;
|
|
struct list_head list;
|
|
};
|
|
|
|
void *
|
|
drmm_kzalloc(struct drm_device *dev, size_t size, int flags)
|
|
{
|
|
void *p;
|
|
struct drmm_node *node = malloc(sizeof(*node), M_DRM, flags | M_ZERO);
|
|
if (node == NULL)
|
|
return NULL;
|
|
p = kzalloc(size, flags);
|
|
if (p == NULL) {
|
|
free(node, M_DRM, sizeof(*node));
|
|
return NULL;
|
|
}
|
|
INIT_LIST_HEAD(&node->list);
|
|
node->p = p;
|
|
node->size = size;
|
|
mtx_enter(&dev->managed.lock);
|
|
list_add(&node->list, &dev->managed.resources);
|
|
mtx_leave(&dev->managed.lock);
|
|
return p;
|
|
}
|
|
|
|
void *
|
|
drmm_kcalloc(struct drm_device *dev, size_t n, size_t size, int flags)
|
|
{
|
|
void *p;
|
|
struct drmm_node *node = malloc(sizeof(*node), M_DRM, flags | M_ZERO);
|
|
if (node == NULL)
|
|
return NULL;
|
|
p = kcalloc(n, size, flags);
|
|
if (p == NULL) {
|
|
free(node, M_DRM, sizeof(*node));
|
|
return NULL;
|
|
}
|
|
INIT_LIST_HEAD(&node->list);
|
|
node->p = p;
|
|
node->size = n * size;
|
|
mtx_enter(&dev->managed.lock);
|
|
list_add(&node->list, &dev->managed.resources);
|
|
mtx_leave(&dev->managed.lock);
|
|
return p;
|
|
}
|
|
|
|
char *
|
|
drmm_kstrdup(struct drm_device *dev, const char *s, int flags)
|
|
{
|
|
char *p;
|
|
struct drmm_node *node = malloc(sizeof(*node), M_DRM, flags | M_ZERO);
|
|
if (node == NULL)
|
|
return NULL;
|
|
p = kstrdup(s, flags);
|
|
if (p == NULL) {
|
|
free(node, M_DRM, sizeof(*node));
|
|
return NULL;
|
|
}
|
|
INIT_LIST_HEAD(&node->list);
|
|
node->p = p;
|
|
node->size = strlen(s) + 1;
|
|
mtx_enter(&dev->managed.lock);
|
|
list_add(&node->list, &dev->managed.resources);
|
|
mtx_leave(&dev->managed.lock);
|
|
return p;
|
|
}
|
|
|
|
void
|
|
drmm_kfree(struct drm_device *dev, void *p)
|
|
{
|
|
struct drmm_node *n, *m = NULL;
|
|
|
|
if (p == NULL)
|
|
return;
|
|
|
|
mtx_enter(&dev->managed.lock);
|
|
list_for_each_entry(n, &dev->managed.resources, list) {
|
|
if (n->p == p) {
|
|
list_del(&n->list);
|
|
m = n;
|
|
break;
|
|
}
|
|
}
|
|
mtx_leave(&dev->managed.lock);
|
|
|
|
if (m != NULL) {
|
|
free(m->p, M_DRM, m->size);
|
|
free(m, M_DRM, sizeof(*m));
|
|
}
|
|
}
|
|
|
|
int
|
|
drmm_add_action(struct drm_device *dev, drmm_func_t f, void *cookie)
|
|
{
|
|
struct drmm_node *node = malloc(sizeof(*node), M_DRM, M_WAITOK | M_ZERO);
|
|
if (node == NULL)
|
|
return -ENOMEM;
|
|
INIT_LIST_HEAD(&node->list);
|
|
node->func = f;
|
|
node->p = cookie;
|
|
mtx_enter(&dev->managed.lock);
|
|
list_add(&node->list, &dev->managed.resources);
|
|
mtx_leave(&dev->managed.lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
drmm_add_action_or_reset(struct drm_device *dev, drmm_func_t f, void *cookie)
|
|
{
|
|
struct drmm_node *node = malloc(sizeof(*node), M_DRM, M_WAITOK | M_ZERO);
|
|
if (node == NULL) {
|
|
f(dev, cookie);
|
|
return -ENOMEM;
|
|
}
|
|
INIT_LIST_HEAD(&node->list);
|
|
node->func = f;
|
|
node->p = cookie;
|
|
mtx_enter(&dev->managed.lock);
|
|
list_add(&node->list, &dev->managed.resources);
|
|
mtx_leave(&dev->managed.lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
drm_managed_release(struct drm_device *dev)
|
|
{
|
|
struct drmm_node *n, *t;
|
|
list_for_each_entry_safe(n, t, &dev->managed.resources, list) {
|
|
list_del(&n->list);
|
|
if (n->func)
|
|
n->func(dev, n->p);
|
|
else
|
|
free(n->p, M_DRM, n->size);
|
|
free(n, M_DRM, sizeof(*n));
|
|
}
|
|
}
|
|
|
|
void
|
|
drmm_add_final_kfree(struct drm_device *dev, void *p)
|
|
{
|
|
dev->managed.final_kfree = p;
|
|
}
|