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 11struct drmm_node { 12 void *p; 13 size_t size; 14 drmm_func_t func; 15 struct list_head list; 16}; 17 18void * 19drmm_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 39void * 40drmm_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 60char * 61drmm_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 81void 82drmm_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 105int 106drmm_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 121int 122drmm_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 139void 140drm_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 153void 154drmm_add_final_kfree(struct drm_device *dev, void *p) 155{ 156 dev->managed.final_kfree = p; 157} 158