xref: /openbsd/sys/dev/pci/drm/drm_managed.c (revision ad8b1aaf)
1 /* Public domain. */
2 
3 #include <linux/kernel.h>
4 #include <linux/slab.h>
5 #include <linux/string.h>
6 #include <linux/list.h>
7 
8 #include <drm/drm_device.h>
9 #include <drm/drm_managed.h>
10 
11 struct drmm_node {
12 	void *p;
13 	size_t size;
14 	drmm_func_t func;
15 	struct list_head list;
16 };
17 
18 void *
drmm_kzalloc(struct drm_device * dev,size_t size,int flags)19 drmm_kzalloc(struct drm_device *dev, size_t size, int flags)
20 {
21 	void *p;
22 	struct drmm_node *node = malloc(sizeof(*node), M_DRM, flags | M_ZERO);
23 	if (node == NULL)
24 		return NULL;
25 	p = kzalloc(size, flags);
26 	if (p == NULL) {
27 		free(node, M_DRM, sizeof(*node));
28 		return NULL;
29 	}
30 	INIT_LIST_HEAD(&node->list);
31 	node->p = p;
32 	node->size = size;
33 	mtx_enter(&dev->managed.lock);
34 	list_add(&node->list, &dev->managed.resources);
35 	mtx_leave(&dev->managed.lock);
36 	return p;
37 }
38 
39 void *
drmm_kcalloc(struct drm_device * dev,size_t n,size_t size,int flags)40 drmm_kcalloc(struct drm_device *dev, size_t n, size_t size, int flags)
41 {
42 	void *p;
43 	struct drmm_node *node = malloc(sizeof(*node), M_DRM, flags | M_ZERO);
44 	if (node == NULL)
45 		return NULL;
46 	p = kcalloc(n, size, flags);
47 	if (p == NULL) {
48 		free(node, M_DRM, sizeof(*node));
49 		return NULL;
50 	}
51 	INIT_LIST_HEAD(&node->list);
52 	node->p = p;
53 	node->size = n * size;
54 	mtx_enter(&dev->managed.lock);
55 	list_add(&node->list, &dev->managed.resources);
56 	mtx_leave(&dev->managed.lock);
57 	return p;
58 }
59 
60 char *
drmm_kstrdup(struct drm_device * dev,const char * s,int flags)61 drmm_kstrdup(struct drm_device *dev, const char *s, int flags)
62 {
63 	char *p;
64 	struct drmm_node *node = malloc(sizeof(*node), M_DRM, flags | M_ZERO);
65 	if (node == NULL)
66 		return NULL;
67 	p = kstrdup(s, flags);
68 	if (p == NULL) {
69 		free(node, M_DRM, sizeof(*node));
70 		return NULL;
71 	}
72 	INIT_LIST_HEAD(&node->list);
73 	node->p = p;
74 	node->size = strlen(s) + 1;
75 	mtx_enter(&dev->managed.lock);
76 	list_add(&node->list, &dev->managed.resources);
77 	mtx_leave(&dev->managed.lock);
78 	return p;
79 }
80 
81 void
drmm_kfree(struct drm_device * dev,void * p)82 drmm_kfree(struct drm_device *dev, void *p)
83 {
84 	struct drmm_node *n, *m = NULL;
85 
86 	if (p == NULL)
87 		return;
88 
89 	mtx_enter(&dev->managed.lock);
90 	list_for_each_entry(n, &dev->managed.resources, list) {
91 		if (n->p == p) {
92 			list_del(&n->list);
93 			m = n;
94 			break;
95 		}
96 	}
97 	mtx_leave(&dev->managed.lock);
98 
99 	if (m != NULL) {
100 		free(m->p, M_DRM, m->size);
101 		free(m, M_DRM, sizeof(*m));
102 	}
103 }
104 
105 int
drmm_add_action(struct drm_device * dev,drmm_func_t f,void * cookie)106 drmm_add_action(struct drm_device *dev, drmm_func_t f, void *cookie)
107 {
108 	struct drmm_node *node = malloc(sizeof(*node), M_DRM, M_WAITOK | M_ZERO);
109 	if (node == NULL)
110 		return -ENOMEM;
111 	INIT_LIST_HEAD(&node->list);
112 	node->func = f;
113 	node->p = cookie;
114 	mtx_enter(&dev->managed.lock);
115 	list_add(&node->list, &dev->managed.resources);
116 	mtx_leave(&dev->managed.lock);
117 
118 	return 0;
119 }
120 
121 int
drmm_add_action_or_reset(struct drm_device * dev,drmm_func_t f,void * cookie)122 drmm_add_action_or_reset(struct drm_device *dev, drmm_func_t f, void *cookie)
123 {
124 	struct drmm_node *node = malloc(sizeof(*node), M_DRM, M_WAITOK | M_ZERO);
125 	if (node == NULL) {
126 		f(dev, cookie);
127 		return -ENOMEM;
128 	}
129 	INIT_LIST_HEAD(&node->list);
130 	node->func = f;
131 	node->p = cookie;
132 	mtx_enter(&dev->managed.lock);
133 	list_add(&node->list, &dev->managed.resources);
134 	mtx_leave(&dev->managed.lock);
135 
136 	return 0;
137 }
138 
139 void
drm_managed_release(struct drm_device * dev)140 drm_managed_release(struct drm_device *dev)
141 {
142 	struct drmm_node *n, *t;
143 	list_for_each_entry_safe(n, t, &dev->managed.resources, list) {
144 		list_del(&n->list);
145 		if (n->func)
146 			n->func(dev, n->p);
147 		else
148 			free(n->p, M_DRM, n->size);
149 		free(n, M_DRM, sizeof(*n));
150 	}
151 }
152 
153 void
drmm_add_final_kfree(struct drm_device * dev,void * p)154 drmm_add_final_kfree(struct drm_device *dev, void *p)
155 {
156 	dev->managed.final_kfree = p;
157 }
158