aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp/generic.c
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas@tungstengraphics.com>2007-01-23 04:33:43 -0500
committerDave Jones <davej@redhat.com>2007-02-03 17:16:24 -0500
commita030ce4477baa06dd9c037ccd3c8d171aac9ed44 (patch)
tree1961f175a2785cc7d5325f45139558de471c4733 /drivers/char/agp/generic.c
parent0316fe8319ff62e527d0d91a3bc7df1c59eafae8 (diff)
[AGPGART] Allow drm-populated agp memory types
This patch allows drm to populate an agpgart structure with pages of its own. It's needed for the new drm memory manager which dynamically flips pages in and out of AGP. The patch modifies the generic functions as well as the intel agp driver. The intel drm driver is currently the only one supporting the new memory manager. Other agp drivers may need some minor fixing up once they have a corresponding memory manager enabled drm driver. AGP memory types >= AGP_USER_TYPES are not populated by the agpgart driver, but the drm is expected to do that, as well as taking care of cache- and tlb flushing when needed. It's not possible to request these types from user space using agpgart ioctls. The Intel driver also gets a new memory type for pages that can be bound cached to the intel GTT. Signed-off-by: Thomas Hellstrom <thomas@tungstengraphics.com> Signed-off-by: Dave Jones <davej@redhat.com>
Diffstat (limited to 'drivers/char/agp/generic.c')
-rw-r--r--drivers/char/agp/generic.c130
1 files changed, 124 insertions, 6 deletions
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3491d6f84bc6..a627b771c2eb 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -101,6 +101,67 @@ static int agp_get_key(void)
101 return -1; 101 return -1;
102} 102}
103 103
104/*
105 * Use kmalloc if possible for the page list. Otherwise fall back to
106 * vmalloc. This speeds things up and also saves memory for small AGP
107 * regions.
108 */
109
110void agp_alloc_page_array(size_t size, struct agp_memory *mem)
111{
112 mem->memory = NULL;
113 mem->vmalloc_flag = 0;
114
115 if (size <= 2*PAGE_SIZE) {
116 mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
117 }
118 if (mem->memory == NULL) {
119 mem->memory = vmalloc(size);
120 mem->vmalloc_flag = 1;
121 }
122}
123EXPORT_SYMBOL(agp_alloc_page_array);
124
125void agp_free_page_array(struct agp_memory *mem)
126{
127 if (mem->vmalloc_flag) {
128 vfree(mem->memory);
129 } else {
130 kfree(mem->memory);
131 }
132}
133EXPORT_SYMBOL(agp_free_page_array);
134
135
136static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
137{
138 struct agp_memory *new;
139 unsigned long alloc_size = num_agp_pages*sizeof(struct page *);
140
141 new = kmalloc(sizeof(struct agp_memory), GFP_KERNEL);
142
143 if (new == NULL)
144 return NULL;
145
146 memset(new, 0, sizeof(struct agp_memory));
147 new->key = agp_get_key();
148
149 if (new->key < 0) {
150 kfree(new);
151 return NULL;
152 }
153
154 agp_alloc_page_array(alloc_size, new);
155
156 if (new->memory == NULL) {
157 agp_free_key(new->key);
158 kfree(new);
159 return NULL;
160 }
161 new->num_scratch_pages = 0;
162 return new;
163}
164
104 165
105struct agp_memory *agp_create_memory(int scratch_pages) 166struct agp_memory *agp_create_memory(int scratch_pages)
106{ 167{
@@ -116,7 +177,8 @@ struct agp_memory *agp_create_memory(int scratch_pages)
116 kfree(new); 177 kfree(new);
117 return NULL; 178 return NULL;
118 } 179 }
119 new->memory = vmalloc(PAGE_SIZE * scratch_pages); 180
181 agp_alloc_page_array(PAGE_SIZE * scratch_pages, new);
120 182
121 if (new->memory == NULL) { 183 if (new->memory == NULL) {
122 agp_free_key(new->key); 184 agp_free_key(new->key);
@@ -124,6 +186,7 @@ struct agp_memory *agp_create_memory(int scratch_pages)
124 return NULL; 186 return NULL;
125 } 187 }
126 new->num_scratch_pages = scratch_pages; 188 new->num_scratch_pages = scratch_pages;
189 new->type = AGP_NORMAL_MEMORY;
127 return new; 190 return new;
128} 191}
129EXPORT_SYMBOL(agp_create_memory); 192EXPORT_SYMBOL(agp_create_memory);
@@ -146,6 +209,11 @@ void agp_free_memory(struct agp_memory *curr)
146 if (curr->is_bound == TRUE) 209 if (curr->is_bound == TRUE)
147 agp_unbind_memory(curr); 210 agp_unbind_memory(curr);
148 211
212 if (curr->type >= AGP_USER_TYPES) {
213 agp_generic_free_by_type(curr);
214 return;
215 }
216
149 if (curr->type != 0) { 217 if (curr->type != 0) {
150 curr->bridge->driver->free_by_type(curr); 218 curr->bridge->driver->free_by_type(curr);
151 return; 219 return;
@@ -157,7 +225,7 @@ void agp_free_memory(struct agp_memory *curr)
157 flush_agp_mappings(); 225 flush_agp_mappings();
158 } 226 }
159 agp_free_key(curr->key); 227 agp_free_key(curr->key);
160 vfree(curr->memory); 228 agp_free_page_array(curr);
161 kfree(curr); 229 kfree(curr);
162} 230}
163EXPORT_SYMBOL(agp_free_memory); 231EXPORT_SYMBOL(agp_free_memory);
@@ -188,6 +256,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
188 if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp) 256 if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp)
189 return NULL; 257 return NULL;
190 258
259 if (type >= AGP_USER_TYPES) {
260 new = agp_generic_alloc_user(page_count, type);
261 if (new)
262 new->bridge = bridge;
263 return new;
264 }
265
191 if (type != 0) { 266 if (type != 0) {
192 new = bridge->driver->alloc_by_type(page_count, type); 267 new = bridge->driver->alloc_by_type(page_count, type);
193 if (new) 268 if (new)
@@ -960,6 +1035,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
960 off_t j; 1035 off_t j;
961 void *temp; 1036 void *temp;
962 struct agp_bridge_data *bridge; 1037 struct agp_bridge_data *bridge;
1038 int mask_type;
963 1039
964 bridge = mem->bridge; 1040 bridge = mem->bridge;
965 if (!bridge) 1041 if (!bridge)
@@ -995,7 +1071,12 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
995 num_entries -= agp_memory_reserved/PAGE_SIZE; 1071 num_entries -= agp_memory_reserved/PAGE_SIZE;
996 if (num_entries < 0) num_entries = 0; 1072 if (num_entries < 0) num_entries = 0;
997 1073
998 if (type != 0 || mem->type != 0) { 1074 if (type != mem->type) {
1075 return -EINVAL;
1076 }
1077
1078 mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
1079 if (mask_type != 0) {
999 /* The generic routines know nothing of memory types */ 1080 /* The generic routines know nothing of memory types */
1000 return -EINVAL; 1081 return -EINVAL;
1001 } 1082 }
@@ -1018,7 +1099,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
1018 } 1099 }
1019 1100
1020 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 1101 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
1021 writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j); 1102 writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type),
1103 bridge->gatt_table+j);
1022 } 1104 }
1023 readl(bridge->gatt_table+j-1); /* PCI Posting. */ 1105 readl(bridge->gatt_table+j-1); /* PCI Posting. */
1024 1106
@@ -1032,6 +1114,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
1032{ 1114{
1033 size_t i; 1115 size_t i;
1034 struct agp_bridge_data *bridge; 1116 struct agp_bridge_data *bridge;
1117 int mask_type;
1035 1118
1036 bridge = mem->bridge; 1119 bridge = mem->bridge;
1037 if (!bridge) 1120 if (!bridge)
@@ -1040,7 +1123,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
1040 if (mem->page_count == 0) 1123 if (mem->page_count == 0)
1041 return 0; 1124 return 0;
1042 1125
1043 if (type != 0 || mem->type != 0) { 1126 if (type != mem->type)
1127 return -EINVAL;
1128
1129 mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
1130 if (mask_type != 0) {
1044 /* The generic routines know nothing of memory types */ 1131 /* The generic routines know nothing of memory types */
1045 return -EINVAL; 1132 return -EINVAL;
1046 } 1133 }
@@ -1066,12 +1153,34 @@ EXPORT_SYMBOL(agp_generic_alloc_by_type);
1066 1153
1067void agp_generic_free_by_type(struct agp_memory *curr) 1154void agp_generic_free_by_type(struct agp_memory *curr)
1068{ 1155{
1069 vfree(curr->memory); 1156 agp_free_page_array(curr);
1070 agp_free_key(curr->key); 1157 agp_free_key(curr->key);
1071 kfree(curr); 1158 kfree(curr);
1072} 1159}
1073EXPORT_SYMBOL(agp_generic_free_by_type); 1160EXPORT_SYMBOL(agp_generic_free_by_type);
1074 1161
1162struct agp_memory *agp_generic_alloc_user(size_t page_count, int type)
1163{
1164 struct agp_memory *new;
1165 int i;
1166 int pages;
1167
1168 pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
1169 new = agp_create_user_memory(page_count);
1170 if (new == NULL)
1171 return NULL;
1172
1173 for (i = 0; i < page_count; i++) {
1174 new->memory[i] = 0;
1175 }
1176 new->page_count = 0;
1177 new->type = type;
1178 new->num_scratch_pages = pages;
1179
1180 return new;
1181}
1182EXPORT_SYMBOL(agp_generic_alloc_user);
1183
1075 1184
1076/* 1185/*
1077 * Basic Page Allocation Routines - 1186 * Basic Page Allocation Routines -
@@ -1165,6 +1274,15 @@ unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
1165} 1274}
1166EXPORT_SYMBOL(agp_generic_mask_memory); 1275EXPORT_SYMBOL(agp_generic_mask_memory);
1167 1276
1277int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
1278 int type)
1279{
1280 if (type >= AGP_USER_TYPES)
1281 return 0;
1282 return type;
1283}
1284EXPORT_SYMBOL(agp_generic_type_to_mask_type);
1285
1168/* 1286/*
1169 * These functions are implemented according to the AGPv3 spec, 1287 * These functions are implemented according to the AGPv3 spec,
1170 * which covers implementation details that had previously been 1288 * which covers implementation details that had previously been