diff options
author | Thomas Hellstrom <thomas@tungstengraphics.com> | 2006-08-07 07:30:28 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2006-09-21 15:32:31 -0400 |
commit | 3a1bd924f36da202e480a0e0174b2878c0924a05 (patch) | |
tree | ffae75227509c612a12dc1abb4f9b717de185054 /drivers | |
parent | b9b603dd1c99a68e65ad51cda25379441df2e17b (diff) |
drm: add simple DRM memory manager, and hash table
This adds the DRM hashtable and simple memory manager implementations from
Tungsten Graphics, this is NOT the new memory manager, this is a replacement
for the SIS and VIA memory managers.
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/drm/Makefile | 2 | ||||
-rw-r--r-- | drivers/char/drm/drmP.h | 33 | ||||
-rw-r--r-- | drivers/char/drm/drm_hashtab.c | 190 | ||||
-rw-r--r-- | drivers/char/drm/drm_hashtab.h | 67 | ||||
-rw-r--r-- | drivers/char/drm/drm_mm.c | 201 | ||||
-rw-r--r-- | drivers/char/drm/drm_sman.c | 352 | ||||
-rw-r--r-- | drivers/char/drm/drm_sman.h | 176 |
7 files changed, 1019 insertions, 2 deletions
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index 9d180c42816c..5eb79f2d5587 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile | |||
@@ -6,7 +6,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ | |||
6 | drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ | 6 | drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ |
7 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ | 7 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ |
8 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ | 8 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ |
9 | drm_sysfs.o | 9 | drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o |
10 | 10 | ||
11 | tdfx-objs := tdfx_drv.o | 11 | tdfx-objs := tdfx_drv.o |
12 | r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o | 12 | r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o |
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 4f0de974c191..c93985bb91a2 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
@@ -79,6 +79,7 @@ | |||
79 | #define __OS_HAS_MTRR (defined(CONFIG_MTRR)) | 79 | #define __OS_HAS_MTRR (defined(CONFIG_MTRR)) |
80 | 80 | ||
81 | #include "drm_os_linux.h" | 81 | #include "drm_os_linux.h" |
82 | #include "drm_hashtab.h" | ||
82 | 83 | ||
83 | /***********************************************************************/ | 84 | /***********************************************************************/ |
84 | /** \name DRM template customization defaults */ | 85 | /** \name DRM template customization defaults */ |
@@ -134,7 +135,9 @@ | |||
134 | #define DRM_MEM_CTXBITMAP 18 | 135 | #define DRM_MEM_CTXBITMAP 18 |
135 | #define DRM_MEM_STUB 19 | 136 | #define DRM_MEM_STUB 19 |
136 | #define DRM_MEM_SGLISTS 20 | 137 | #define DRM_MEM_SGLISTS 20 |
137 | #define DRM_MEM_CTXLIST 21 | 138 | #define DRM_MEM_CTXLIST 21 |
139 | #define DRM_MEM_MM 22 | ||
140 | #define DRM_MEM_HASHTAB 23 | ||
138 | 141 | ||
139 | #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) | 142 | #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) |
140 | 143 | ||
@@ -515,6 +518,22 @@ typedef struct ati_pcigart_info { | |||
515 | drm_local_map_t mapping; | 518 | drm_local_map_t mapping; |
516 | } drm_ati_pcigart_info; | 519 | } drm_ati_pcigart_info; |
517 | 520 | ||
521 | /* | ||
522 | * Generic memory manager structs | ||
523 | */ | ||
524 | typedef struct drm_mm_node { | ||
525 | struct list_head fl_entry; | ||
526 | struct list_head ml_entry; | ||
527 | int free; | ||
528 | unsigned long start; | ||
529 | unsigned long size; | ||
530 | void *private; | ||
531 | } drm_mm_node_t; | ||
532 | |||
533 | typedef struct drm_mm { | ||
534 | drm_mm_node_t root_node; | ||
535 | } drm_mm_t; | ||
536 | |||
518 | /** | 537 | /** |
519 | * DRM driver structure. This structure represent the common code for | 538 | * DRM driver structure. This structure represent the common code for |
520 | * a family of cards. There will one drm_device for each card present | 539 | * a family of cards. There will one drm_device for each card present |
@@ -1001,6 +1020,18 @@ extern struct class_device *drm_sysfs_device_add(struct class *cs, | |||
1001 | drm_head_t *head); | 1020 | drm_head_t *head); |
1002 | extern void drm_sysfs_device_remove(struct class_device *class_dev); | 1021 | extern void drm_sysfs_device_remove(struct class_device *class_dev); |
1003 | 1022 | ||
1023 | /* | ||
1024 | * Basic memory manager support (drm_mm.c) | ||
1025 | */ | ||
1026 | extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, | ||
1027 | unsigned long size, | ||
1028 | unsigned alignment); | ||
1029 | extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur); | ||
1030 | extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, | ||
1031 | unsigned alignment, int best_match); | ||
1032 | extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); | ||
1033 | extern void drm_mm_takedown(drm_mm_t *mm); | ||
1034 | |||
1004 | /* Inline replacements for DRM_IOREMAP macros */ | 1035 | /* Inline replacements for DRM_IOREMAP macros */ |
1005 | static __inline__ void drm_core_ioremap(struct drm_map *map, | 1036 | static __inline__ void drm_core_ioremap(struct drm_map *map, |
1006 | struct drm_device *dev) | 1037 | struct drm_device *dev) |
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c new file mode 100644 index 000000000000..480611395481 --- /dev/null +++ b/drivers/char/drm/drm_hashtab.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. 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 | /* | ||
29 | * Simple open hash tab implementation. | ||
30 | * | ||
31 | * Authors: | ||
32 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
33 | */ | ||
34 | |||
35 | #include "drmP.h" | ||
36 | #include "drm_hashtab.h" | ||
37 | #include <linux/hash.h> | ||
38 | |||
39 | int drm_ht_create(drm_open_hash_t *ht, unsigned int order) | ||
40 | { | ||
41 | unsigned int i; | ||
42 | |||
43 | ht->size = 1 << order; | ||
44 | ht->order = order; | ||
45 | ht->fill = 0; | ||
46 | ht->table = vmalloc(ht->size*sizeof(*ht->table)); | ||
47 | if (!ht->table) { | ||
48 | DRM_ERROR("Out of memory for hash table\n"); | ||
49 | return -ENOMEM; | ||
50 | } | ||
51 | for (i=0; i< ht->size; ++i) { | ||
52 | INIT_HLIST_HEAD(&ht->table[i]); | ||
53 | } | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key) | ||
58 | { | ||
59 | drm_hash_item_t *entry; | ||
60 | struct hlist_head *h_list; | ||
61 | struct hlist_node *list; | ||
62 | unsigned int hashed_key; | ||
63 | int count = 0; | ||
64 | |||
65 | hashed_key = hash_long(key, ht->order); | ||
66 | DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); | ||
67 | h_list = &ht->table[hashed_key]; | ||
68 | hlist_for_each(list, h_list) { | ||
69 | entry = hlist_entry(list, drm_hash_item_t, head); | ||
70 | DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht, | ||
75 | unsigned long key) | ||
76 | { | ||
77 | drm_hash_item_t *entry; | ||
78 | struct hlist_head *h_list; | ||
79 | struct hlist_node *list; | ||
80 | unsigned int hashed_key; | ||
81 | |||
82 | hashed_key = hash_long(key, ht->order); | ||
83 | h_list = &ht->table[hashed_key]; | ||
84 | hlist_for_each(list, h_list) { | ||
85 | entry = hlist_entry(list, drm_hash_item_t, head); | ||
86 | if (entry->key == key) | ||
87 | return list; | ||
88 | if (entry->key > key) | ||
89 | break; | ||
90 | } | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | |||
95 | int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item) | ||
96 | { | ||
97 | drm_hash_item_t *entry; | ||
98 | struct hlist_head *h_list; | ||
99 | struct hlist_node *list, *parent; | ||
100 | unsigned int hashed_key; | ||
101 | unsigned long key = item->key; | ||
102 | |||
103 | hashed_key = hash_long(key, ht->order); | ||
104 | h_list = &ht->table[hashed_key]; | ||
105 | parent = NULL; | ||
106 | hlist_for_each(list, h_list) { | ||
107 | entry = hlist_entry(list, drm_hash_item_t, head); | ||
108 | if (entry->key == key) | ||
109 | return -1; | ||
110 | if (entry->key > key) | ||
111 | break; | ||
112 | parent = list; | ||
113 | } | ||
114 | if (parent) { | ||
115 | hlist_add_after(parent, &item->head); | ||
116 | } else { | ||
117 | hlist_add_head(&item->head, h_list); | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Just insert an item and return any "bits" bit key that hasn't been | ||
124 | * used before. | ||
125 | */ | ||
126 | int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, | ||
127 | unsigned long seed, int bits, int shift, | ||
128 | unsigned long add) | ||
129 | { | ||
130 | int ret; | ||
131 | unsigned long mask = (1 << bits) - 1; | ||
132 | unsigned long first, unshifted_key; | ||
133 | |||
134 | unshifted_key = hash_long(seed, bits); | ||
135 | first = unshifted_key; | ||
136 | do { | ||
137 | item->key = (unshifted_key << shift) + add; | ||
138 | ret = drm_ht_insert_item(ht, item); | ||
139 | if (ret) | ||
140 | unshifted_key = (unshifted_key + 1) & mask; | ||
141 | } while(ret && (unshifted_key != first)); | ||
142 | |||
143 | if (ret) { | ||
144 | DRM_ERROR("Available key bit space exhausted\n"); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, | ||
151 | drm_hash_item_t **item) | ||
152 | { | ||
153 | struct hlist_node *list; | ||
154 | |||
155 | list = drm_ht_find_key(ht, key); | ||
156 | if (!list) | ||
157 | return -1; | ||
158 | |||
159 | *item = hlist_entry(list, drm_hash_item_t, head); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key) | ||
164 | { | ||
165 | struct hlist_node *list; | ||
166 | |||
167 | list = drm_ht_find_key(ht, key); | ||
168 | if (list) { | ||
169 | hlist_del_init(list); | ||
170 | ht->fill--; | ||
171 | return 0; | ||
172 | } | ||
173 | return -1; | ||
174 | } | ||
175 | |||
176 | int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item) | ||
177 | { | ||
178 | hlist_del_init(&item->head); | ||
179 | ht->fill--; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | void drm_ht_remove(drm_open_hash_t *ht) | ||
184 | { | ||
185 | if (ht->table) { | ||
186 | vfree(ht->table); | ||
187 | ht->table = NULL; | ||
188 | } | ||
189 | } | ||
190 | |||
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h new file mode 100644 index 000000000000..40afec05bff8 --- /dev/null +++ b/drivers/char/drm/drm_hashtab.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. 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 | /* | ||
29 | * Simple open hash tab implementation. | ||
30 | * | ||
31 | * Authors: | ||
32 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
33 | */ | ||
34 | |||
35 | #ifndef DRM_HASHTAB_H | ||
36 | #define DRM_HASHTAB_H | ||
37 | |||
38 | #define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) | ||
39 | |||
40 | typedef struct drm_hash_item{ | ||
41 | struct hlist_node head; | ||
42 | unsigned long key; | ||
43 | } drm_hash_item_t; | ||
44 | |||
45 | typedef struct drm_open_hash{ | ||
46 | unsigned int size; | ||
47 | unsigned int order; | ||
48 | unsigned int fill; | ||
49 | struct hlist_head *table; | ||
50 | } drm_open_hash_t; | ||
51 | |||
52 | |||
53 | extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order); | ||
54 | extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item); | ||
55 | extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, | ||
56 | unsigned long seed, int bits, int shift, | ||
57 | unsigned long add); | ||
58 | extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item); | ||
59 | |||
60 | extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key); | ||
61 | extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key); | ||
62 | extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item); | ||
63 | extern void drm_ht_remove(drm_open_hash_t *ht); | ||
64 | |||
65 | |||
66 | #endif | ||
67 | |||
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c new file mode 100644 index 000000000000..c55ed45a8944 --- /dev/null +++ b/drivers/char/drm/drm_mm.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., 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 | |||
29 | /* | ||
30 | * Generic simple memory manager implementation. Intended to be used as a base | ||
31 | * class implementation for more advanced memory managers. | ||
32 | * | ||
33 | * Note that the algorithm used is quite simple and there might be substantial | ||
34 | * performance gains if a smarter free list is implemented. Currently it is just an | ||
35 | * unordered stack of free regions. This could easily be improved if an RB-tree | ||
36 | * is used instead. At least if we expect heavy fragmentation. | ||
37 | * | ||
38 | * Aligned allocations can also see improvement. | ||
39 | * | ||
40 | * Authors: | ||
41 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
42 | */ | ||
43 | |||
44 | #include "drmP.h" | ||
45 | |||
46 | drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, | ||
47 | unsigned long size, unsigned alignment) | ||
48 | { | ||
49 | |||
50 | drm_mm_node_t *child; | ||
51 | |||
52 | if (alignment) | ||
53 | size += alignment - 1; | ||
54 | |||
55 | if (parent->size == size) { | ||
56 | list_del_init(&parent->fl_entry); | ||
57 | parent->free = FALSE; | ||
58 | return parent; | ||
59 | } else { | ||
60 | child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); | ||
61 | if (!child) | ||
62 | return NULL; | ||
63 | |||
64 | INIT_LIST_HEAD(&child->ml_entry); | ||
65 | INIT_LIST_HEAD(&child->fl_entry); | ||
66 | |||
67 | child->free = FALSE; | ||
68 | child->size = size; | ||
69 | child->start = parent->start; | ||
70 | |||
71 | list_add_tail(&child->ml_entry, &parent->ml_entry); | ||
72 | parent->size -= size; | ||
73 | parent->start += size; | ||
74 | } | ||
75 | return child; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Put a block. Merge with the previous and / or next block if they are free. | ||
80 | * Otherwise add to the free stack. | ||
81 | */ | ||
82 | |||
83 | void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) | ||
84 | { | ||
85 | |||
86 | drm_mm_node_t *list_root = &mm->root_node; | ||
87 | struct list_head *cur_head = &cur->ml_entry; | ||
88 | struct list_head *root_head = &list_root->ml_entry; | ||
89 | drm_mm_node_t *prev_node = NULL; | ||
90 | drm_mm_node_t *next_node; | ||
91 | |||
92 | int merged = FALSE; | ||
93 | |||
94 | if (cur_head->prev != root_head) { | ||
95 | prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry); | ||
96 | if (prev_node->free) { | ||
97 | prev_node->size += cur->size; | ||
98 | merged = TRUE; | ||
99 | } | ||
100 | } | ||
101 | if (cur_head->next != root_head) { | ||
102 | next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry); | ||
103 | if (next_node->free) { | ||
104 | if (merged) { | ||
105 | prev_node->size += next_node->size; | ||
106 | list_del(&next_node->ml_entry); | ||
107 | list_del(&next_node->fl_entry); | ||
108 | drm_free(next_node, sizeof(*next_node), | ||
109 | DRM_MEM_MM); | ||
110 | } else { | ||
111 | next_node->size += cur->size; | ||
112 | next_node->start = cur->start; | ||
113 | merged = TRUE; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | if (!merged) { | ||
118 | cur->free = TRUE; | ||
119 | list_add(&cur->fl_entry, &list_root->fl_entry); | ||
120 | } else { | ||
121 | list_del(&cur->ml_entry); | ||
122 | drm_free(cur, sizeof(*cur), DRM_MEM_MM); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, | ||
127 | unsigned long size, | ||
128 | unsigned alignment, int best_match) | ||
129 | { | ||
130 | struct list_head *list; | ||
131 | const struct list_head *free_stack = &mm->root_node.fl_entry; | ||
132 | drm_mm_node_t *entry; | ||
133 | drm_mm_node_t *best; | ||
134 | unsigned long best_size; | ||
135 | |||
136 | best = NULL; | ||
137 | best_size = ~0UL; | ||
138 | |||
139 | if (alignment) | ||
140 | size += alignment - 1; | ||
141 | |||
142 | list_for_each(list, free_stack) { | ||
143 | entry = list_entry(list, drm_mm_node_t, fl_entry); | ||
144 | if (entry->size >= size) { | ||
145 | if (!best_match) | ||
146 | return entry; | ||
147 | if (size < best_size) { | ||
148 | best = entry; | ||
149 | best_size = entry->size; | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return best; | ||
155 | } | ||
156 | |||
157 | int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) | ||
158 | { | ||
159 | drm_mm_node_t *child; | ||
160 | |||
161 | INIT_LIST_HEAD(&mm->root_node.ml_entry); | ||
162 | INIT_LIST_HEAD(&mm->root_node.fl_entry); | ||
163 | child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); | ||
164 | if (!child) | ||
165 | return -ENOMEM; | ||
166 | |||
167 | INIT_LIST_HEAD(&child->ml_entry); | ||
168 | INIT_LIST_HEAD(&child->fl_entry); | ||
169 | |||
170 | child->start = start; | ||
171 | child->size = size; | ||
172 | child->free = TRUE; | ||
173 | |||
174 | list_add(&child->fl_entry, &mm->root_node.fl_entry); | ||
175 | list_add(&child->ml_entry, &mm->root_node.ml_entry); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | EXPORT_SYMBOL(drm_mm_init); | ||
181 | |||
182 | void drm_mm_takedown(drm_mm_t * mm) | ||
183 | { | ||
184 | struct list_head *bnode = mm->root_node.fl_entry.next; | ||
185 | drm_mm_node_t *entry; | ||
186 | |||
187 | entry = list_entry(bnode, drm_mm_node_t, fl_entry); | ||
188 | |||
189 | if (entry->ml_entry.next != &mm->root_node.ml_entry || | ||
190 | entry->fl_entry.next != &mm->root_node.fl_entry) { | ||
191 | DRM_ERROR("Memory manager not clean. Delaying takedown\n"); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | list_del(&entry->fl_entry); | ||
196 | list_del(&entry->ml_entry); | ||
197 | |||
198 | drm_free(entry, sizeof(*entry), DRM_MEM_MM); | ||
199 | } | ||
200 | |||
201 | EXPORT_SYMBOL(drm_mm_takedown); | ||
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c new file mode 100644 index 000000000000..baba91398911 --- /dev/null +++ b/drivers/char/drm/drm_sman.c | |||
@@ -0,0 +1,352 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
18 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
20 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * The above copyright notice and this permission notice (including the | ||
23 | * next paragraph) shall be included in all copies or substantial portions | ||
24 | * of the Software. | ||
25 | * | ||
26 | * | ||
27 | **************************************************************************/ | ||
28 | /* | ||
29 | * Simple memory manager interface that keeps track on allocate regions on a | ||
30 | * per "owner" basis. All regions associated with an "owner" can be released | ||
31 | * with a simple call. Typically if the "owner" exists. The owner is any | ||
32 | * "unsigned long" identifier. Can typically be a pointer to a file private | ||
33 | * struct or a context identifier. | ||
34 | * | ||
35 | * Authors: | ||
36 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
37 | */ | ||
38 | |||
39 | #include "drm_sman.h" | ||
40 | |||
41 | typedef struct drm_owner_item { | ||
42 | drm_hash_item_t owner_hash; | ||
43 | struct list_head sman_list; | ||
44 | struct list_head mem_blocks; | ||
45 | } drm_owner_item_t; | ||
46 | |||
47 | void drm_sman_takedown(drm_sman_t * sman) | ||
48 | { | ||
49 | drm_ht_remove(&sman->user_hash_tab); | ||
50 | drm_ht_remove(&sman->owner_hash_tab); | ||
51 | if (sman->mm) | ||
52 | drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm), | ||
53 | DRM_MEM_MM); | ||
54 | } | ||
55 | |||
56 | EXPORT_SYMBOL(drm_sman_takedown); | ||
57 | |||
58 | int | ||
59 | drm_sman_init(drm_sman_t * sman, unsigned int num_managers, | ||
60 | unsigned int user_order, unsigned int owner_order) | ||
61 | { | ||
62 | int ret = 0; | ||
63 | |||
64 | sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm), | ||
65 | DRM_MEM_MM); | ||
66 | if (!sman->mm) { | ||
67 | ret = -ENOMEM; | ||
68 | goto out; | ||
69 | } | ||
70 | sman->num_managers = num_managers; | ||
71 | INIT_LIST_HEAD(&sman->owner_items); | ||
72 | ret = drm_ht_create(&sman->owner_hash_tab, owner_order); | ||
73 | if (ret) | ||
74 | goto out1; | ||
75 | ret = drm_ht_create(&sman->user_hash_tab, user_order); | ||
76 | if (!ret) | ||
77 | goto out; | ||
78 | |||
79 | drm_ht_remove(&sman->owner_hash_tab); | ||
80 | out1: | ||
81 | drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM); | ||
82 | out: | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | EXPORT_SYMBOL(drm_sman_init); | ||
87 | |||
88 | static void *drm_sman_mm_allocate(void *private, unsigned long size, | ||
89 | unsigned alignment) | ||
90 | { | ||
91 | drm_mm_t *mm = (drm_mm_t *) private; | ||
92 | drm_mm_node_t *tmp; | ||
93 | |||
94 | tmp = drm_mm_search_free(mm, size, alignment, TRUE); | ||
95 | if (!tmp) { | ||
96 | return NULL; | ||
97 | } | ||
98 | tmp = drm_mm_get_block(tmp, size, alignment); | ||
99 | return tmp; | ||
100 | } | ||
101 | |||
102 | static void drm_sman_mm_free(void *private, void *ref) | ||
103 | { | ||
104 | drm_mm_t *mm = (drm_mm_t *) private; | ||
105 | drm_mm_node_t *node = (drm_mm_node_t *) ref; | ||
106 | |||
107 | drm_mm_put_block(mm, node); | ||
108 | } | ||
109 | |||
110 | static void drm_sman_mm_destroy(void *private) | ||
111 | { | ||
112 | drm_mm_t *mm = (drm_mm_t *) private; | ||
113 | drm_mm_takedown(mm); | ||
114 | drm_free(mm, sizeof(*mm), DRM_MEM_MM); | ||
115 | } | ||
116 | |||
117 | unsigned long drm_sman_mm_offset(void *private, void *ref) | ||
118 | { | ||
119 | drm_mm_node_t *node = (drm_mm_node_t *) ref; | ||
120 | return node->start; | ||
121 | } | ||
122 | |||
123 | int | ||
124 | drm_sman_set_range(drm_sman_t * sman, unsigned int manager, | ||
125 | unsigned long start, unsigned long size) | ||
126 | { | ||
127 | drm_sman_mm_t *sman_mm; | ||
128 | drm_mm_t *mm; | ||
129 | int ret; | ||
130 | |||
131 | BUG_ON(manager >= sman->num_managers); | ||
132 | |||
133 | sman_mm = &sman->mm[manager]; | ||
134 | mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM); | ||
135 | if (!mm) { | ||
136 | return -ENOMEM; | ||
137 | } | ||
138 | sman_mm->private = mm; | ||
139 | ret = drm_mm_init(mm, start, size); | ||
140 | |||
141 | if (ret) { | ||
142 | drm_free(mm, sizeof(*mm), DRM_MEM_MM); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | sman_mm->allocate = drm_sman_mm_allocate; | ||
147 | sman_mm->free = drm_sman_mm_free; | ||
148 | sman_mm->destroy = drm_sman_mm_destroy; | ||
149 | sman_mm->offset = drm_sman_mm_offset; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | EXPORT_SYMBOL(drm_sman_set_range); | ||
155 | |||
156 | int | ||
157 | drm_sman_set_manager(drm_sman_t * sman, unsigned int manager, | ||
158 | drm_sman_mm_t * allocator) | ||
159 | { | ||
160 | BUG_ON(manager >= sman->num_managers); | ||
161 | sman->mm[manager] = *allocator; | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman, | ||
167 | unsigned long owner) | ||
168 | { | ||
169 | int ret; | ||
170 | drm_hash_item_t *owner_hash_item; | ||
171 | drm_owner_item_t *owner_item; | ||
172 | |||
173 | ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item); | ||
174 | if (!ret) { | ||
175 | return drm_hash_entry(owner_hash_item, drm_owner_item_t, | ||
176 | owner_hash); | ||
177 | } | ||
178 | |||
179 | owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM); | ||
180 | if (!owner_item) | ||
181 | goto out; | ||
182 | |||
183 | INIT_LIST_HEAD(&owner_item->mem_blocks); | ||
184 | owner_item->owner_hash.key = owner; | ||
185 | if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash)) | ||
186 | goto out1; | ||
187 | |||
188 | list_add_tail(&owner_item->sman_list, &sman->owner_items); | ||
189 | return owner_item; | ||
190 | |||
191 | out1: | ||
192 | drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); | ||
193 | out: | ||
194 | return NULL; | ||
195 | } | ||
196 | |||
197 | drm_memblock_item_t *drm_sman_alloc(drm_sman_t *sman, unsigned int manager, | ||
198 | unsigned long size, unsigned alignment, | ||
199 | unsigned long owner) | ||
200 | { | ||
201 | void *tmp; | ||
202 | drm_sman_mm_t *sman_mm; | ||
203 | drm_owner_item_t *owner_item; | ||
204 | drm_memblock_item_t *memblock; | ||
205 | |||
206 | BUG_ON(manager >= sman->num_managers); | ||
207 | |||
208 | sman_mm = &sman->mm[manager]; | ||
209 | tmp = sman_mm->allocate(sman_mm->private, size, alignment); | ||
210 | |||
211 | if (!tmp) { | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM); | ||
216 | |||
217 | if (!memblock) | ||
218 | goto out; | ||
219 | |||
220 | memblock->mm_info = tmp; | ||
221 | memblock->mm = sman_mm; | ||
222 | memblock->sman = sman; | ||
223 | |||
224 | if (drm_ht_just_insert_please | ||
225 | (&sman->user_hash_tab, &memblock->user_hash, | ||
226 | (unsigned long)memblock, 32, 0, 0)) | ||
227 | goto out1; | ||
228 | |||
229 | owner_item = drm_sman_get_owner_item(sman, owner); | ||
230 | if (!owner_item) | ||
231 | goto out2; | ||
232 | |||
233 | list_add_tail(&memblock->owner_list, &owner_item->mem_blocks); | ||
234 | |||
235 | return memblock; | ||
236 | |||
237 | out2: | ||
238 | drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash); | ||
239 | out1: | ||
240 | drm_free(memblock, sizeof(*memblock), DRM_MEM_MM); | ||
241 | out: | ||
242 | sman_mm->free(sman_mm->private, tmp); | ||
243 | |||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | EXPORT_SYMBOL(drm_sman_alloc); | ||
248 | |||
249 | static void drm_sman_free(drm_memblock_item_t *item) | ||
250 | { | ||
251 | drm_sman_t *sman = item->sman; | ||
252 | |||
253 | list_del(&item->owner_list); | ||
254 | drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash); | ||
255 | item->mm->free(item->mm->private, item->mm_info); | ||
256 | drm_free(item, sizeof(*item), DRM_MEM_MM); | ||
257 | } | ||
258 | |||
259 | int drm_sman_free_key(drm_sman_t *sman, unsigned int key) | ||
260 | { | ||
261 | drm_hash_item_t *hash_item; | ||
262 | drm_memblock_item_t *memblock_item; | ||
263 | |||
264 | if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item)) | ||
265 | return -EINVAL; | ||
266 | |||
267 | memblock_item = drm_hash_entry(hash_item, drm_memblock_item_t, user_hash); | ||
268 | drm_sman_free(memblock_item); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | EXPORT_SYMBOL(drm_sman_free_key); | ||
273 | |||
274 | static void drm_sman_remove_owner(drm_sman_t *sman, | ||
275 | drm_owner_item_t *owner_item) | ||
276 | { | ||
277 | list_del(&owner_item->sman_list); | ||
278 | drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash); | ||
279 | drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); | ||
280 | } | ||
281 | |||
282 | int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner) | ||
283 | { | ||
284 | |||
285 | drm_hash_item_t *hash_item; | ||
286 | drm_owner_item_t *owner_item; | ||
287 | |||
288 | if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { | ||
289 | return -1; | ||
290 | } | ||
291 | |||
292 | owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash); | ||
293 | if (owner_item->mem_blocks.next == &owner_item->mem_blocks) { | ||
294 | drm_sman_remove_owner(sman, owner_item); | ||
295 | return -1; | ||
296 | } | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | EXPORT_SYMBOL(drm_sman_owner_clean); | ||
302 | |||
303 | static void drm_sman_do_owner_cleanup(drm_sman_t *sman, | ||
304 | drm_owner_item_t *owner_item) | ||
305 | { | ||
306 | drm_memblock_item_t *entry, *next; | ||
307 | |||
308 | list_for_each_entry_safe(entry, next, &owner_item->mem_blocks, | ||
309 | owner_list) { | ||
310 | drm_sman_free(entry); | ||
311 | } | ||
312 | drm_sman_remove_owner(sman, owner_item); | ||
313 | } | ||
314 | |||
315 | void drm_sman_owner_cleanup(drm_sman_t *sman, unsigned long owner) | ||
316 | { | ||
317 | |||
318 | drm_hash_item_t *hash_item; | ||
319 | drm_owner_item_t *owner_item; | ||
320 | |||
321 | if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { | ||
322 | |||
323 | return; | ||
324 | } | ||
325 | |||
326 | owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash); | ||
327 | drm_sman_do_owner_cleanup(sman, owner_item); | ||
328 | } | ||
329 | |||
330 | EXPORT_SYMBOL(drm_sman_owner_cleanup); | ||
331 | |||
332 | void drm_sman_cleanup(drm_sman_t *sman) | ||
333 | { | ||
334 | drm_owner_item_t *entry, *next; | ||
335 | unsigned int i; | ||
336 | drm_sman_mm_t *sman_mm; | ||
337 | |||
338 | list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) { | ||
339 | drm_sman_do_owner_cleanup(sman, entry); | ||
340 | } | ||
341 | if (sman->mm) { | ||
342 | for (i = 0; i < sman->num_managers; ++i) { | ||
343 | sman_mm = &sman->mm[i]; | ||
344 | if (sman_mm->private) { | ||
345 | sman_mm->destroy(sman_mm->private); | ||
346 | sman_mm->private = NULL; | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | |||
352 | EXPORT_SYMBOL(drm_sman_cleanup); | ||
diff --git a/drivers/char/drm/drm_sman.h b/drivers/char/drm/drm_sman.h new file mode 100644 index 000000000000..7c48360f114e --- /dev/null +++ b/drivers/char/drm/drm_sman.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., 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 | /* | ||
29 | * Simple memory MANager interface that keeps track on allocate regions on a | ||
30 | * per "owner" basis. All regions associated with an "owner" can be released | ||
31 | * with a simple call. Typically if the "owner" exists. The owner is any | ||
32 | * "unsigned long" identifier. Can typically be a pointer to a file private | ||
33 | * struct or a context identifier. | ||
34 | * | ||
35 | * Authors: | ||
36 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
37 | */ | ||
38 | |||
39 | #ifndef DRM_SMAN_H | ||
40 | #define DRM_SMAN_H | ||
41 | |||
42 | #include "drmP.h" | ||
43 | #include "drm_hashtab.h" | ||
44 | |||
45 | /* | ||
46 | * A class that is an abstration of a simple memory allocator. | ||
47 | * The sman implementation provides a default such allocator | ||
48 | * using the drm_mm.c implementation. But the user can replace it. | ||
49 | * See the SiS implementation, which may use the SiS FB kernel module | ||
50 | * for memory management. | ||
51 | */ | ||
52 | |||
53 | typedef struct drm_sman_mm { | ||
54 | /* private info. If allocated, needs to be destroyed by the destroy | ||
55 | function */ | ||
56 | void *private; | ||
57 | |||
58 | /* Allocate a memory block with given size and alignment. | ||
59 | Return an opaque reference to the memory block */ | ||
60 | |||
61 | void *(*allocate) (void *private, unsigned long size, | ||
62 | unsigned alignment); | ||
63 | |||
64 | /* Free a memory block. "ref" is the opaque reference that we got from | ||
65 | the "alloc" function */ | ||
66 | |||
67 | void (*free) (void *private, void *ref); | ||
68 | |||
69 | /* Free all resources associated with this allocator */ | ||
70 | |||
71 | void (*destroy) (void *private); | ||
72 | |||
73 | /* Return a memory offset from the opaque reference returned from the | ||
74 | "alloc" function */ | ||
75 | |||
76 | unsigned long (*offset) (void *private, void *ref); | ||
77 | } drm_sman_mm_t; | ||
78 | |||
79 | typedef struct drm_memblock_item { | ||
80 | struct list_head owner_list; | ||
81 | drm_hash_item_t user_hash; | ||
82 | void *mm_info; | ||
83 | drm_sman_mm_t *mm; | ||
84 | struct drm_sman *sman; | ||
85 | } drm_memblock_item_t; | ||
86 | |||
87 | typedef struct drm_sman { | ||
88 | drm_sman_mm_t *mm; | ||
89 | int num_managers; | ||
90 | drm_open_hash_t owner_hash_tab; | ||
91 | drm_open_hash_t user_hash_tab; | ||
92 | struct list_head owner_items; | ||
93 | } drm_sman_t; | ||
94 | |||
95 | /* | ||
96 | * Take down a memory manager. This function should only be called after a | ||
97 | * successful init and after a call to drm_sman_cleanup. | ||
98 | */ | ||
99 | |||
100 | extern void drm_sman_takedown(drm_sman_t * sman); | ||
101 | |||
102 | /* | ||
103 | * Allocate structures for a manager. | ||
104 | * num_managers are the number of memory pools to manage. (VRAM, AGP, ....) | ||
105 | * user_order is the log2 of the number of buckets in the user hash table. | ||
106 | * set this to approximately log2 of the max number of memory regions | ||
107 | * that will be allocated for _all_ pools together. | ||
108 | * owner_order is the log2 of the number of buckets in the owner hash table. | ||
109 | * set this to approximately log2 of | ||
110 | * the number of client file connections that will | ||
111 | * be using the manager. | ||
112 | * | ||
113 | */ | ||
114 | |||
115 | extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers, | ||
116 | unsigned int user_order, unsigned int owner_order); | ||
117 | |||
118 | /* | ||
119 | * Initialize a drm_mm.c allocator. Should be called only once for each | ||
120 | * manager unless a customized allogator is used. | ||
121 | */ | ||
122 | |||
123 | extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager, | ||
124 | unsigned long start, unsigned long size); | ||
125 | |||
126 | /* | ||
127 | * Initialize a customized allocator for one of the managers. | ||
128 | * (See the SiS module). The object pointed to by "allocator" is copied, | ||
129 | * so it can be destroyed after this call. | ||
130 | */ | ||
131 | |||
132 | extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger, | ||
133 | drm_sman_mm_t * allocator); | ||
134 | |||
135 | /* | ||
136 | * Allocate a memory block. Aligment is not implemented yet. | ||
137 | */ | ||
138 | |||
139 | extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman, | ||
140 | unsigned int manager, | ||
141 | unsigned long size, | ||
142 | unsigned alignment, | ||
143 | unsigned long owner); | ||
144 | /* | ||
145 | * Free a memory block identified by its user hash key. | ||
146 | */ | ||
147 | |||
148 | extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key); | ||
149 | |||
150 | /* | ||
151 | * returns TRUE iff there are no stale memory blocks associated with this owner. | ||
152 | * Typically called to determine if we need to idle the hardware and call | ||
153 | * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all | ||
154 | * resources associated with owner. | ||
155 | */ | ||
156 | |||
157 | extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner); | ||
158 | |||
159 | /* | ||
160 | * Frees all stale memory blocks associated with this owner. Note that this | ||
161 | * requires that the hardware is finished with all blocks, so the graphics engine | ||
162 | * should be idled before this call is made. This function also frees | ||
163 | * any resources associated with "owner" and should be called when owner | ||
164 | * is not going to be referenced anymore. | ||
165 | */ | ||
166 | |||
167 | extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner); | ||
168 | |||
169 | /* | ||
170 | * Frees all stale memory blocks associated with the memory manager. | ||
171 | * See idling above. | ||
172 | */ | ||
173 | |||
174 | extern void drm_sman_cleanup(drm_sman_t * sman); | ||
175 | |||
176 | #endif | ||