2 /****************************************************************************
3 * Copyright (C) 2003-2006 by XGI Technology, Taiwan.
5 * All Rights Reserved. *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation on the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT. IN NO EVENT SHALL XGI AND/OR
23 * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ***************************************************************************/
29 #include "xgi_linux.h"
33 #define XGI_FB_HEAP_START 0x1000000
35 static struct xgi_mem_heap *xgi_fb_heap;
36 static struct kmem_cache *xgi_fb_cache_block = NULL;
37 extern struct list_head xgi_mempid_list;
39 static struct xgi_mem_block *xgi_mem_new_node(void);
40 static struct xgi_mem_block *xgi_mem_alloc(struct xgi_info * info, unsigned long size);
41 static struct xgi_mem_block *xgi_mem_free(struct xgi_info * info, unsigned long offset);
43 void xgi_fb_alloc(struct xgi_info * info, struct xgi_mem_alloc * alloc,
46 struct xgi_mem_block *block;
47 struct xgi_mem_pid *mempid_block;
49 if (alloc->is_front) {
50 alloc->location = XGI_MEMLOC_LOCAL;
51 alloc->bus_addr = info->fb.base;
54 ("Video RAM allocation on front buffer successfully! \n");
56 xgi_down(info->fb_sem);
57 block = xgi_mem_alloc(info, alloc->size);
61 alloc->location = XGI_MEMLOC_LOCAL;
65 XGI_ERROR("Video RAM allocation failed\n");
67 XGI_INFO("Video RAM allocation succeeded: 0x%p\n",
68 (char *)block->offset);
69 alloc->location = XGI_MEMLOC_LOCAL;
70 alloc->size = block->size;
71 alloc->bus_addr = info->fb.base + block->offset;
72 alloc->hw_addr = block->offset;
76 kmalloc(sizeof(struct xgi_mem_pid), GFP_KERNEL);
77 mempid_block->location = XGI_MEMLOC_LOCAL;
78 mempid_block->bus_addr = alloc->bus_addr;
79 mempid_block->pid = pid;
82 XGI_ERROR("mempid_block alloc failed\n");
85 ("Memory ProcessID add one fb block pid:%ld successfully! \n",
87 list_add(&mempid_block->list, &xgi_mempid_list);
92 void xgi_fb_free(struct xgi_info * info, unsigned long bus_addr)
94 struct xgi_mem_block *block;
95 unsigned long offset = bus_addr - info->fb.base;
96 struct xgi_mem_pid *mempid_block;
97 struct xgi_mem_pid *mempid_freeblock = NULL;
100 XGI_INFO("free onscreen frame buffer successfully !\n");
102 xgi_down(info->fb_sem);
103 block = xgi_mem_free(info, offset);
104 xgi_up(info->fb_sem);
107 XGI_ERROR("xgi_mem_free() failed at base 0x%lx\n",
112 list_for_each_entry(mempid_block, &xgi_mempid_list, list) {
113 if (mempid_block->location == XGI_MEMLOC_LOCAL
114 && mempid_block->bus_addr == bus_addr) {
115 mempid_freeblock = mempid_block;
119 if (mempid_freeblock) {
120 list_del(&mempid_freeblock->list);
122 ("Memory ProcessID delete one fb block pid:%ld successfully! \n",
123 mempid_freeblock->pid);
124 kfree(mempid_freeblock);
129 int xgi_fb_heap_init(struct xgi_info * info)
131 struct xgi_mem_block *block;
133 xgi_fb_heap = kmalloc(sizeof(struct xgi_mem_heap), GFP_KERNEL);
135 XGI_ERROR("xgi_fb_heap alloc failed\n");
139 INIT_LIST_HEAD(&xgi_fb_heap->free_list);
140 INIT_LIST_HEAD(&xgi_fb_heap->used_list);
141 INIT_LIST_HEAD(&xgi_fb_heap->sort_list);
144 kmem_cache_create("xgi_fb_block", sizeof(struct xgi_mem_block), 0,
145 SLAB_HWCACHE_ALIGN, NULL, NULL);
147 if (NULL == xgi_fb_cache_block) {
148 XGI_ERROR("Fail to creat xgi_fb_block\n");
153 (struct xgi_mem_block *) kmem_cache_alloc(xgi_fb_cache_block,
156 XGI_ERROR("kmem_cache_alloc failed\n");
160 block->offset = XGI_FB_HEAP_START;
161 block->size = info->fb.size - XGI_FB_HEAP_START;
163 list_add(&block->list, &xgi_fb_heap->free_list);
165 xgi_fb_heap->max_freesize = info->fb.size - XGI_FB_HEAP_START;
167 XGI_INFO("fb start offset: 0x%lx, memory size : 0x%lx\n", block->offset,
169 XGI_INFO("xgi_fb_heap->max_freesize: 0x%lx \n",
170 xgi_fb_heap->max_freesize);
175 if (xgi_fb_cache_block) {
176 kmem_cache_destroy(xgi_fb_cache_block);
177 xgi_fb_cache_block = NULL;
187 void xgi_fb_heap_cleanup(struct xgi_info * info)
189 struct list_head *free_list;
190 struct xgi_mem_block *block;
191 struct xgi_mem_block *next;
195 free_list = &xgi_fb_heap->free_list;
196 for (i = 0; i < 3; i++, free_list++) {
197 list_for_each_entry_safe(block, next, free_list, list) {
199 ("No. %d block->offset: 0x%lx block->size: 0x%lx \n",
200 i, block->offset, block->size);
201 //XGI_INFO("No. %d free block: 0x%p \n", i, block);
202 kmem_cache_free(xgi_fb_cache_block, block);
206 XGI_INFO("xgi_fb_heap: 0x%p \n", xgi_fb_heap);
211 if (xgi_fb_cache_block) {
212 kmem_cache_destroy(xgi_fb_cache_block);
213 xgi_fb_cache_block = NULL;
217 static struct xgi_mem_block *xgi_mem_new_node(void)
219 struct xgi_mem_block *block;
222 (struct xgi_mem_block *) kmem_cache_alloc(xgi_fb_cache_block,
225 XGI_ERROR("kmem_cache_alloc failed\n");
233 static void xgi_mem_insert_node_after(struct xgi_mem_list * list,
234 struct xgi_mem_block * current,
235 struct xgi_mem_block * block);
236 static void xgi_mem_insert_node_before(struct xgi_mem_list * list,
237 struct xgi_mem_block * current,
238 struct xgi_mem_block * block);
239 static void xgi_mem_insert_node_head(struct xgi_mem_list * list,
240 struct xgi_mem_block * block);
241 static void xgi_mem_insert_node_tail(struct xgi_mem_list * list,
242 struct xgi_mem_block * block);
243 static void xgi_mem_delete_node(struct xgi_mem_list * list, struct xgi_mem_block * block);
245 * insert node:block after node:current
247 static void xgi_mem_insert_node_after(struct xgi_mem_list * list,
248 struct xgi_mem_block * current,
249 struct xgi_mem_block * block)
251 block->prev = current;
252 block->next = current->next;
253 current->next = block;
255 if (current == list->tail) {
258 block->next->prev = block;
263 * insert node:block before node:current
265 static void xgi_mem_insert_node_before(struct xgi_mem_list * list,
266 struct xgi_mem_block * current,
267 struct xgi_mem_block * block)
269 block->prev = current->prev;
270 block->next = current;
271 current->prev = block;
272 if (current == list->head) {
275 block->prev->next = block;
278 void xgi_mem_insert_node_head(struct xgi_mem_list * list, struct xgi_mem_block * block)
280 block->next = list->head;
283 if (NULL == list->head) {
286 list->head->prev = block;
291 static void xgi_mem_insert_node_tail(struct xgi_mem_list * list,
292 struct xgi_mem_block * block)
295 block->prev = list->tail;
296 if (NULL == list->tail) {
299 list->tail->next = block;
304 static void xgi_mem_delete_node(struct xgi_mem_list * list, struct xgi_mem_block * block)
306 if (block == list->head) {
307 list->head = block->next;
309 if (block == list->tail) {
310 list->tail = block->prev;
314 block->prev->next = block->next;
317 block->next->prev = block->prev;
320 block->next = block->prev = NULL;
323 static struct xgi_mem_block *xgi_mem_alloc(struct xgi_info * info,
324 unsigned long originalSize)
326 struct xgi_mem_block *block, *free_block, *used_block;
328 unsigned long size = (originalSize + PAGE_SIZE - 1) & PAGE_MASK;
330 XGI_INFO("Original 0x%lx bytes requested, really 0x%lx allocated\n",
334 XGI_ERROR("size == 0\n");
337 XGI_INFO("max_freesize: 0x%lx \n", xgi_fb_heap->max_freesize);
338 if (size > xgi_fb_heap->max_freesize) {
340 ("size: 0x%lx is bigger than frame buffer total free size: 0x%lx !\n",
341 size, xgi_fb_heap->max_freesize);
345 list_for_each_entry(block, &xgi_fb_heap->free_list, list) {
346 XGI_INFO("free_list: 0x%px \n", free_list);
347 if (size <= block->size) {
352 if (&block->list == &xgi_fb_heap->free_list) {
354 ("Can't allocate %ldk size from frame buffer memory !\n",
360 XGI_INFO("alloc size: 0x%lx from offset: 0x%lx size: 0x%lx \n",
361 size, free_block->offset, free_block->size);
363 if (size == free_block->size) {
364 used_block = free_block;
365 XGI_INFO("size == free_block->size: free_block = 0x%p\n",
367 list_del(&free_block->list);
369 used_block = xgi_mem_new_node();
371 if (used_block == NULL)
374 if (used_block == free_block) {
375 XGI_ERROR("used_block == free_block = 0x%p\n",
379 used_block->offset = free_block->offset;
380 used_block->size = size;
382 free_block->offset += size;
383 free_block->size -= size;
386 xgi_fb_heap->max_freesize -= size;
388 list_add(&used_block->list, &xgi_fb_heap->used_list);
393 static struct xgi_mem_block *xgi_mem_free(struct xgi_info * info, unsigned long offset)
395 struct xgi_mem_block *used_block = NULL, *block;
396 struct xgi_mem_block *prev, *next;
401 list_for_each_entry(block, &xgi_fb_heap->used_list, list) {
402 if (block->offset == offset) {
407 if (&block->list == &xgi_fb_heap->used_list) {
408 XGI_ERROR("can't find block: 0x%lx to free!\n", offset);
413 XGI_INFO("used_block: 0x%p, offset = 0x%lx, size = 0x%lx\n",
414 used_block, used_block->offset, used_block->size);
416 xgi_fb_heap->max_freesize += used_block->size;
419 upper = used_block->offset + used_block->size;
420 lower = used_block->offset;
422 list_for_each_entry(block, &xgi_fb_heap->free_list, list) {
423 if (block->offset == upper) {
425 } else if ((block->offset + block->size) == lower) {
430 XGI_INFO("next = 0x%p, prev = 0x%p\n", next, prev);
431 list_del(&used_block->list);
434 prev->size += (used_block->size + next->size);
435 list_del(&next->list);
436 XGI_INFO("free node 0x%p\n", next);
437 kmem_cache_free(xgi_fb_cache_block, next);
438 kmem_cache_free(xgi_fb_cache_block, used_block);
446 prev->size += used_block->size;
447 XGI_INFO("free node 0x%p\n", used_block);
448 kmem_cache_free(xgi_fb_cache_block, used_block);
454 next->size += used_block->size;
455 next->offset = used_block->offset;
456 XGI_INFO("free node 0x%p\n", used_block);
457 kmem_cache_free(xgi_fb_cache_block, used_block);
462 list_add(&used_block->list, &xgi_fb_heap->free_list);
463 XGI_INFO("Recycled free node %p, offset = 0x%lx, size = 0x%lx\n",
464 used_block, used_block->offset, used_block->size);