}
/**
- * drm_suballoc_new() - Make a suballocation.
+ * drm_suballoc_alloc() - Allocate uninitialized suballoc object.
+ * @gfp: gfp flags used for memory allocation.
+ *
+ * Allocate memory for an uninitialized suballoc object. Intended usage is
+ * allocate memory for suballoc object outside of a reclaim tainted context
+ * and then be initialized at a later time in a reclaim tainted context.
+ *
+ * @drm_suballoc_free() should be used to release the memory if returned
+ * suballoc object is in uninitialized state.
+ *
+ * Return: a new uninitialized suballoc object, or an ERR_PTR(-ENOMEM).
+ */
+struct drm_suballoc *drm_suballoc_alloc(gfp_t gfp)
+{
+ struct drm_suballoc *sa;
+
+ sa = kmalloc(sizeof(*sa), gfp);
+ if (!sa)
+ return ERR_PTR(-ENOMEM);
+
+ sa->manager = NULL;
+
+ return sa;
+}
+EXPORT_SYMBOL(drm_suballoc_alloc);
+
+/**
+ * drm_suballoc_insert() - Initialize a suballocation and insert a hole.
* @sa_manager: pointer to the sa_manager
+ * @sa: The struct drm_suballoc.
* @size: number of bytes we want to suballocate.
- * @gfp: gfp flags used for memory allocation. Typically GFP_KERNEL but
- * the argument is provided for suballocations from reclaim context or
- * where the caller wants to avoid pipelining rather than wait for
- * reclaim.
* @intr: Whether to perform waits interruptible. This should typically
* always be true, unless the caller needs to propagate a
* non-interruptible context from above layers.
* @align: Alignment. Must not exceed the default manager alignment.
* If @align is zero, then the manager alignment is used.
*
- * Try to make a suballocation of size @size, which will be rounded
- * up to the alignment specified in specified in drm_suballoc_manager_init().
+ * Try to make a suballocation on a pre-allocated suballoc object of size @size,
+ * which will be rounded up to the alignment specified in specified in
+ * drm_suballoc_manager_init().
*
- * Return: a new suballocated bo, or an ERR_PTR.
+ * Return: zero on success, errno on failure.
*/
-struct drm_suballoc *
-drm_suballoc_new(struct drm_suballoc_manager *sa_manager, size_t size,
- gfp_t gfp, bool intr, size_t align)
+int drm_suballoc_insert(struct drm_suballoc_manager *sa_manager,
+ struct drm_suballoc *sa, size_t size,
+ bool intr, size_t align)
{
struct dma_fence *fences[DRM_SUBALLOC_MAX_QUEUES];
unsigned int tries[DRM_SUBALLOC_MAX_QUEUES];
unsigned int count;
int i, r;
- struct drm_suballoc *sa;
if (WARN_ON_ONCE(align > sa_manager->align))
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (WARN_ON_ONCE(size > sa_manager->size || !size))
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (!align)
align = sa_manager->align;
- sa = kmalloc(sizeof(*sa), gfp);
- if (!sa)
- return ERR_PTR(-ENOMEM);
sa->manager = sa_manager;
sa->fence = NULL;
INIT_LIST_HEAD(&sa->olist);
if (drm_suballoc_try_alloc(sa_manager, sa,
size, align)) {
spin_unlock(&sa_manager->wq.lock);
- return sa;
+ return 0;
}
/* see if we can skip over some allocations */
} while (!r);
spin_unlock(&sa_manager->wq.lock);
- kfree(sa);
- return ERR_PTR(r);
+ sa->manager = NULL;
+ return r;
+}
+EXPORT_SYMBOL(drm_suballoc_insert);
+
+/**
+ * drm_suballoc_new() - Make a suballocation.
+ * @sa_manager: pointer to the sa_manager
+ * @size: number of bytes we want to suballocate.
+ * @gfp: gfp flags used for memory allocation. Typically GFP_KERNEL but
+ * the argument is provided for suballocations from reclaim context or
+ * where the caller wants to avoid pipelining rather than wait for
+ * reclaim.
+ * @intr: Whether to perform waits interruptible. This should typically
+ * always be true, unless the caller needs to propagate a
+ * non-interruptible context from above layers.
+ * @align: Alignment. Must not exceed the default manager alignment.
+ * If @align is zero, then the manager alignment is used.
+ *
+ * Try to make a suballocation of size @size, which will be rounded
+ * up to the alignment specified in specified in drm_suballoc_manager_init().
+ *
+ * Return: a new suballocated bo, or an ERR_PTR.
+ */
+struct drm_suballoc *
+drm_suballoc_new(struct drm_suballoc_manager *sa_manager, size_t size,
+ gfp_t gfp, bool intr, size_t align)
+{
+ struct drm_suballoc *sa;
+ int err;
+
+ sa = drm_suballoc_alloc(gfp);
+ if (IS_ERR(sa))
+ return sa;
+
+ err = drm_suballoc_insert(sa_manager, sa, size, intr, align);
+ if (err) {
+ drm_suballoc_free(sa, NULL);
+ return ERR_PTR(err);
+ }
+
+ return sa;
}
EXPORT_SYMBOL(drm_suballoc_new);
if (!suballoc)
return;
+ if (!suballoc->manager) {
+ kfree(suballoc);
+ return;
+ }
+
sa_manager = suballoc->manager;
spin_lock(&sa_manager->wq.lock);