Line data Source code
1 : /**************************************************************************
2 : *
3 : * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
4 : * All Rights Reserved.
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a
7 : * copy of this software and associated documentation files (the
8 : * "Software"), to deal in the Software without restriction, including
9 : * without limitation the rights to use, copy, modify, merge, publish,
10 : * distribute, sub license, and/or sell copies of the Software, and to
11 : * permit persons to whom the Software is furnished to do so, subject to
12 : * the following conditions:
13 : *
14 : * The above copyright notice and this permission notice (including the
15 : * next paragraph) shall be included in all copies or substantial portions
16 : * of the Software.
17 : *
18 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 : * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 : * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 : * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 : * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 : *
26 : **************************************************************************/
27 : /*
28 : * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
29 : */
30 :
31 : #include <dev/pci/drm/ttm/ttm_module.h>
32 : #include <dev/pci/drm/ttm/ttm_bo_driver.h>
33 : #include <dev/pci/drm/ttm/ttm_placement.h>
34 : #include <dev/pci/drm/drm_mm.h>
35 :
36 : /**
37 : * Currently we use a spinlock for the lock, but a mutex *may* be
38 : * more appropriate to reduce scheduling latency if the range manager
39 : * ends up with very fragmented allocation patterns.
40 : */
41 :
42 : struct ttm_range_manager {
43 : struct drm_mm mm;
44 : spinlock_t lock;
45 : };
46 :
47 0 : static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
48 : struct ttm_buffer_object *bo,
49 : const struct ttm_place *place,
50 : struct ttm_mem_reg *mem)
51 : {
52 0 : struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
53 0 : struct drm_mm *mm = &rman->mm;
54 : struct drm_mm_node *node = NULL;
55 : enum drm_mm_search_flags sflags = DRM_MM_SEARCH_BEST;
56 : enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT;
57 : unsigned long lpfn;
58 : int ret;
59 :
60 0 : lpfn = place->lpfn;
61 0 : if (!lpfn)
62 0 : lpfn = man->size;
63 :
64 0 : node = kzalloc(sizeof(*node), GFP_KERNEL);
65 0 : if (!node)
66 0 : return -ENOMEM;
67 :
68 0 : if (place->flags & TTM_PL_FLAG_TOPDOWN) {
69 : sflags = DRM_MM_SEARCH_BELOW;
70 : aflags = DRM_MM_CREATE_TOP;
71 0 : }
72 :
73 0 : spin_lock(&rman->lock);
74 0 : ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages,
75 0 : mem->page_alignment, 0,
76 0 : place->fpfn, lpfn,
77 : sflags, aflags);
78 0 : spin_unlock(&rman->lock);
79 :
80 0 : if (unlikely(ret)) {
81 0 : kfree(node);
82 0 : } else {
83 0 : mem->mm_node = node;
84 0 : mem->start = node->start;
85 : }
86 :
87 0 : return 0;
88 0 : }
89 :
90 0 : static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
91 : struct ttm_mem_reg *mem)
92 : {
93 0 : struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
94 :
95 0 : if (mem->mm_node) {
96 0 : spin_lock(&rman->lock);
97 0 : drm_mm_remove_node(mem->mm_node);
98 0 : spin_unlock(&rman->lock);
99 :
100 0 : kfree(mem->mm_node);
101 0 : mem->mm_node = NULL;
102 0 : }
103 0 : }
104 :
105 0 : static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
106 : unsigned long p_size)
107 : {
108 : struct ttm_range_manager *rman;
109 :
110 0 : rman = kzalloc(sizeof(*rman), GFP_KERNEL);
111 0 : if (!rman)
112 0 : return -ENOMEM;
113 :
114 0 : drm_mm_init(&rman->mm, 0, p_size);
115 0 : mtx_init(&rman->lock, IPL_NONE);
116 0 : man->priv = rman;
117 0 : return 0;
118 0 : }
119 :
120 0 : static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
121 : {
122 0 : struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
123 0 : struct drm_mm *mm = &rman->mm;
124 :
125 0 : spin_lock(&rman->lock);
126 0 : if (drm_mm_clean(mm)) {
127 0 : drm_mm_takedown(mm);
128 0 : spin_unlock(&rman->lock);
129 0 : kfree(rman);
130 0 : man->priv = NULL;
131 0 : return 0;
132 : }
133 0 : spin_unlock(&rman->lock);
134 0 : return -EBUSY;
135 0 : }
136 :
137 0 : static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
138 : const char *prefix)
139 : {
140 0 : struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
141 :
142 0 : spin_lock(&rman->lock);
143 0 : drm_mm_debug_table(&rman->mm, prefix);
144 0 : spin_unlock(&rman->lock);
145 0 : }
146 :
147 : const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
148 : ttm_bo_man_init,
149 : ttm_bo_man_takedown,
150 : ttm_bo_man_get_node,
151 : ttm_bo_man_put_node,
152 : ttm_bo_man_debug
153 : };
154 : EXPORT_SYMBOL(ttm_bo_manager_func);
|