Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
gpu
drm
nouveau
core
core
mm.c
Go to the documentation of this file.
1
/*
2
* Copyright 2012 Red Hat Inc.
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
13
*
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
* OTHER DEALINGS IN THE SOFTWARE.
21
*
22
* Authors: Ben Skeggs
23
*/
24
25
#include "
core/os.h
"
26
#include "
core/mm.h
"
27
28
#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
29
list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
30
31
void
32
nouveau_mm_free
(
struct
nouveau_mm
*mm,
struct
nouveau_mm_node
**pthis)
33
{
34
struct
nouveau_mm_node
*
this
= *pthis;
35
36
if
(
this
) {
37
struct
nouveau_mm_node
*
prev
=
node
(
this
, prev);
38
struct
nouveau_mm_node
*
next
=
node
(
this
, next);
39
40
if
(prev && prev->
type
== 0) {
41
prev->
length
+= this->
length
;
42
list_del
(&this->
nl_entry
);
43
kfree
(
this
);
this
=
prev
;
44
}
45
46
if
(next && next->
type
== 0) {
47
next->
offset
= this->
offset
;
48
next->
length
+= this->
length
;
49
if
(this->
type
== 0)
50
list_del
(&this->
fl_entry
);
51
list_del
(&this->
nl_entry
);
52
kfree
(
this
);
this
=
NULL
;
53
}
54
55
if
(
this
&& this->
type
!= 0) {
56
list_for_each_entry
(prev, &mm->
free
,
fl_entry
) {
57
if
(this->
offset < prev->
offset
)
58
break
;
59
}
60
61
list_add_tail
(&this->
fl_entry
, &prev->
fl_entry
);
62
this->
type
= 0;
63
}
64
}
65
66
*pthis =
NULL
;
67
}
68
69
static
struct
nouveau_mm_node
*
70
region_head(
struct
nouveau_mm
*mm,
struct
nouveau_mm_node
*
a
,
u32
size
)
71
{
72
struct
nouveau_mm_node
*
b
;
73
74
if
(a->
length
== size)
75
return
a
;
76
77
b =
kmalloc
(
sizeof
(*b),
GFP_KERNEL
);
78
if
(
unlikely
(b ==
NULL
))
79
return
NULL
;
80
81
b->
offset
= a->
offset
;
82
b->
length
=
size
;
83
b->
type
= a->
type
;
84
a->
offset
+=
size
;
85
a->
length
-=
size
;
86
list_add_tail
(&b->
nl_entry
, &a->
nl_entry
);
87
if
(b->
type
== 0)
88
list_add_tail
(&b->
fl_entry
, &a->
fl_entry
);
89
return
b
;
90
}
91
92
int
93
nouveau_mm_head
(
struct
nouveau_mm
*mm,
u8
type
,
u32
size_max
,
u32
size_min,
94
u32
align
,
struct
nouveau_mm_node
**pnode)
95
{
96
struct
nouveau_mm_node
*
prev
, *
this
, *
next
;
97
u32
mask
= align - 1;
98
u32
splitoff;
99
u32
s
,
e
;
100
101
list_for_each_entry
(
this
, &mm->
free
,
fl_entry
) {
102
e = this->
offset
+ this->
length
;
103
s = this->
offset
;
104
105
prev =
node
(
this
, prev);
106
if
(prev && prev->
type
!= type)
107
s =
roundup
(s, mm->
block_size
);
108
109
next =
node
(
this
, next);
110
if
(next && next->
type
!= type)
111
e =
rounddown
(e, mm->
block_size
);
112
113
s = (s +
mask
) & ~mask;
114
e &= ~mask;
115
if
(s > e || e - s < size_min)
116
continue
;
117
118
splitoff = s - this->
offset
;
119
if
(splitoff && !region_head(mm,
this
, splitoff))
120
return
-
ENOMEM
;
121
122
this
= region_head(mm,
this
,
min
(size_max, e - s));
123
if
(!
this
)
124
return
-
ENOMEM
;
125
126
this->type =
type
;
127
list_del
(&this->
fl_entry
);
128
*pnode =
this
;
129
return
0;
130
}
131
132
return
-
ENOSPC
;
133
}
134
135
static
struct
nouveau_mm_node
*
136
region_tail(
struct
nouveau_mm
*mm,
struct
nouveau_mm_node
*a,
u32
size)
137
{
138
struct
nouveau_mm_node
*
b
;
139
140
if
(a->
length
== size)
141
return
a
;
142
143
b =
kmalloc
(
sizeof
(*b),
GFP_KERNEL
);
144
if
(
unlikely
(b ==
NULL
))
145
return
NULL
;
146
147
a->
length
-=
size
;
148
b->
offset
= a->
offset
+ a->
length
;
149
b->
length
=
size
;
150
b->
type
= a->
type
;
151
152
list_add(&b->
nl_entry
, &a->
nl_entry
);
153
if
(b->
type
== 0)
154
list_add(&b->
fl_entry
, &a->
fl_entry
);
155
return
b
;
156
}
157
158
int
159
nouveau_mm_tail
(
struct
nouveau_mm
*mm,
u8
type
,
u32
size_max
,
u32
size_min,
160
u32
align
,
struct
nouveau_mm_node
**pnode)
161
{
162
struct
nouveau_mm_node
*
prev
, *
this
, *
next
;
163
u32
mask
= align - 1;
164
165
list_for_each_entry_reverse
(
this
, &mm->
free
,
fl_entry
) {
166
u32
e
= this->
offset
+ this->
length
;
167
u32
s
= this->
offset
;
168
u32
c
= 0,
a
;
169
170
prev =
node
(
this
, prev);
171
if
(prev && prev->
type
!= type)
172
s =
roundup
(s, mm->
block_size
);
173
174
next =
node
(
this
, next);
175
if
(next && next->
type
!= type) {
176
e =
rounddown
(e, mm->
block_size
);
177
c = next->
offset
-
e
;
178
}
179
180
s = (s +
mask
) & ~mask;
181
a = e -
s
;
182
if
(s > e || a < size_min)
183
continue
;
184
185
a =
min
(a, size_max);
186
s = (e -
a
) & ~mask;
187
c += (e -
s
) - a;
188
189
if
(c && !region_tail(mm,
this
, c))
190
return
-
ENOMEM
;
191
192
this
= region_tail(mm,
this
, a);
193
if
(!
this
)
194
return
-
ENOMEM
;
195
196
this->type =
type
;
197
list_del
(&this->
fl_entry
);
198
*pnode =
this
;
199
return
0;
200
}
201
202
return
-
ENOSPC
;
203
}
204
205
int
206
nouveau_mm_init
(
struct
nouveau_mm
*mm,
u32
offset
,
u32
length
,
u32
block
)
207
{
208
struct
nouveau_mm_node
*
node
;
209
210
if
(block) {
211
mutex_init
(&mm->
mutex
);
212
INIT_LIST_HEAD(&mm->
nodes
);
213
INIT_LIST_HEAD(&mm->
free
);
214
mm->
block_size
=
block
;
215
mm->
heap_nodes
= 0;
216
}
217
218
node = kzalloc(
sizeof
(*node),
GFP_KERNEL
);
219
if
(!node)
220
return
-
ENOMEM
;
221
222
if
(length) {
223
node->
offset
=
roundup
(offset, mm->
block_size
);
224
node->
length
=
rounddown
(offset + length, mm->
block_size
);
225
node->
length
-= node->
offset
;
226
}
227
228
list_add_tail
(&node->
nl_entry
, &mm->
nodes
);
229
list_add_tail
(&node->
fl_entry
, &mm->
free
);
230
mm->
heap_nodes
++;
231
return
0;
232
}
233
234
int
235
nouveau_mm_fini
(
struct
nouveau_mm
*mm)
236
{
237
struct
nouveau_mm_node
*
node
, *heap =
238
list_first_entry
(&mm->
nodes
,
struct
nouveau_mm_node
,
nl_entry
);
239
int
nodes = 0;
240
241
list_for_each_entry
(node, &mm->
nodes
,
nl_entry
) {
242
if
(
WARN_ON
(nodes++ == mm->
heap_nodes
))
243
return
-
EBUSY
;
244
}
245
246
kfree
(heap);
247
return
0;
248
}
Generated on Thu Jan 10 2013 12:59:07 for Linux Kernel by
1.8.2