cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

frontend.c (24190B)


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