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 * 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 * 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 * 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 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 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 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 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 154 drmm_add_final_kfree(struct drm_device *dev, void *p) 155 { 156 dev->managed.final_kfree = p; 157 } 158