aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp/generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/agp/generic.c')
-rw-r--r--drivers/char/agp/generic.c125
1 files changed, 117 insertions, 8 deletions
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3491d6f84bc6..7923337c3d26 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -101,6 +101,63 @@ 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 if (mem->memory == NULL) {
118 mem->memory = vmalloc(size);
119 mem->vmalloc_flag = 1;
120 }
121}
122EXPORT_SYMBOL(agp_alloc_page_array);
123
124void agp_free_page_array(struct agp_memory *mem)
125{
126 if (mem->vmalloc_flag) {
127 vfree(mem->memory);
128 } else {
129 kfree(mem->memory);
130 }
131}
132EXPORT_SYMBOL(agp_free_page_array);
133
134
135static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
136{
137 struct agp_memory *new;
138 unsigned long alloc_size = num_agp_pages*sizeof(struct page *);
139
140 new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL);
141 if (new == NULL)
142 return NULL;
143
144 new->key = agp_get_key();
145
146 if (new->key < 0) {
147 kfree(new);
148 return NULL;
149 }
150
151 agp_alloc_page_array(alloc_size, new);
152
153 if (new->memory == NULL) {
154 agp_free_key(new->key);
155 kfree(new);
156 return NULL;
157 }
158 new->num_scratch_pages = 0;
159 return new;
160}
104 161
105struct agp_memory *agp_create_memory(int scratch_pages) 162struct agp_memory *agp_create_memory(int scratch_pages)
106{ 163{
@@ -116,7 +173,8 @@ struct agp_memory *agp_create_memory(int scratch_pages)
116 kfree(new); 173 kfree(new);
117 return NULL; 174 return NULL;
118 } 175 }
119 new->memory = vmalloc(PAGE_SIZE * scratch_pages); 176
177 agp_alloc_page_array(PAGE_SIZE * scratch_pages, new);
120 178
121 if (new->memory == NULL) { 179 if (new->memory == NULL) {
122 agp_free_key(new->key); 180 agp_free_key(new->key);
@@ -124,6 +182,7 @@ struct agp_memory *agp_create_memory(int scratch_pages)
124 return NULL; 182 return NULL;
125 } 183 }
126 new->num_scratch_pages = scratch_pages; 184 new->num_scratch_pages = scratch_pages;
185 new->type = AGP_NORMAL_MEMORY;
127 return new; 186 return new;
128} 187}
129EXPORT_SYMBOL(agp_create_memory); 188EXPORT_SYMBOL(agp_create_memory);
@@ -146,6 +205,11 @@ void agp_free_memory(struct agp_memory *curr)
146 if (curr->is_bound == TRUE) 205 if (curr->is_bound == TRUE)
147 agp_unbind_memory(curr); 206 agp_unbind_memory(curr);
148 207
208 if (curr->type >= AGP_USER_TYPES) {
209 agp_generic_free_by_type(curr);
210 return;
211 }
212
149 if (curr->type != 0) { 213 if (curr->type != 0) {
150 curr->bridge->driver->free_by_type(curr); 214 curr->bridge->driver->free_by_type(curr);
151 return; 215 return;
@@ -157,7 +221,7 @@ void agp_free_memory(struct agp_memory *curr)
157 flush_agp_mappings(); 221 flush_agp_mappings();
158 } 222 }
159 agp_free_key(curr->key); 223 agp_free_key(curr->key);
160 vfree(curr->memory); 224 agp_free_page_array(curr);
161 kfree(curr); 225 kfree(curr);
162} 226}
163EXPORT_SYMBOL(agp_free_memory); 227EXPORT_SYMBOL(agp_free_memory);
@@ -188,6 +252,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) 252 if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp)
189 return NULL; 253 return NULL;
190 254
255 if (type >= AGP_USER_TYPES) {
256 new = agp_generic_alloc_user(page_count, type);
257 if (new)
258 new->bridge = bridge;
259 return new;
260 }
261
191 if (type != 0) { 262 if (type != 0) {
192 new = bridge->driver->alloc_by_type(page_count, type); 263 new = bridge->driver->alloc_by_type(page_count, type);
193 if (new) 264 if (new)
@@ -960,6 +1031,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
960 off_t j; 1031 off_t j;
961 void *temp; 1032 void *temp;
962 struct agp_bridge_data *bridge; 1033 struct agp_bridge_data *bridge;
1034 int mask_type;
963 1035
964 bridge = mem->bridge; 1036 bridge = mem->bridge;
965 if (!bridge) 1037 if (!bridge)
@@ -995,7 +1067,11 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
995 num_entries -= agp_memory_reserved/PAGE_SIZE; 1067 num_entries -= agp_memory_reserved/PAGE_SIZE;
996 if (num_entries < 0) num_entries = 0; 1068 if (num_entries < 0) num_entries = 0;
997 1069
998 if (type != 0 || mem->type != 0) { 1070 if (type != mem->type)
1071 return -EINVAL;
1072
1073 mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
1074 if (mask_type != 0) {
999 /* The generic routines know nothing of memory types */ 1075 /* The generic routines know nothing of memory types */
1000 return -EINVAL; 1076 return -EINVAL;
1001 } 1077 }
@@ -1018,7 +1094,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
1018 } 1094 }
1019 1095
1020 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 1096 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); 1097 writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type),
1098 bridge->gatt_table+j);
1022 } 1099 }
1023 readl(bridge->gatt_table+j-1); /* PCI Posting. */ 1100 readl(bridge->gatt_table+j-1); /* PCI Posting. */
1024 1101
@@ -1032,6 +1109,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
1032{ 1109{
1033 size_t i; 1110 size_t i;
1034 struct agp_bridge_data *bridge; 1111 struct agp_bridge_data *bridge;
1112 int mask_type;
1035 1113
1036 bridge = mem->bridge; 1114 bridge = mem->bridge;
1037 if (!bridge) 1115 if (!bridge)
@@ -1040,7 +1118,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
1040 if (mem->page_count == 0) 1118 if (mem->page_count == 0)
1041 return 0; 1119 return 0;
1042 1120
1043 if (type != 0 || mem->type != 0) { 1121 if (type != mem->type)
1122 return -EINVAL;
1123
1124 mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
1125 if (mask_type != 0) {
1044 /* The generic routines know nothing of memory types */ 1126 /* The generic routines know nothing of memory types */
1045 return -EINVAL; 1127 return -EINVAL;
1046 } 1128 }
@@ -1056,22 +1138,40 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
1056} 1138}
1057EXPORT_SYMBOL(agp_generic_remove_memory); 1139EXPORT_SYMBOL(agp_generic_remove_memory);
1058 1140
1059
1060struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) 1141struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type)
1061{ 1142{
1062 return NULL; 1143 return NULL;
1063} 1144}
1064EXPORT_SYMBOL(agp_generic_alloc_by_type); 1145EXPORT_SYMBOL(agp_generic_alloc_by_type);
1065 1146
1066
1067void agp_generic_free_by_type(struct agp_memory *curr) 1147void agp_generic_free_by_type(struct agp_memory *curr)
1068{ 1148{
1069 vfree(curr->memory); 1149 agp_free_page_array(curr);
1070 agp_free_key(curr->key); 1150 agp_free_key(curr->key);
1071 kfree(curr); 1151 kfree(curr);
1072} 1152}
1073EXPORT_SYMBOL(agp_generic_free_by_type); 1153EXPORT_SYMBOL(agp_generic_free_by_type);
1074 1154
1155struct agp_memory *agp_generic_alloc_user(size_t page_count, int type)
1156{
1157 struct agp_memory *new;
1158 int i;
1159 int pages;
1160
1161 pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
1162 new = agp_create_user_memory(page_count);
1163 if (new == NULL)
1164 return NULL;
1165
1166 for (i = 0; i < page_count; i++)
1167 new->memory[i] = 0;
1168 new->page_count = 0;
1169 new->type = type;
1170 new->num_scratch_pages = pages;
1171
1172 return new;
1173}
1174EXPORT_SYMBOL(agp_generic_alloc_user);
1075 1175
1076/* 1176/*
1077 * Basic Page Allocation Routines - 1177 * Basic Page Allocation Routines -
@@ -1165,6 +1265,15 @@ unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
1165} 1265}
1166EXPORT_SYMBOL(agp_generic_mask_memory); 1266EXPORT_SYMBOL(agp_generic_mask_memory);
1167 1267
1268int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
1269 int type)
1270{
1271 if (type >= AGP_USER_TYPES)
1272 return 0;
1273 return type;
1274}
1275EXPORT_SYMBOL(agp_generic_type_to_mask_type);
1276
1168/* 1277/*
1169 * These functions are implemented according to the AGPv3 spec, 1278 * These functions are implemented according to the AGPv3 spec,
1170 * which covers implementation details that had previously been 1279 * which covers implementation details that had previously been