diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-01-14 00:46:30 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-01-16 20:28:54 -0500 |
commit | 8b464bfed674fc25d39d8a686010ebe509c8f62a (patch) | |
tree | 6c518cb466d186473af95b3ed6b7fe2756b960c4 /drivers/gpu | |
parent | c906ca0fbf237b77ba2101a2fa9050317137fde8 (diff) |
drm/nouveau: greatly simplify mm, killing some bugs in the process
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mm.c | 182 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mm.h | 4 |
3 files changed, 52 insertions, 160 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 69044eb104bb..26347b7cd872 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c | |||
@@ -742,30 +742,24 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) | |||
742 | { | 742 | { |
743 | struct nouveau_mm *mm = man->priv; | 743 | struct nouveau_mm *mm = man->priv; |
744 | struct nouveau_mm_node *r; | 744 | struct nouveau_mm_node *r; |
745 | u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {}; | 745 | u32 total = 0, free = 0; |
746 | int i; | ||
747 | 746 | ||
748 | mutex_lock(&mm->mutex); | 747 | mutex_lock(&mm->mutex); |
749 | list_for_each_entry(r, &mm->nodes, nl_entry) { | 748 | list_for_each_entry(r, &mm->nodes, nl_entry) { |
750 | printk(KERN_DEBUG "%s %s-%d: 0x%010llx 0x%010llx\n", | 749 | printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n", |
751 | prefix, r->free ? "free" : "used", r->type, | 750 | prefix, r->type, ((u64)r->offset << 12), |
752 | ((u64)r->offset << 12), | ||
753 | (((u64)r->offset + r->length) << 12)); | 751 | (((u64)r->offset + r->length) << 12)); |
752 | |||
754 | total += r->length; | 753 | total += r->length; |
755 | ttotal[r->type] += r->length; | 754 | if (!r->type) |
756 | if (r->free) | 755 | free += r->length; |
757 | tfree[r->type] += r->length; | ||
758 | else | ||
759 | tused[r->type] += r->length; | ||
760 | } | 756 | } |
761 | mutex_unlock(&mm->mutex); | 757 | mutex_unlock(&mm->mutex); |
762 | 758 | ||
763 | printk(KERN_DEBUG "%s total: 0x%010llx\n", prefix, total << 12); | 759 | printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n", |
764 | for (i = 0; i < 3; i++) { | 760 | prefix, (u64)total << 12, (u64)free << 12); |
765 | printk(KERN_DEBUG "%s type %d: 0x%010llx, " | 761 | printk(KERN_DEBUG "%s block: 0x%08x\n", |
766 | "used 0x%010llx, free 0x%010llx\n", prefix, | 762 | prefix, mm->block_size << 12); |
767 | i, ttotal[i] << 12, tused[i] << 12, tfree[i] << 12); | ||
768 | } | ||
769 | } | 763 | } |
770 | 764 | ||
771 | const struct ttm_mem_type_manager_func nouveau_vram_manager = { | 765 | const struct ttm_mem_type_manager_func nouveau_vram_manager = { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c index cdbb11eb701b..8844b50c3e54 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.c +++ b/drivers/gpu/drm/nouveau/nouveau_mm.c | |||
@@ -48,175 +48,76 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) | |||
48 | 48 | ||
49 | b->offset = a->offset; | 49 | b->offset = a->offset; |
50 | b->length = size; | 50 | b->length = size; |
51 | b->free = a->free; | ||
52 | b->type = a->type; | 51 | b->type = a->type; |
53 | a->offset += size; | 52 | a->offset += size; |
54 | a->length -= size; | 53 | a->length -= size; |
55 | list_add_tail(&b->nl_entry, &a->nl_entry); | 54 | list_add_tail(&b->nl_entry, &a->nl_entry); |
56 | if (b->free) | 55 | if (b->type == 0) |
57 | list_add_tail(&b->fl_entry, &a->fl_entry); | 56 | list_add_tail(&b->fl_entry, &a->fl_entry); |
58 | return b; | 57 | return b; |
59 | } | 58 | } |
60 | 59 | ||
61 | static struct nouveau_mm_node * | 60 | #define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \ |
62 | nouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this) | 61 | list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) |
63 | { | ||
64 | struct nouveau_mm_node *prev, *next; | ||
65 | |||
66 | /* try to merge with free adjacent entries of same type */ | ||
67 | prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry); | ||
68 | if (this->nl_entry.prev != &rmm->nodes) { | ||
69 | if (prev->free && prev->type == this->type) { | ||
70 | prev->length += this->length; | ||
71 | region_put(rmm, this); | ||
72 | this = prev; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); | ||
77 | if (this->nl_entry.next != &rmm->nodes) { | ||
78 | if (next->free && next->type == this->type) { | ||
79 | next->offset = this->offset; | ||
80 | next->length += this->length; | ||
81 | region_put(rmm, this); | ||
82 | this = next; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | return this; | ||
87 | } | ||
88 | 62 | ||
89 | void | 63 | void |
90 | nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) | 64 | nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) |
91 | { | 65 | { |
92 | u32 block_s, block_l; | 66 | struct nouveau_mm_node *prev = node(this, prev); |
67 | struct nouveau_mm_node *next = node(this, next); | ||
93 | 68 | ||
94 | this->free = true; | ||
95 | list_add(&this->fl_entry, &rmm->free); | 69 | list_add(&this->fl_entry, &rmm->free); |
96 | this = nouveau_mm_merge(rmm, this); | 70 | this->type = 0; |
97 | |||
98 | /* any entirely free blocks now? we'll want to remove typing | ||
99 | * on them now so they can be use for any memory allocation | ||
100 | */ | ||
101 | block_s = roundup(this->offset, rmm->block_size); | ||
102 | if (block_s + rmm->block_size > this->offset + this->length) | ||
103 | return; | ||
104 | 71 | ||
105 | /* split off any still-typed region at the start */ | 72 | if (prev && prev->type == 0) { |
106 | if (block_s != this->offset) { | 73 | prev->length += this->length; |
107 | if (!region_split(rmm, this, block_s - this->offset)) | 74 | region_put(rmm, this); |
108 | return; | 75 | this = prev; |
109 | } | 76 | } |
110 | 77 | ||
111 | /* split off the soon-to-be-untyped block(s) */ | 78 | if (next && next->type == 0) { |
112 | block_l = rounddown(this->length, rmm->block_size); | 79 | next->offset = this->offset; |
113 | if (block_l != this->length) { | 80 | next->length += this->length; |
114 | this = region_split(rmm, this, block_l); | 81 | region_put(rmm, this); |
115 | if (!this) | ||
116 | return; | ||
117 | } | 82 | } |
118 | |||
119 | /* mark as having no type, and retry merge with any adjacent | ||
120 | * untyped blocks | ||
121 | */ | ||
122 | this->type = 0; | ||
123 | nouveau_mm_merge(rmm, this); | ||
124 | } | 83 | } |
125 | 84 | ||
126 | int | 85 | int |
127 | nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, | 86 | nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, |
128 | u32 align, struct nouveau_mm_node **pnode) | 87 | u32 align, struct nouveau_mm_node **pnode) |
129 | { | 88 | { |
130 | struct nouveau_mm_node *this, *tmp, *next; | 89 | struct nouveau_mm_node *prev, *this, *next; |
131 | u32 splitoff, avail, alloc; | 90 | u32 min = size_nc ? size_nc : size; |
132 | 91 | u32 align_mask = align - 1; | |
133 | list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) { | 92 | u32 splitoff; |
134 | next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); | 93 | u32 s, e; |
135 | if (this->nl_entry.next == &rmm->nodes) | 94 | |
136 | next = NULL; | 95 | list_for_each_entry(this, &rmm->free, fl_entry) { |
137 | 96 | e = this->offset + this->length; | |
138 | /* skip wrongly typed blocks */ | 97 | s = this->offset; |
139 | if (this->type && this->type != type) | 98 | |
99 | prev = node(this, prev); | ||
100 | if (prev && prev->type != type) | ||
101 | s = roundup(s, rmm->block_size); | ||
102 | |||
103 | next = node(this, next); | ||
104 | if (next && next->type != type) | ||
105 | e = rounddown(e, rmm->block_size); | ||
106 | |||
107 | s = (s + align_mask) & ~align_mask; | ||
108 | e &= ~align_mask; | ||
109 | if (s > e || e - s < min) | ||
140 | continue; | 110 | continue; |
141 | 111 | ||
142 | /* account for alignment */ | 112 | splitoff = s - this->offset; |
143 | splitoff = this->offset & (align - 1); | 113 | if (splitoff && !region_split(rmm, this, splitoff)) |
144 | if (splitoff) | 114 | return -ENOMEM; |
145 | splitoff = align - splitoff; | ||
146 | |||
147 | if (this->length <= splitoff) | ||
148 | continue; | ||
149 | |||
150 | /* determine total memory available from this, and | ||
151 | * the next block (if appropriate) | ||
152 | */ | ||
153 | avail = this->length; | ||
154 | if (next && next->free && (!next->type || next->type == type)) | ||
155 | avail += next->length; | ||
156 | |||
157 | avail -= splitoff; | ||
158 | |||
159 | /* determine allocation size */ | ||
160 | if (size_nc) { | ||
161 | alloc = min(avail, size); | ||
162 | alloc = rounddown(alloc, size_nc); | ||
163 | if (alloc == 0) | ||
164 | continue; | ||
165 | } else { | ||
166 | alloc = size; | ||
167 | if (avail < alloc) | ||
168 | continue; | ||
169 | } | ||
170 | |||
171 | /* untyped block, split off a chunk that's a multiple | ||
172 | * of block_size and type it | ||
173 | */ | ||
174 | if (!this->type) { | ||
175 | u32 block = roundup(alloc + splitoff, rmm->block_size); | ||
176 | if (this->length < block) | ||
177 | continue; | ||
178 | |||
179 | this = region_split(rmm, this, block); | ||
180 | if (!this) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | this->type = type; | ||
184 | } | ||
185 | |||
186 | /* stealing memory from adjacent block */ | ||
187 | if (alloc > this->length) { | ||
188 | u32 amount = alloc - (this->length - splitoff); | ||
189 | |||
190 | if (!next->type) { | ||
191 | amount = roundup(amount, rmm->block_size); | ||
192 | |||
193 | next = region_split(rmm, next, amount); | ||
194 | if (!next) | ||
195 | return -ENOMEM; | ||
196 | |||
197 | next->type = type; | ||
198 | } | ||
199 | |||
200 | this->length += amount; | ||
201 | next->offset += amount; | ||
202 | next->length -= amount; | ||
203 | if (!next->length) { | ||
204 | list_del(&next->nl_entry); | ||
205 | list_del(&next->fl_entry); | ||
206 | kfree(next); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | if (splitoff) { | ||
211 | if (!region_split(rmm, this, splitoff)) | ||
212 | return -ENOMEM; | ||
213 | } | ||
214 | 115 | ||
215 | this = region_split(rmm, this, alloc); | 116 | this = region_split(rmm, this, min(size, e - s)); |
216 | if (this == NULL) | 117 | if (!this) |
217 | return -ENOMEM; | 118 | return -ENOMEM; |
218 | 119 | ||
219 | this->free = false; | 120 | this->type = type; |
220 | list_del(&this->fl_entry); | 121 | list_del(&this->fl_entry); |
221 | *pnode = this; | 122 | *pnode = this; |
222 | return 0; | 123 | return 0; |
@@ -234,7 +135,6 @@ nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) | |||
234 | heap = kzalloc(sizeof(*heap), GFP_KERNEL); | 135 | heap = kzalloc(sizeof(*heap), GFP_KERNEL); |
235 | if (!heap) | 136 | if (!heap) |
236 | return -ENOMEM; | 137 | return -ENOMEM; |
237 | heap->free = true; | ||
238 | heap->offset = roundup(offset, block); | 138 | heap->offset = roundup(offset, block); |
239 | heap->length = rounddown(offset + length, block) - heap->offset; | 139 | heap->length = rounddown(offset + length, block) - heap->offset; |
240 | 140 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h index af3844933036..798eaf39691c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.h +++ b/drivers/gpu/drm/nouveau/nouveau_mm.h | |||
@@ -30,9 +30,7 @@ struct nouveau_mm_node { | |||
30 | struct list_head fl_entry; | 30 | struct list_head fl_entry; |
31 | struct list_head rl_entry; | 31 | struct list_head rl_entry; |
32 | 32 | ||
33 | bool free; | 33 | u8 type; |
34 | int type; | ||
35 | |||
36 | u32 offset; | 34 | u32 offset; |
37 | u32 length; | 35 | u32 length; |
38 | }; | 36 | }; |