Home | History | Annotate | Line # | Download | only in drm
drm_vma_manager.c revision 1.1.8.4
      1  1.1.8.4     skrll /*	$NetBSD: drm_vma_manager.c,v 1.1.8.4 2016/12/05 10:55:25 skrll Exp $	*/
      2      1.1  riastrad 
      3      1.1  riastrad /*-
      4      1.1  riastrad  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5      1.1  riastrad  * All rights reserved.
      6      1.1  riastrad  *
      7      1.1  riastrad  * This code is derived from software contributed to The NetBSD Foundation
      8      1.1  riastrad  * by Taylor R. Campbell.
      9      1.1  riastrad  *
     10      1.1  riastrad  * Redistribution and use in source and binary forms, with or without
     11      1.1  riastrad  * modification, are permitted provided that the following conditions
     12      1.1  riastrad  * are met:
     13      1.1  riastrad  * 1. Redistributions of source code must retain the above copyright
     14      1.1  riastrad  *    notice, this list of conditions and the following disclaimer.
     15      1.1  riastrad  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1  riastrad  *    notice, this list of conditions and the following disclaimer in the
     17      1.1  riastrad  *    documentation and/or other materials provided with the distribution.
     18      1.1  riastrad  *
     19      1.1  riastrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20      1.1  riastrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21      1.1  riastrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22      1.1  riastrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23      1.1  riastrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24      1.1  riastrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25      1.1  riastrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26      1.1  riastrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27      1.1  riastrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28      1.1  riastrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29      1.1  riastrad  * POSSIBILITY OF SUCH DAMAGE.
     30      1.1  riastrad  */
     31      1.1  riastrad 
     32      1.1  riastrad #include <sys/cdefs.h>
     33  1.1.8.4     skrll __KERNEL_RCSID(0, "$NetBSD: drm_vma_manager.c,v 1.1.8.4 2016/12/05 10:55:25 skrll Exp $");
     34      1.1  riastrad 
     35      1.1  riastrad #include <sys/kmem.h>
     36      1.1  riastrad #include <sys/rbtree.h>
     37      1.1  riastrad #include <sys/vmem.h>
     38      1.1  riastrad 
     39      1.1  riastrad #include <drm/drm_vma_manager.h>
     40      1.1  riastrad 
     41      1.1  riastrad static int
     42      1.1  riastrad drm_vma_node_compare(void *cookie __unused, const void *va, const void *vb)
     43      1.1  riastrad {
     44      1.1  riastrad 	const struct drm_vma_offset_node *const na = va;
     45      1.1  riastrad 	const struct drm_vma_offset_node *const nb = vb;
     46      1.1  riastrad 
     47      1.1  riastrad 	if (na->von_startpage < nb->von_startpage)
     48      1.1  riastrad 		return -1;
     49      1.1  riastrad 	if (na->von_startpage > nb->von_startpage)
     50      1.1  riastrad 		return +1;
     51      1.1  riastrad 	return 0;
     52      1.1  riastrad }
     53      1.1  riastrad 
     54      1.1  riastrad static int
     55      1.1  riastrad drm_vma_node_compare_key(void *cookie __unused, const void *vn, const void *vk)
     56      1.1  riastrad {
     57      1.1  riastrad 	const struct drm_vma_offset_node *const n = vn;
     58      1.1  riastrad 	const vmem_addr_t *const k = vk;
     59      1.1  riastrad 
     60      1.1  riastrad 	if (n->von_startpage < *k)
     61      1.1  riastrad 		return -1;
     62      1.1  riastrad 	if (n->von_startpage > *k)
     63      1.1  riastrad 		return +1;
     64      1.1  riastrad 	return 0;
     65      1.1  riastrad }
     66      1.1  riastrad 
     67      1.1  riastrad static const rb_tree_ops_t drm_vma_node_rb_ops = {
     68      1.1  riastrad 	.rbto_compare_nodes = &drm_vma_node_compare,
     69      1.1  riastrad 	.rbto_compare_key = &drm_vma_node_compare_key,
     70      1.1  riastrad 	.rbto_node_offset = offsetof(struct drm_vma_offset_node, von_rb_node),
     71      1.1  riastrad 	.rbto_context = NULL,
     72      1.1  riastrad };
     73      1.1  riastrad 
     74      1.1  riastrad static int
     75      1.1  riastrad drm_vma_file_compare(void *cookie __unused, const void *va, const void *vb)
     76      1.1  riastrad {
     77      1.1  riastrad 	const struct drm_vma_offset_file *const fa = va;
     78      1.1  riastrad 	const struct drm_vma_offset_file *const fb = vb;
     79      1.1  riastrad 
     80      1.1  riastrad 	if (fa->vof_file < fb->vof_file)
     81      1.1  riastrad 		return -1;
     82      1.1  riastrad 	if (fa->vof_file > fb->vof_file)
     83      1.1  riastrad 		return +1;
     84      1.1  riastrad 	return 0;
     85      1.1  riastrad }
     86      1.1  riastrad 
     87      1.1  riastrad static int
     88      1.1  riastrad drm_vma_file_compare_key(void *cookie __unused, const void *vf, const void *vk)
     89      1.1  riastrad {
     90      1.1  riastrad 	const struct drm_vma_offset_file *const f = vf;
     91      1.1  riastrad 	const struct file *const k = vk;
     92      1.1  riastrad 
     93      1.1  riastrad 	if (f->vof_file < k)
     94      1.1  riastrad 		return -1;
     95      1.1  riastrad 	if (f->vof_file > k)
     96      1.1  riastrad 		return +1;
     97      1.1  riastrad 	return 0;
     98      1.1  riastrad }
     99      1.1  riastrad 
    100      1.1  riastrad static const rb_tree_ops_t drm_vma_file_rb_ops = {
    101      1.1  riastrad 	.rbto_compare_nodes = &drm_vma_file_compare,
    102      1.1  riastrad 	.rbto_compare_key = &drm_vma_file_compare_key,
    103      1.1  riastrad 	.rbto_node_offset = offsetof(struct drm_vma_offset_file, vof_rb_node),
    104      1.1  riastrad 	.rbto_context = NULL,
    105      1.1  riastrad };
    106      1.1  riastrad 
    107      1.1  riastrad void
    108      1.1  riastrad drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr,
    109      1.1  riastrad     unsigned long startpage, unsigned long npages)
    110      1.1  riastrad {
    111      1.1  riastrad 
    112      1.1  riastrad 	rw_init(&mgr->vom_lock);
    113      1.1  riastrad 	rb_tree_init(&mgr->vom_nodes, &drm_vma_node_rb_ops);
    114      1.1  riastrad 	mgr->vom_vmem = vmem_create("drm_vma", startpage, npages, 1,
    115      1.1  riastrad 	    NULL, NULL, NULL, 0, VM_SLEEP, IPL_NONE);
    116      1.1  riastrad }
    117      1.1  riastrad 
    118      1.1  riastrad void
    119      1.1  riastrad drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr)
    120      1.1  riastrad {
    121      1.1  riastrad 
    122      1.1  riastrad 	vmem_destroy(mgr->vom_vmem);
    123  1.1.8.3     skrll 	KASSERTMSG((RB_TREE_MIN(&mgr->vom_nodes) == NULL),
    124  1.1.8.3     skrll 	    "drm vma offset manager %p not empty", mgr);
    125      1.1  riastrad #if 0
    126      1.1  riastrad 	rb_tree_destroy(&mgr->vom_nodes);
    127      1.1  riastrad #endif
    128      1.1  riastrad 	rw_destroy(&mgr->vom_lock);
    129      1.1  riastrad }
    130  1.1.8.2     skrll 
    131      1.1  riastrad void
    132      1.1  riastrad drm_vma_node_init(struct drm_vma_offset_node *node)
    133      1.1  riastrad {
    134      1.1  riastrad 	static const struct drm_vma_offset_node zero_node;
    135      1.1  riastrad 
    136      1.1  riastrad 	*node = zero_node;
    137      1.1  riastrad 
    138      1.1  riastrad 	rw_init(&node->von_lock);
    139      1.1  riastrad 	node->von_startpage = 0;
    140      1.1  riastrad 	node->von_npages = 0;
    141      1.1  riastrad 	rb_tree_init(&node->von_files, &drm_vma_file_rb_ops);
    142      1.1  riastrad }
    143      1.1  riastrad 
    144      1.1  riastrad void
    145      1.1  riastrad drm_vma_node_destroy(struct drm_vma_offset_node *node)
    146      1.1  riastrad {
    147      1.1  riastrad 
    148  1.1.8.3     skrll 	KASSERTMSG((RB_TREE_MIN(&node->von_files) == NULL),
    149  1.1.8.3     skrll 	    "drm vma node %p not empty", node);
    150      1.1  riastrad #if 0
    151      1.1  riastrad 	rb_tree_destroy(&node->von_files);
    152      1.1  riastrad #endif
    153      1.1  riastrad 	KASSERT(node->von_startpage == 0);
    154      1.1  riastrad 	KASSERT(node->von_npages == 0);
    155      1.1  riastrad 	rw_destroy(&node->von_lock);
    156      1.1  riastrad }
    157      1.1  riastrad 
    158      1.1  riastrad int
    159      1.1  riastrad drm_vma_offset_add(struct drm_vma_offset_manager *mgr,
    160      1.1  riastrad     struct drm_vma_offset_node *node, unsigned long npages)
    161      1.1  riastrad {
    162      1.1  riastrad 	vmem_size_t startpage;
    163      1.1  riastrad 	struct drm_vma_offset_node *collision __diagused;
    164      1.1  riastrad 	int error;
    165      1.1  riastrad 
    166      1.1  riastrad 	KASSERT(npages != 0);
    167      1.1  riastrad 
    168      1.1  riastrad 	if (0 < node->von_npages)
    169      1.1  riastrad 		return 0;
    170      1.1  riastrad 
    171  1.1.8.1     skrll 	error = vmem_alloc(mgr->vom_vmem, npages, VM_NOSLEEP|VM_BESTFIT,
    172      1.1  riastrad 	    &startpage);
    173  1.1.8.1     skrll 	if (error) {
    174  1.1.8.1     skrll 		if (error == ENOMEM)
    175  1.1.8.1     skrll 			error = ENOSPC;
    176      1.1  riastrad 		/* XXX errno NetBSD->Linux */
    177      1.1  riastrad 		return -error;
    178  1.1.8.1     skrll 	}
    179      1.1  riastrad 
    180      1.1  riastrad 	node->von_startpage = startpage;
    181      1.1  riastrad 	node->von_npages = npages;
    182      1.1  riastrad 
    183  1.1.8.4     skrll 	rw_enter(&mgr->vom_lock, RW_WRITER);
    184      1.1  riastrad 	collision = rb_tree_insert_node(&mgr->vom_nodes, node);
    185      1.1  riastrad 	KASSERT(collision == node);
    186  1.1.8.4     skrll 	rw_exit(&mgr->vom_lock);
    187      1.1  riastrad 
    188      1.1  riastrad 	return 0;
    189      1.1  riastrad }
    190      1.1  riastrad 
    191      1.1  riastrad void
    192      1.1  riastrad drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,
    193      1.1  riastrad     struct drm_vma_offset_node *node)
    194      1.1  riastrad {
    195      1.1  riastrad 
    196      1.1  riastrad 	if (node->von_npages == 0)
    197      1.1  riastrad 		return;
    198      1.1  riastrad 
    199  1.1.8.4     skrll 	rw_enter(&mgr->vom_lock, RW_WRITER);
    200      1.1  riastrad 	rb_tree_remove_node(&mgr->vom_nodes, node);
    201  1.1.8.4     skrll 	rw_exit(&mgr->vom_lock);
    202      1.1  riastrad 
    203      1.1  riastrad 	vmem_free(mgr->vom_vmem, node->von_startpage, node->von_npages);
    204      1.1  riastrad 
    205      1.1  riastrad 	node->von_npages = 0;
    206      1.1  riastrad 	node->von_startpage = 0;
    207      1.1  riastrad }
    208  1.1.8.2     skrll 
    209      1.1  riastrad void
    210      1.1  riastrad drm_vma_offset_lock_lookup(struct drm_vma_offset_manager *mgr)
    211      1.1  riastrad {
    212      1.1  riastrad 
    213      1.1  riastrad 	rw_enter(&mgr->vom_lock, RW_READER);
    214      1.1  riastrad }
    215      1.1  riastrad 
    216      1.1  riastrad void
    217      1.1  riastrad drm_vma_offset_unlock_lookup(struct drm_vma_offset_manager *mgr)
    218      1.1  riastrad {
    219      1.1  riastrad 
    220      1.1  riastrad 	rw_exit(&mgr->vom_lock);
    221      1.1  riastrad }
    222      1.1  riastrad 
    223      1.1  riastrad struct drm_vma_offset_node *
    224      1.1  riastrad drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr,
    225      1.1  riastrad     unsigned long startpage, unsigned long npages)
    226      1.1  riastrad {
    227      1.1  riastrad 	const vmem_addr_t key = startpage;
    228      1.1  riastrad 	struct drm_vma_offset_node *node;
    229      1.1  riastrad 
    230      1.1  riastrad 	KASSERT(rw_lock_held(&mgr->vom_lock));
    231      1.1  riastrad 
    232      1.1  riastrad 	node = rb_tree_find_node_leq(&mgr->vom_nodes, &key);
    233      1.1  riastrad 	if (node == NULL)
    234      1.1  riastrad 		return NULL;
    235      1.1  riastrad 	KASSERT(node->von_startpage <= startpage);
    236      1.1  riastrad 	if (npages < node->von_npages)
    237      1.1  riastrad 		return NULL;
    238      1.1  riastrad 	if (node->von_npages - npages < startpage - node->von_startpage)
    239      1.1  riastrad 		return NULL;
    240      1.1  riastrad 
    241      1.1  riastrad 	return node;
    242      1.1  riastrad }
    243      1.1  riastrad 
    244      1.1  riastrad struct drm_vma_offset_node *
    245      1.1  riastrad drm_vma_offset_exact_lookup(struct drm_vma_offset_manager *mgr,
    246      1.1  riastrad     unsigned long startpage, unsigned long npages)
    247      1.1  riastrad {
    248      1.1  riastrad 	const vmem_addr_t key = startpage;
    249      1.1  riastrad 	struct drm_vma_offset_node *node;
    250      1.1  riastrad 
    251      1.1  riastrad 	rw_enter(&mgr->vom_lock, RW_READER);
    252      1.1  riastrad 
    253      1.1  riastrad 	node = rb_tree_find_node(&mgr->vom_nodes, &key);
    254      1.1  riastrad 	if (node == NULL)
    255      1.1  riastrad 		goto out;
    256      1.1  riastrad 	KASSERT(node->von_startpage == startpage);
    257      1.1  riastrad 	if (node->von_npages != npages) {
    258      1.1  riastrad 		node = NULL;
    259      1.1  riastrad 		goto out;
    260      1.1  riastrad 	}
    261      1.1  riastrad 
    262      1.1  riastrad out:	rw_exit(&mgr->vom_lock);
    263      1.1  riastrad 	return node;
    264      1.1  riastrad }
    265  1.1.8.2     skrll 
    266      1.1  riastrad int
    267      1.1  riastrad drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *file)
    268      1.1  riastrad {
    269      1.1  riastrad 	struct drm_vma_offset_file *new, *old;
    270      1.1  riastrad 
    271      1.1  riastrad 	new = kmem_alloc(sizeof(*new), KM_NOSLEEP);
    272      1.1  riastrad 	if (new == NULL)
    273      1.1  riastrad 		return -ENOMEM;
    274      1.1  riastrad 	new->vof_file = file;
    275      1.1  riastrad 
    276      1.1  riastrad 	rw_enter(&node->von_lock, RW_WRITER);
    277      1.1  riastrad 	old = rb_tree_insert_node(&node->von_files, new);
    278      1.1  riastrad 	rw_exit(&node->von_lock);
    279      1.1  riastrad 
    280      1.1  riastrad 	if (old != new)		/* collision */
    281      1.1  riastrad 		kmem_free(new, sizeof(*new));
    282      1.1  riastrad 
    283      1.1  riastrad 	return 0;
    284      1.1  riastrad }
    285      1.1  riastrad 
    286      1.1  riastrad void
    287      1.1  riastrad drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *file)
    288      1.1  riastrad {
    289      1.1  riastrad 
    290      1.1  riastrad 	rw_enter(&node->von_lock, RW_WRITER);
    291      1.1  riastrad 	struct drm_vma_offset_file *const found =
    292      1.1  riastrad 	    rb_tree_find_node(&node->von_files, file);
    293      1.1  riastrad 	if (found != NULL)
    294      1.1  riastrad 		rb_tree_remove_node(&node->von_files, found);
    295      1.1  riastrad 	rw_exit(&node->von_lock);
    296  1.1.8.2     skrll 	if (found != NULL)
    297  1.1.8.2     skrll 		kmem_free(found, sizeof(*found));
    298      1.1  riastrad }
    299      1.1  riastrad 
    300      1.1  riastrad bool
    301      1.1  riastrad drm_vma_node_is_allowed(struct drm_vma_offset_node *node, struct file *file)
    302      1.1  riastrad {
    303      1.1  riastrad 
    304      1.1  riastrad 	rw_enter(&node->von_lock, RW_READER);
    305      1.1  riastrad 	const bool allowed =
    306      1.1  riastrad 	    (rb_tree_find_node(&node->von_files, file) != NULL);
    307      1.1  riastrad 	rw_exit(&node->von_lock);
    308      1.1  riastrad 
    309      1.1  riastrad 	return allowed;
    310      1.1  riastrad }
    311      1.1  riastrad 
    312      1.1  riastrad int
    313      1.1  riastrad drm_vma_node_verify_access(struct drm_vma_offset_node *node, struct file *file)
    314      1.1  riastrad {
    315      1.1  riastrad 
    316      1.1  riastrad 	if (!drm_vma_node_is_allowed(node, file))
    317      1.1  riastrad 		return -EACCES;
    318      1.1  riastrad 
    319      1.1  riastrad 	return 0;
    320      1.1  riastrad }
    321