Branch data Line data Source code
1 : : /*
2 : : * AGPGART driver frontend
3 : : * Copyright (C) 2004 Silicon Graphics, Inc.
4 : : * Copyright (C) 2002-2003 Dave Jones
5 : : * Copyright (C) 1999 Jeff Hartmann
6 : : * Copyright (C) 1999 Precision Insight, Inc.
7 : : * Copyright (C) 1999 Xi Graphics, Inc.
8 : : *
9 : : * Permission is hereby granted, free of charge, to any person obtaining a
10 : : * copy of this software and associated documentation files (the "Software"),
11 : : * to deal in the Software without restriction, including without limitation
12 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : : * and/or sell copies of the Software, and to permit persons to whom the
14 : : * Software is furnished to do so, subject to the following conditions:
15 : : *
16 : : * The above copyright notice and this permission notice shall be included
17 : : * in all copies or substantial portions of the Software.
18 : : *
19 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : : * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
23 : : * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 : : * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25 : : * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 : : *
27 : : */
28 : :
29 : : #include <linux/types.h>
30 : : #include <linux/kernel.h>
31 : : #include <linux/module.h>
32 : : #include <linux/mman.h>
33 : : #include <linux/pci.h>
34 : : #include <linux/miscdevice.h>
35 : : #include <linux/agp_backend.h>
36 : : #include <linux/agpgart.h>
37 : : #include <linux/slab.h>
38 : : #include <linux/mm.h>
39 : : #include <linux/fs.h>
40 : : #include <linux/sched.h>
41 : : #include <linux/uaccess.h>
42 : : #include <asm/pgtable.h>
43 : : #include "agp.h"
44 : :
45 : : struct agp_front_data agp_fe;
46 : :
47 : 0 : struct agp_memory *agp_find_mem_by_key(int key)
48 : : {
49 : 0 : struct agp_memory *curr;
50 : :
51 [ # # ]: 0 : if (agp_fe.current_controller == NULL)
52 : : return NULL;
53 : :
54 : 0 : curr = agp_fe.current_controller->pool;
55 : :
56 [ # # # # : 0 : while (curr != NULL) {
# # ]
57 [ # # # # : 0 : if (curr->key == key)
# # ]
58 : : break;
59 : 0 : curr = curr->next;
60 : : }
61 : :
62 : : DBG("key=%d -> mem=%p", key, curr);
63 : : return curr;
64 : : }
65 : :
66 : 0 : static void agp_remove_from_pool(struct agp_memory *temp)
67 : : {
68 : 0 : struct agp_memory *prev;
69 : 0 : struct agp_memory *next;
70 : :
71 : : /* Check to see if this is even in the memory pool */
72 : :
73 : 0 : DBG("mem=%p", temp);
74 [ # # # # ]: 0 : if (agp_find_mem_by_key(temp->key) != NULL) {
75 : 0 : next = temp->next;
76 : 0 : prev = temp->prev;
77 : :
78 [ # # ]: 0 : if (prev != NULL) {
79 : 0 : prev->next = next;
80 [ # # ]: 0 : if (next != NULL)
81 : 0 : next->prev = prev;
82 : :
83 : : } else {
84 : : /* This is the first item on the list */
85 [ # # ]: 0 : if (next != NULL)
86 : 0 : next->prev = NULL;
87 : :
88 : 0 : agp_fe.current_controller->pool = next;
89 : : }
90 : : }
91 : 0 : }
92 : :
93 : : /*
94 : : * Routines for managing each client's segment list -
95 : : * These routines handle adding and removing segments
96 : : * to each auth'ed client.
97 : : */
98 : :
99 : : static struct
100 : 0 : agp_segment_priv *agp_find_seg_in_client(const struct agp_client *client,
101 : : unsigned long offset,
102 : : int size, pgprot_t page_prot)
103 : : {
104 : 0 : struct agp_segment_priv *seg;
105 : 0 : int i;
106 : 0 : off_t pg_start;
107 : 0 : size_t pg_count;
108 : :
109 : 0 : pg_start = offset / 4096;
110 : 0 : pg_count = size / 4096;
111 : 0 : seg = *(client->segments);
112 : :
113 [ # # ]: 0 : for (i = 0; i < client->num_segments; i++) {
114 [ # # ]: 0 : if ((seg[i].pg_start == pg_start) &&
115 [ # # ]: 0 : (seg[i].pg_count == pg_count) &&
116 [ # # ]: 0 : (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) {
117 : : return seg + i;
118 : : }
119 : : }
120 : :
121 : : return NULL;
122 : : }
123 : :
124 : : static void agp_remove_seg_from_client(struct agp_client *client)
125 : : {
126 : : DBG("client=%p", client);
127 : :
128 : : if (client->segments != NULL) {
129 : : if (*(client->segments) != NULL) {
130 : : DBG("Freeing %p from client %p", *(client->segments), client);
131 : : kfree(*(client->segments));
132 : : }
133 : : DBG("Freeing %p from client %p", client->segments, client);
134 : : kfree(client->segments);
135 : : client->segments = NULL;
136 : : }
137 : : }
138 : :
139 : 0 : static void agp_add_seg_to_client(struct agp_client *client,
140 : : struct agp_segment_priv ** seg, int num_segments)
141 : : {
142 : 0 : struct agp_segment_priv **prev_seg;
143 : :
144 : 0 : prev_seg = client->segments;
145 : :
146 : 0 : if (prev_seg != NULL)
147 : 0 : agp_remove_seg_from_client(client);
148 : :
149 : 0 : DBG("Adding seg %p (%d segments) to client %p", seg, num_segments, client);
150 : 0 : client->num_segments = num_segments;
151 : 0 : client->segments = seg;
152 : : }
153 : :
154 : 0 : static pgprot_t agp_convert_mmap_flags(int prot)
155 : : {
156 : 0 : unsigned long prot_bits;
157 : :
158 : 0 : prot_bits = calc_vm_prot_bits(prot, 0) | VM_SHARED;
159 : 0 : return vm_get_page_prot(prot_bits);
160 : : }
161 : :
162 : 0 : int agp_create_segment(struct agp_client *client, struct agp_region *region)
163 : : {
164 : 0 : struct agp_segment_priv **ret_seg;
165 : 0 : struct agp_segment_priv *seg;
166 : 0 : struct agp_segment *user_seg;
167 : 0 : size_t i;
168 : :
169 : 0 : seg = kzalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL);
170 [ # # ]: 0 : if (seg == NULL) {
171 : 0 : kfree(region->seg_list);
172 : 0 : region->seg_list = NULL;
173 : 0 : return -ENOMEM;
174 : : }
175 : 0 : user_seg = region->seg_list;
176 : :
177 [ # # ]: 0 : for (i = 0; i < region->seg_count; i++) {
178 : 0 : seg[i].pg_start = user_seg[i].pg_start;
179 : 0 : seg[i].pg_count = user_seg[i].pg_count;
180 : 0 : seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot);
181 : : }
182 : 0 : kfree(region->seg_list);
183 : 0 : region->seg_list = NULL;
184 : :
185 : 0 : ret_seg = kmalloc(sizeof(void *), GFP_KERNEL);
186 [ # # ]: 0 : if (ret_seg == NULL) {
187 : 0 : kfree(seg);
188 : 0 : return -ENOMEM;
189 : : }
190 : 0 : *ret_seg = seg;
191 [ # # ]: 0 : agp_add_seg_to_client(client, ret_seg, region->seg_count);
192 : 0 : return 0;
193 : : }
194 : :
195 : : /* End - Routines for managing each client's segment list */
196 : :
197 : : /* This function must only be called when current_controller != NULL */
198 : 0 : static void agp_insert_into_pool(struct agp_memory * temp)
199 : : {
200 : 0 : struct agp_memory *prev;
201 : :
202 : 0 : prev = agp_fe.current_controller->pool;
203 : :
204 : 0 : if (prev != NULL) {
205 : 0 : prev->prev = temp;
206 : 0 : temp->next = prev;
207 : : }
208 : 0 : agp_fe.current_controller->pool = temp;
209 : : }
210 : :
211 : :
212 : : /* File private list routines */
213 : :
214 : 0 : struct agp_file_private *agp_find_private(pid_t pid)
215 : : {
216 : 0 : struct agp_file_private *curr;
217 : :
218 : 0 : curr = agp_fe.file_priv_list;
219 : :
220 [ # # # # ]: 0 : while (curr != NULL) {
221 [ # # # # ]: 0 : if (curr->my_pid == pid)
222 : 0 : return curr;
223 : 0 : curr = curr->next;
224 : : }
225 : :
226 : : return NULL;
227 : : }
228 : :
229 : 0 : static void agp_insert_file_private(struct agp_file_private * priv)
230 : : {
231 : 0 : struct agp_file_private *prev;
232 : :
233 : 0 : prev = agp_fe.file_priv_list;
234 : :
235 : 0 : if (prev != NULL)
236 : 0 : prev->prev = priv;
237 : 0 : priv->next = prev;
238 : 0 : agp_fe.file_priv_list = priv;
239 : : }
240 : :
241 : 0 : static void agp_remove_file_private(struct agp_file_private * priv)
242 : : {
243 : 0 : struct agp_file_private *next;
244 : 0 : struct agp_file_private *prev;
245 : :
246 : 0 : next = priv->next;
247 : 0 : prev = priv->prev;
248 : :
249 : 0 : if (prev != NULL) {
250 : 0 : prev->next = next;
251 : :
252 [ # # ]: 0 : if (next != NULL)
253 : 0 : next->prev = prev;
254 : :
255 : : } else {
256 [ # # ]: 0 : if (next != NULL)
257 : 0 : next->prev = NULL;
258 : :
259 : 0 : agp_fe.file_priv_list = next;
260 : : }
261 : : }
262 : :
263 : : /* End - File flag list routines */
264 : :
265 : : /*
266 : : * Wrappers for agp_free_memory & agp_allocate_memory
267 : : * These make sure that internal lists are kept updated.
268 : : */
269 : 0 : void agp_free_memory_wrap(struct agp_memory *memory)
270 : : {
271 : 0 : agp_remove_from_pool(memory);
272 : 0 : agp_free_memory(memory);
273 : 0 : }
274 : :
275 : 0 : struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type)
276 : : {
277 : 0 : struct agp_memory *memory;
278 : :
279 : 0 : memory = agp_allocate_memory(agp_bridge, pg_count, type);
280 [ # # ]: 0 : if (memory == NULL)
281 : : return NULL;
282 : :
283 [ # # ]: 0 : agp_insert_into_pool(memory);
284 : 0 : return memory;
285 : : }
286 : :
287 : : /* Routines for managing the list of controllers -
288 : : * These routines manage the current controller, and the list of
289 : : * controllers
290 : : */
291 : :
292 : 0 : static struct agp_controller *agp_find_controller_by_pid(pid_t id)
293 : : {
294 : 0 : struct agp_controller *controller;
295 : :
296 : 0 : controller = agp_fe.controllers;
297 : :
298 [ # # # # ]: 0 : while (controller != NULL) {
299 [ # # # # ]: 0 : if (controller->pid == id)
300 : : return controller;
301 : 0 : controller = controller->next;
302 : : }
303 : :
304 : : return NULL;
305 : : }
306 : :
307 : 0 : static struct agp_controller *agp_create_controller(pid_t id)
308 : : {
309 : 0 : struct agp_controller *controller;
310 : :
311 : 0 : controller = kzalloc(sizeof(struct agp_controller), GFP_KERNEL);
312 [ # # ]: 0 : if (controller == NULL)
313 : : return NULL;
314 : :
315 : 0 : controller->pid = id;
316 : 0 : return controller;
317 : : }
318 : :
319 : 0 : static int agp_insert_controller(struct agp_controller *controller)
320 : : {
321 : 0 : struct agp_controller *prev_controller;
322 : :
323 : 0 : prev_controller = agp_fe.controllers;
324 : 0 : controller->next = prev_controller;
325 : :
326 : 0 : if (prev_controller != NULL)
327 : 0 : prev_controller->prev = controller;
328 : :
329 : 0 : agp_fe.controllers = controller;
330 : :
331 : 0 : return 0;
332 : : }
333 : :
334 : : static void agp_remove_all_clients(struct agp_controller *controller)
335 : : {
336 : : struct agp_client *client;
337 : : struct agp_client *temp;
338 : :
339 : : client = controller->clients;
340 : :
341 : : while (client) {
342 : : struct agp_file_private *priv;
343 : :
344 : : temp = client;
345 : : agp_remove_seg_from_client(temp);
346 : : priv = agp_find_private(temp->pid);
347 : :
348 : : if (priv != NULL) {
349 : : clear_bit(AGP_FF_IS_VALID, &priv->access_flags);
350 : : clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
351 : : }
352 : : client = client->next;
353 : : kfree(temp);
354 : : }
355 : : }
356 : :
357 : : static void agp_remove_all_memory(struct agp_controller *controller)
358 : : {
359 : : struct agp_memory *memory;
360 : : struct agp_memory *temp;
361 : :
362 : : memory = controller->pool;
363 : :
364 : : while (memory) {
365 : : temp = memory;
366 : : memory = memory->next;
367 : : agp_free_memory_wrap(temp);
368 : : }
369 : : }
370 : :
371 : 0 : static int agp_remove_controller(struct agp_controller *controller)
372 : : {
373 : 0 : struct agp_controller *prev_controller;
374 : 0 : struct agp_controller *next_controller;
375 : :
376 : 0 : prev_controller = controller->prev;
377 : 0 : next_controller = controller->next;
378 : :
379 [ # # ]: 0 : if (prev_controller != NULL) {
380 : 0 : prev_controller->next = next_controller;
381 [ # # ]: 0 : if (next_controller != NULL)
382 : 0 : next_controller->prev = prev_controller;
383 : :
384 : : } else {
385 [ # # ]: 0 : if (next_controller != NULL)
386 : 0 : next_controller->prev = NULL;
387 : :
388 : 0 : agp_fe.controllers = next_controller;
389 : : }
390 : :
391 : 0 : agp_remove_all_memory(controller);
392 : 0 : agp_remove_all_clients(controller);
393 : :
394 [ # # ]: 0 : if (agp_fe.current_controller == controller) {
395 : 0 : agp_fe.current_controller = NULL;
396 : 0 : agp_fe.backend_acquired = false;
397 : 0 : agp_backend_release(agp_bridge);
398 : : }
399 : 0 : kfree(controller);
400 : 0 : return 0;
401 : : }
402 : :
403 : 0 : static void agp_controller_make_current(struct agp_controller *controller)
404 : : {
405 : 0 : struct agp_client *clients;
406 : :
407 : 0 : clients = controller->clients;
408 : :
409 [ # # ]: 0 : while (clients != NULL) {
410 : 0 : struct agp_file_private *priv;
411 : :
412 : 0 : priv = agp_find_private(clients->pid);
413 : :
414 [ # # ]: 0 : if (priv != NULL) {
415 : 0 : set_bit(AGP_FF_IS_VALID, &priv->access_flags);
416 : 0 : set_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
417 : : }
418 : 0 : clients = clients->next;
419 : : }
420 : :
421 : 0 : agp_fe.current_controller = controller;
422 : 0 : }
423 : :
424 : : static void agp_controller_release_current(struct agp_controller *controller,
425 : : struct agp_file_private *controller_priv)
426 : : {
427 : : struct agp_client *clients;
428 : :
429 : : clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags);
430 : : clients = controller->clients;
431 : :
432 : : while (clients != NULL) {
433 : : struct agp_file_private *priv;
434 : :
435 : : priv = agp_find_private(clients->pid);
436 : :
437 : : if (priv != NULL)
438 : : clear_bit(AGP_FF_IS_VALID, &priv->access_flags);
439 : :
440 : : clients = clients->next;
441 : : }
442 : :
443 : : agp_fe.current_controller = NULL;
444 : : agp_fe.used_by_controller = false;
445 : : agp_backend_release(agp_bridge);
446 : : }
447 : :
448 : : /*
449 : : * Routines for managing client lists -
450 : : * These routines are for managing the list of auth'ed clients.
451 : : */
452 : :
453 : : static struct agp_client
454 : 0 : *agp_find_client_in_controller(struct agp_controller *controller, pid_t id)
455 : : {
456 : 0 : struct agp_client *client;
457 : :
458 : 0 : if (controller == NULL)
459 : : return NULL;
460 : :
461 : 0 : client = controller->clients;
462 : :
463 [ # # # # : 0 : while (client != NULL) {
# # # # #
# ]
464 [ # # # # : 0 : if (client->pid == id)
# # # # #
# ]
465 : : return client;
466 : 0 : client = client->next;
467 : : }
468 : :
469 : : return NULL;
470 : : }
471 : :
472 : 0 : static struct agp_controller *agp_find_controller_for_client(pid_t id)
473 : : {
474 : 0 : struct agp_controller *controller;
475 : :
476 : 0 : controller = agp_fe.controllers;
477 : :
478 [ # # ]: 0 : while (controller != NULL) {
479 [ # # ]: 0 : if ((agp_find_client_in_controller(controller, id)) != NULL)
480 : : return controller;
481 : 0 : controller = controller->next;
482 : : }
483 : :
484 : : return NULL;
485 : : }
486 : :
487 : 0 : struct agp_client *agp_find_client_by_pid(pid_t id)
488 : : {
489 : 0 : struct agp_client *temp;
490 : :
491 [ # # # # : 0 : if (agp_fe.current_controller == NULL)
# # ]
492 : : return NULL;
493 : :
494 : 0 : temp = agp_find_client_in_controller(agp_fe.current_controller, id);
495 : : return temp;
496 : : }
497 : :
498 : 0 : static void agp_insert_client(struct agp_client *client)
499 : : {
500 : 0 : struct agp_client *prev_client;
501 : :
502 : 0 : prev_client = agp_fe.current_controller->clients;
503 : 0 : client->next = prev_client;
504 : :
505 : 0 : if (prev_client != NULL)
506 : 0 : prev_client->prev = client;
507 : :
508 : 0 : agp_fe.current_controller->clients = client;
509 : 0 : agp_fe.current_controller->num_clients++;
510 : : }
511 : :
512 : 0 : struct agp_client *agp_create_client(pid_t id)
513 : : {
514 : 0 : struct agp_client *new_client;
515 : :
516 : 0 : new_client = kzalloc(sizeof(struct agp_client), GFP_KERNEL);
517 [ # # ]: 0 : if (new_client == NULL)
518 : : return NULL;
519 : :
520 : 0 : new_client->pid = id;
521 [ # # ]: 0 : agp_insert_client(new_client);
522 : 0 : return new_client;
523 : : }
524 : :
525 : 0 : int agp_remove_client(pid_t id)
526 : : {
527 : 0 : struct agp_client *client;
528 : 0 : struct agp_client *prev_client;
529 : 0 : struct agp_client *next_client;
530 : 0 : struct agp_controller *controller;
531 : :
532 : 0 : controller = agp_find_controller_for_client(id);
533 [ # # ]: 0 : if (controller == NULL)
534 : : return -EINVAL;
535 : :
536 : 0 : client = agp_find_client_in_controller(controller, id);
537 [ # # ]: 0 : if (client == NULL)
538 : : return -EINVAL;
539 : :
540 : 0 : prev_client = client->prev;
541 : 0 : next_client = client->next;
542 : :
543 [ # # ]: 0 : if (prev_client != NULL) {
544 : 0 : prev_client->next = next_client;
545 [ # # ]: 0 : if (next_client != NULL)
546 : 0 : next_client->prev = prev_client;
547 : :
548 : : } else {
549 [ # # ]: 0 : if (next_client != NULL)
550 : 0 : next_client->prev = NULL;
551 : 0 : controller->clients = next_client;
552 : : }
553 : :
554 : 0 : controller->num_clients--;
555 : 0 : agp_remove_seg_from_client(client);
556 : 0 : kfree(client);
557 : 0 : return 0;
558 : : }
559 : :
560 : : /* End - Routines for managing client lists */
561 : :
562 : : /* File Operations */
563 : :
564 : 0 : static int agp_mmap(struct file *file, struct vm_area_struct *vma)
565 : : {
566 : 0 : unsigned int size, current_size;
567 : 0 : unsigned long offset;
568 : 0 : struct agp_client *client;
569 : 0 : struct agp_file_private *priv = file->private_data;
570 : 0 : struct agp_kern_info kerninfo;
571 : :
572 : 0 : mutex_lock(&(agp_fe.agp_mutex));
573 : :
574 [ # # ]: 0 : if (agp_fe.backend_acquired != true)
575 : 0 : goto out_eperm;
576 : :
577 [ # # ]: 0 : if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags)))
578 : 0 : goto out_eperm;
579 : :
580 : 0 : agp_copy_info(agp_bridge, &kerninfo);
581 : 0 : size = vma->vm_end - vma->vm_start;
582 : 0 : current_size = kerninfo.aper_size;
583 : 0 : current_size = current_size * 0x100000;
584 : 0 : offset = vma->vm_pgoff << PAGE_SHIFT;
585 : 0 : DBG("%lx:%lx", offset, offset+size);
586 : :
587 [ # # ]: 0 : if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
588 [ # # ]: 0 : if ((size + offset) > current_size)
589 : 0 : goto out_inval;
590 : :
591 [ # # ]: 0 : client = agp_find_client_by_pid(current->pid);
592 : :
593 [ # # ]: 0 : if (client == NULL)
594 : 0 : goto out_eperm;
595 : :
596 [ # # ]: 0 : if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot))
597 : 0 : goto out_inval;
598 : :
599 : 0 : DBG("client vm_ops=%p", kerninfo.vm_ops);
600 [ # # ]: 0 : if (kerninfo.vm_ops) {
601 : 0 : vma->vm_ops = kerninfo.vm_ops;
602 [ # # ]: 0 : } else if (io_remap_pfn_range(vma, vma->vm_start,
603 : 0 : (kerninfo.aper_base + offset) >> PAGE_SHIFT,
604 : : size,
605 : : pgprot_writecombine(vma->vm_page_prot))) {
606 : 0 : goto out_again;
607 : : }
608 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
609 : 0 : return 0;
610 : : }
611 : :
612 [ # # ]: 0 : if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
613 [ # # ]: 0 : if (size != current_size)
614 : 0 : goto out_inval;
615 : :
616 : 0 : DBG("controller vm_ops=%p", kerninfo.vm_ops);
617 [ # # ]: 0 : if (kerninfo.vm_ops) {
618 : 0 : vma->vm_ops = kerninfo.vm_ops;
619 [ # # ]: 0 : } else if (io_remap_pfn_range(vma, vma->vm_start,
620 : 0 : kerninfo.aper_base >> PAGE_SHIFT,
621 : : size,
622 : : pgprot_writecombine(vma->vm_page_prot))) {
623 : 0 : goto out_again;
624 : : }
625 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
626 : 0 : return 0;
627 : : }
628 : :
629 : 0 : out_eperm:
630 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
631 : 0 : return -EPERM;
632 : :
633 : 0 : out_inval:
634 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
635 : 0 : return -EINVAL;
636 : :
637 : 0 : out_again:
638 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
639 : 0 : return -EAGAIN;
640 : : }
641 : :
642 : 0 : static int agp_release(struct inode *inode, struct file *file)
643 : : {
644 : 0 : struct agp_file_private *priv = file->private_data;
645 : :
646 : 0 : mutex_lock(&(agp_fe.agp_mutex));
647 : :
648 : 0 : DBG("priv=%p", priv);
649 : :
650 [ # # ]: 0 : if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
651 : 0 : struct agp_controller *controller;
652 : :
653 : 0 : controller = agp_find_controller_by_pid(priv->my_pid);
654 : :
655 [ # # ]: 0 : if (controller != NULL) {
656 [ # # ]: 0 : if (controller == agp_fe.current_controller)
657 : 0 : agp_controller_release_current(controller, priv);
658 : 0 : agp_remove_controller(controller);
659 : 0 : controller = NULL;
660 : : }
661 : : }
662 : :
663 [ # # ]: 0 : if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags))
664 : 0 : agp_remove_client(priv->my_pid);
665 : :
666 [ # # ]: 0 : agp_remove_file_private(priv);
667 : 0 : kfree(priv);
668 : 0 : file->private_data = NULL;
669 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
670 : 0 : return 0;
671 : : }
672 : :
673 : 0 : static int agp_open(struct inode *inode, struct file *file)
674 : : {
675 [ # # ]: 0 : int minor = iminor(inode);
676 : 0 : struct agp_file_private *priv;
677 : 0 : struct agp_client *client;
678 : :
679 [ # # ]: 0 : if (minor != AGPGART_MINOR)
680 : : return -ENXIO;
681 : :
682 : 0 : mutex_lock(&(agp_fe.agp_mutex));
683 : :
684 : 0 : priv = kzalloc(sizeof(struct agp_file_private), GFP_KERNEL);
685 [ # # ]: 0 : if (priv == NULL) {
686 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
687 : 0 : return -ENOMEM;
688 : : }
689 : :
690 : 0 : set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
691 : 0 : priv->my_pid = current->pid;
692 : :
693 [ # # ]: 0 : if (capable(CAP_SYS_RAWIO))
694 : : /* Root priv, can be controller */
695 : 0 : set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags);
696 : :
697 [ # # ]: 0 : client = agp_find_client_by_pid(current->pid);
698 : :
699 [ # # ]: 0 : if (client != NULL) {
700 : 0 : set_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
701 : 0 : set_bit(AGP_FF_IS_VALID, &priv->access_flags);
702 : : }
703 : 0 : file->private_data = (void *) priv;
704 [ # # ]: 0 : agp_insert_file_private(priv);
705 : 0 : DBG("private=%p, client=%p", priv, client);
706 : :
707 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
708 : :
709 : 0 : return 0;
710 : : }
711 : :
712 : : static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg)
713 : : {
714 : : struct agp_info userinfo;
715 : : struct agp_kern_info kerninfo;
716 : :
717 : : agp_copy_info(agp_bridge, &kerninfo);
718 : :
719 : : memset(&userinfo, 0, sizeof(userinfo));
720 : : userinfo.version.major = kerninfo.version.major;
721 : : userinfo.version.minor = kerninfo.version.minor;
722 : : userinfo.bridge_id = kerninfo.device->vendor |
723 : : (kerninfo.device->device << 16);
724 : : userinfo.agp_mode = kerninfo.mode;
725 : : userinfo.aper_base = kerninfo.aper_base;
726 : : userinfo.aper_size = kerninfo.aper_size;
727 : : userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory;
728 : : userinfo.pg_used = kerninfo.current_memory;
729 : :
730 : : if (copy_to_user(arg, &userinfo, sizeof(struct agp_info)))
731 : : return -EFAULT;
732 : :
733 : : return 0;
734 : : }
735 : :
736 : 0 : int agpioc_acquire_wrap(struct agp_file_private *priv)
737 : : {
738 : 0 : struct agp_controller *controller;
739 : :
740 : 0 : DBG("");
741 : :
742 [ # # ]: 0 : if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags)))
743 : : return -EPERM;
744 : :
745 [ # # ]: 0 : if (agp_fe.current_controller != NULL)
746 : : return -EBUSY;
747 : :
748 [ # # ]: 0 : if (!agp_bridge)
749 : : return -ENODEV;
750 : :
751 [ # # ]: 0 : if (atomic_read(&agp_bridge->agp_in_use))
752 : : return -EBUSY;
753 : :
754 : 0 : atomic_inc(&agp_bridge->agp_in_use);
755 : :
756 : 0 : agp_fe.backend_acquired = true;
757 : :
758 : 0 : controller = agp_find_controller_by_pid(priv->my_pid);
759 : :
760 [ # # ]: 0 : if (controller != NULL) {
761 : 0 : agp_controller_make_current(controller);
762 : : } else {
763 : 0 : controller = agp_create_controller(priv->my_pid);
764 : :
765 : 0 : if (controller == NULL) {
766 : 0 : agp_fe.backend_acquired = false;
767 : 0 : agp_backend_release(agp_bridge);
768 : 0 : return -ENOMEM;
769 : : }
770 [ # # ]: 0 : agp_insert_controller(controller);
771 : 0 : agp_controller_make_current(controller);
772 : : }
773 : :
774 : 0 : set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags);
775 : 0 : set_bit(AGP_FF_IS_VALID, &priv->access_flags);
776 : 0 : return 0;
777 : : }
778 : :
779 : 0 : int agpioc_release_wrap(struct agp_file_private *priv)
780 : : {
781 : 0 : DBG("");
782 : 0 : agp_controller_release_current(agp_fe.current_controller, priv);
783 : 0 : return 0;
784 : : }
785 : :
786 : 0 : int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg)
787 : : {
788 : 0 : struct agp_setup mode;
789 : :
790 : 0 : DBG("");
791 [ # # ]: 0 : if (copy_from_user(&mode, arg, sizeof(struct agp_setup)))
792 : : return -EFAULT;
793 : :
794 : 0 : agp_enable(agp_bridge, mode.agp_mode);
795 : 0 : return 0;
796 : : }
797 : :
798 : : static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg)
799 : : {
800 : : struct agp_region reserve;
801 : : struct agp_client *client;
802 : : struct agp_file_private *client_priv;
803 : :
804 : : DBG("");
805 : : if (copy_from_user(&reserve, arg, sizeof(struct agp_region)))
806 : : return -EFAULT;
807 : :
808 : : if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment))
809 : : return -EFAULT;
810 : :
811 : : client = agp_find_client_by_pid(reserve.pid);
812 : :
813 : : if (reserve.seg_count == 0) {
814 : : /* remove a client */
815 : : client_priv = agp_find_private(reserve.pid);
816 : :
817 : : if (client_priv != NULL) {
818 : : set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
819 : : set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
820 : : }
821 : : if (client == NULL) {
822 : : /* client is already removed */
823 : : return 0;
824 : : }
825 : : return agp_remove_client(reserve.pid);
826 : : } else {
827 : : struct agp_segment *segment;
828 : :
829 : : if (reserve.seg_count >= 16384)
830 : : return -EINVAL;
831 : :
832 : : segment = kmalloc((sizeof(struct agp_segment) * reserve.seg_count),
833 : : GFP_KERNEL);
834 : :
835 : : if (segment == NULL)
836 : : return -ENOMEM;
837 : :
838 : : if (copy_from_user(segment, (void __user *) reserve.seg_list,
839 : : sizeof(struct agp_segment) * reserve.seg_count)) {
840 : : kfree(segment);
841 : : return -EFAULT;
842 : : }
843 : : reserve.seg_list = segment;
844 : :
845 : : if (client == NULL) {
846 : : /* Create the client and add the segment */
847 : : client = agp_create_client(reserve.pid);
848 : :
849 : : if (client == NULL) {
850 : : kfree(segment);
851 : : return -ENOMEM;
852 : : }
853 : : client_priv = agp_find_private(reserve.pid);
854 : :
855 : : if (client_priv != NULL) {
856 : : set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
857 : : set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
858 : : }
859 : : }
860 : : return agp_create_segment(client, &reserve);
861 : : }
862 : : /* Will never really happen */
863 : : return -EINVAL;
864 : : }
865 : :
866 : 0 : int agpioc_protect_wrap(struct agp_file_private *priv)
867 : : {
868 : 0 : DBG("");
869 : : /* This function is not currently implemented */
870 : 0 : return -EINVAL;
871 : : }
872 : :
873 : : static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg)
874 : : {
875 : : struct agp_memory *memory;
876 : : struct agp_allocate alloc;
877 : :
878 : : DBG("");
879 : : if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate)))
880 : : return -EFAULT;
881 : :
882 : : if (alloc.type >= AGP_USER_TYPES)
883 : : return -EINVAL;
884 : :
885 : : memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type);
886 : :
887 : : if (memory == NULL)
888 : : return -ENOMEM;
889 : :
890 : : alloc.key = memory->key;
891 : : alloc.physical = memory->physical;
892 : :
893 : : if (copy_to_user(arg, &alloc, sizeof(struct agp_allocate))) {
894 : : agp_free_memory_wrap(memory);
895 : : return -EFAULT;
896 : : }
897 : : return 0;
898 : : }
899 : :
900 : 0 : int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg)
901 : : {
902 : 0 : struct agp_memory *memory;
903 : :
904 : 0 : DBG("");
905 [ # # ]: 0 : memory = agp_find_mem_by_key(arg);
906 : :
907 [ # # ]: 0 : if (memory == NULL)
908 : : return -EINVAL;
909 : :
910 : 0 : agp_free_memory_wrap(memory);
911 : 0 : return 0;
912 : : }
913 : :
914 : : static int agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg)
915 : : {
916 : : struct agp_bind bind_info;
917 : : struct agp_memory *memory;
918 : :
919 : : DBG("");
920 : : if (copy_from_user(&bind_info, arg, sizeof(struct agp_bind)))
921 : : return -EFAULT;
922 : :
923 : : memory = agp_find_mem_by_key(bind_info.key);
924 : :
925 : : if (memory == NULL)
926 : : return -EINVAL;
927 : :
928 : : return agp_bind_memory(memory, bind_info.pg_start);
929 : : }
930 : :
931 : : static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg)
932 : : {
933 : : struct agp_memory *memory;
934 : : struct agp_unbind unbind;
935 : :
936 : : DBG("");
937 : : if (copy_from_user(&unbind, arg, sizeof(struct agp_unbind)))
938 : : return -EFAULT;
939 : :
940 : : memory = agp_find_mem_by_key(unbind.key);
941 : :
942 : : if (memory == NULL)
943 : : return -EINVAL;
944 : :
945 : : return agp_unbind_memory(memory);
946 : : }
947 : :
948 : 0 : static long agp_ioctl(struct file *file,
949 : : unsigned int cmd, unsigned long arg)
950 : : {
951 : 0 : struct agp_file_private *curr_priv = file->private_data;
952 : 0 : int ret_val = -ENOTTY;
953 : :
954 : 0 : DBG("priv=%p, cmd=%x", curr_priv, cmd);
955 : 0 : mutex_lock(&(agp_fe.agp_mutex));
956 : :
957 [ # # # # ]: 0 : if ((agp_fe.current_controller == NULL) &&
958 : : (cmd != AGPIOC_ACQUIRE)) {
959 : 0 : ret_val = -EINVAL;
960 : 0 : goto ioctl_out;
961 : : }
962 [ # # # # ]: 0 : if ((agp_fe.backend_acquired != true) &&
963 : : (cmd != AGPIOC_ACQUIRE)) {
964 : 0 : ret_val = -EBUSY;
965 : 0 : goto ioctl_out;
966 : : }
967 [ # # ]: 0 : if (cmd != AGPIOC_ACQUIRE) {
968 [ # # ]: 0 : if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) {
969 : 0 : ret_val = -EPERM;
970 : 0 : goto ioctl_out;
971 : : }
972 : : /* Use the original pid of the controller,
973 : : * in case it's threaded */
974 : :
975 [ # # ]: 0 : if (agp_fe.current_controller->pid != curr_priv->my_pid) {
976 : 0 : ret_val = -EBUSY;
977 : 0 : goto ioctl_out;
978 : : }
979 : : }
980 : :
981 [ # # # # : 0 : switch (cmd) {
# # # # #
# # ]
982 : 0 : case AGPIOC_INFO:
983 : 0 : ret_val = agpioc_info_wrap(curr_priv, (void __user *) arg);
984 : 0 : break;
985 : :
986 : 0 : case AGPIOC_ACQUIRE:
987 : 0 : ret_val = agpioc_acquire_wrap(curr_priv);
988 : 0 : break;
989 : :
990 : : case AGPIOC_RELEASE:
991 : 0 : ret_val = agpioc_release_wrap(curr_priv);
992 : 0 : break;
993 : :
994 : 0 : case AGPIOC_SETUP:
995 : 0 : ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg);
996 : 0 : break;
997 : :
998 : 0 : case AGPIOC_RESERVE:
999 : 0 : ret_val = agpioc_reserve_wrap(curr_priv, (void __user *) arg);
1000 : 0 : break;
1001 : :
1002 : : case AGPIOC_PROTECT:
1003 : 0 : ret_val = agpioc_protect_wrap(curr_priv);
1004 : 0 : break;
1005 : :
1006 : 0 : case AGPIOC_ALLOCATE:
1007 : 0 : ret_val = agpioc_allocate_wrap(curr_priv, (void __user *) arg);
1008 : 0 : break;
1009 : :
1010 : 0 : case AGPIOC_DEALLOCATE:
1011 : 0 : ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg);
1012 : 0 : break;
1013 : :
1014 : 0 : case AGPIOC_BIND:
1015 : 0 : ret_val = agpioc_bind_wrap(curr_priv, (void __user *) arg);
1016 : 0 : break;
1017 : :
1018 : 0 : case AGPIOC_UNBIND:
1019 : 0 : ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg);
1020 : 0 : break;
1021 : :
1022 : : case AGPIOC_CHIPSET_FLUSH:
1023 : : break;
1024 : : }
1025 : :
1026 : 0 : ioctl_out:
1027 : 0 : DBG("ioctl returns %d\n", ret_val);
1028 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
1029 : 0 : return ret_val;
1030 : : }
1031 : :
1032 : : static const struct file_operations agp_fops =
1033 : : {
1034 : : .owner = THIS_MODULE,
1035 : : .llseek = no_llseek,
1036 : : .unlocked_ioctl = agp_ioctl,
1037 : : #ifdef CONFIG_COMPAT
1038 : : .compat_ioctl = compat_agp_ioctl,
1039 : : #endif
1040 : : .mmap = agp_mmap,
1041 : : .open = agp_open,
1042 : : .release = agp_release,
1043 : : };
1044 : :
1045 : : static struct miscdevice agp_miscdev =
1046 : : {
1047 : : .minor = AGPGART_MINOR,
1048 : : .name = "agpgart",
1049 : : .fops = &agp_fops
1050 : : };
1051 : :
1052 : 0 : int agp_frontend_initialize(void)
1053 : : {
1054 : 0 : memset(&agp_fe, 0, sizeof(struct agp_front_data));
1055 : 0 : mutex_init(&(agp_fe.agp_mutex));
1056 : :
1057 [ # # ]: 0 : if (misc_register(&agp_miscdev)) {
1058 : 0 : printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR);
1059 : 0 : return -EIO;
1060 : : }
1061 : : return 0;
1062 : : }
1063 : :
1064 : 0 : void agp_frontend_cleanup(void)
1065 : : {
1066 : 0 : misc_deregister(&agp_miscdev);
1067 : 0 : }
|