1 /* drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*-
2  * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
3  *
4  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Author:
28  *    Rickard E. (Rik) Faith <faith@valinux.com>
29  *    Gareth Hughes <gareth@valinux.com>
30  */
31 
32 #include "drmP.h"
33 #include <linux/module.h>
34 
35 #if __REALLY_HAVE_AGP
36 
37 #define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
38 #define DRM_AGP_PUT inter_module_put("drm_agp")
39 
40 static const drm_agp_t *drm_agp = NULL;
41 
DRM(agp_info)42 int DRM(agp_info)(struct inode *inode, struct file *filp,
43 		  unsigned int cmd, unsigned long arg)
44 {
45 	drm_file_t	 *priv	 = filp->private_data;
46 	drm_device_t	 *dev	 = priv->dev;
47 	agp_kern_info    *kern;
48 	drm_agp_info_t   info;
49 
50 	if (!dev->agp || !dev->agp->acquired || !drm_agp->copy_info)
51 		return -EINVAL;
52 
53 	kern                   = &dev->agp->agp_info;
54 	info.agp_version_major = kern->version.major;
55 	info.agp_version_minor = kern->version.minor;
56 	info.mode              = kern->mode;
57 	info.aperture_base     = kern->aper_base;
58 	info.aperture_size     = kern->aper_size * 1024 * 1024;
59 	info.memory_allowed    = kern->max_memory << PAGE_SHIFT;
60 	info.memory_used       = kern->current_memory << PAGE_SHIFT;
61 	info.id_vendor         = kern->device->vendor;
62 	info.id_device         = kern->device->device;
63 
64 	if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info)))
65 		return -EFAULT;
66 	return 0;
67 }
68 
DRM(agp_acquire)69 int DRM(agp_acquire)(struct inode *inode, struct file *filp,
70 		     unsigned int cmd, unsigned long arg)
71 {
72 	drm_file_t	 *priv	 = filp->private_data;
73 	drm_device_t	 *dev	 = priv->dev;
74 	int              retcode;
75 
76 	if (!dev->agp)
77 		return -ENODEV;
78 	if (dev->agp->acquired)
79 		return -EBUSY;
80 	if(!drm_agp->acquire)
81 		return -EINVAL;
82 	if ((retcode = drm_agp->acquire()))
83 		return retcode;
84 	dev->agp->acquired = 1;
85 	return 0;
86 }
87 
DRM(agp_release)88 int DRM(agp_release)(struct inode *inode, struct file *filp,
89 		     unsigned int cmd, unsigned long arg)
90 {
91 	drm_file_t	 *priv	 = filp->private_data;
92 	drm_device_t	 *dev	 = priv->dev;
93 
94 	if (!dev->agp || !dev->agp->acquired || !drm_agp->release)
95 		return -EINVAL;
96 	drm_agp->release();
97 	dev->agp->acquired = 0;
98 	return 0;
99 
100 }
101 
DRM(agp_do_release)102 void DRM(agp_do_release)(void)
103 {
104 	if (drm_agp->release) drm_agp->release();
105 }
106 
DRM(agp_enable)107 int DRM(agp_enable)(struct inode *inode, struct file *filp,
108 		    unsigned int cmd, unsigned long arg)
109 {
110 	drm_file_t	 *priv	 = filp->private_data;
111 	drm_device_t	 *dev	 = priv->dev;
112 	drm_agp_mode_t   mode;
113 
114 	if (!dev->agp || !dev->agp->acquired || !drm_agp->enable)
115 		return -EINVAL;
116 
117 	if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode)))
118 		return -EFAULT;
119 
120 	dev->agp->mode    = mode.mode;
121 	drm_agp->enable(mode.mode);
122 	dev->agp->base    = dev->agp->agp_info.aper_base;
123 	dev->agp->enabled = 1;
124 	return 0;
125 }
126 
DRM(agp_alloc)127 int DRM(agp_alloc)(struct inode *inode, struct file *filp,
128 		   unsigned int cmd, unsigned long arg)
129 {
130 	drm_file_t	 *priv	 = filp->private_data;
131 	drm_device_t	 *dev	 = priv->dev;
132 	drm_agp_buffer_t request;
133 	drm_agp_mem_t    *entry;
134 	agp_memory       *memory;
135 	unsigned long    pages;
136 	u32 		 type;
137 
138 	if (!dev->agp || !dev->agp->acquired) return -EINVAL;
139 	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
140 		return -EFAULT;
141 	if (!(entry = DRM(alloc)(sizeof(*entry), DRM_MEM_AGPLISTS)))
142 		return -ENOMEM;
143 
144    	memset(entry, 0, sizeof(*entry));
145 
146 	pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
147 	type = (u32) request.type;
148 
149 	if (!(memory = DRM(alloc_agp)(pages, type))) {
150 		DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
151 		return -ENOMEM;
152 	}
153 
154 	entry->handle    = (unsigned long)memory->memory;
155 	entry->memory    = memory;
156 	entry->bound     = 0;
157 	entry->pages     = pages;
158 	entry->prev      = NULL;
159 	entry->next      = dev->agp->memory;
160 	if (dev->agp->memory) dev->agp->memory->prev = entry;
161 	dev->agp->memory = entry;
162 
163 	request.handle   = entry->handle;
164         request.physical = memory->physical;
165 
166 	if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) {
167 		dev->agp->memory       = entry->next;
168 		dev->agp->memory->prev = NULL;
169 		DRM(free_agp)(memory, pages);
170 		DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
171 		return -EFAULT;
172 	}
173 	return 0;
174 }
175 
DRM(agp_lookup_entry)176 static drm_agp_mem_t *DRM(agp_lookup_entry)(drm_device_t *dev,
177 					    unsigned long handle)
178 {
179 	drm_agp_mem_t *entry;
180 
181 	for (entry = dev->agp->memory; entry; entry = entry->next) {
182 		if (entry->handle == handle) return entry;
183 	}
184 	return NULL;
185 }
186 
DRM(agp_unbind)187 int DRM(agp_unbind)(struct inode *inode, struct file *filp,
188 		    unsigned int cmd, unsigned long arg)
189 {
190 	drm_file_t	  *priv	 = filp->private_data;
191 	drm_device_t	  *dev	 = priv->dev;
192 	drm_agp_binding_t request;
193 	drm_agp_mem_t     *entry;
194 
195 	if (!dev->agp || !dev->agp->acquired) return -EINVAL;
196 	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
197 		return -EFAULT;
198 	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
199 		return -EINVAL;
200 	if (!entry->bound) return -EINVAL;
201 	return DRM(unbind_agp)(entry->memory);
202 }
203 
DRM(agp_bind)204 int DRM(agp_bind)(struct inode *inode, struct file *filp,
205 		  unsigned int cmd, unsigned long arg)
206 {
207 	drm_file_t	  *priv	 = filp->private_data;
208 	drm_device_t	  *dev	 = priv->dev;
209 	drm_agp_binding_t request;
210 	drm_agp_mem_t     *entry;
211 	int               retcode;
212 	int               page;
213 
214 	if (!dev->agp || !dev->agp->acquired || !drm_agp->bind_memory)
215 		return -EINVAL;
216 	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
217 		return -EFAULT;
218 	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
219 		return -EINVAL;
220 	if (entry->bound) return -EINVAL;
221 	page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
222 	if ((retcode = DRM(bind_agp)(entry->memory, page))) return retcode;
223 	entry->bound = dev->agp->base + (page << PAGE_SHIFT);
224 	DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
225 		  dev->agp->base, entry->bound);
226 	return 0;
227 }
228 
DRM(agp_free)229 int DRM(agp_free)(struct inode *inode, struct file *filp,
230 		  unsigned int cmd, unsigned long arg)
231 {
232 	drm_file_t	 *priv	 = filp->private_data;
233 	drm_device_t	 *dev	 = priv->dev;
234 	drm_agp_buffer_t request;
235 	drm_agp_mem_t    *entry;
236 
237 	if (!dev->agp || !dev->agp->acquired) return -EINVAL;
238 	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
239 		return -EFAULT;
240 	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
241 		return -EINVAL;
242 	if (entry->bound) DRM(unbind_agp)(entry->memory);
243 
244 	if (entry->prev) entry->prev->next = entry->next;
245 	else             dev->agp->memory  = entry->next;
246 	if (entry->next) entry->next->prev = entry->prev;
247 	DRM(free_agp)(entry->memory, entry->pages);
248 	DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
249 	return 0;
250 }
251 
DRM(agp_init)252 drm_agp_head_t *DRM(agp_init)(void)
253 {
254 	drm_agp_head_t *head         = NULL;
255 
256 	drm_agp = DRM_AGP_GET;
257 	if (drm_agp) {
258 		if (!(head = DRM(alloc)(sizeof(*head), DRM_MEM_AGPLISTS)))
259 			return NULL;
260 		memset((void *)head, 0, sizeof(*head));
261 		drm_agp->copy_info(&head->agp_info);
262 		if (head->agp_info.chipset == NOT_SUPPORTED) {
263 			DRM(free)(head, sizeof(*head), DRM_MEM_AGPLISTS);
264 			return NULL;
265 		}
266 		head->memory = NULL;
267 
268 		head->cant_use_aperture = head->agp_info.cant_use_aperture;
269 		head->page_mask = head->agp_info.page_mask;
270 
271 		DRM_INFO("AGP %d.%d Aperture @ 0x%08lx %ZuMB\n",
272 			 head->agp_info.version.major,
273 			 head->agp_info.version.minor,
274 			 head->agp_info.aper_base,
275 			 head->agp_info.aper_size);
276 	}
277 	return head;
278 }
279 
DRM(agp_uninit)280 void DRM(agp_uninit)(void)
281 {
282 	DRM_AGP_PUT;
283 	drm_agp = NULL;
284 }
285 
DRM(agp_allocate_memory)286 agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type)
287 {
288 	if (!drm_agp->allocate_memory) return NULL;
289 	return drm_agp->allocate_memory(pages, type);
290 }
291 
DRM(agp_free_memory)292 int DRM(agp_free_memory)(agp_memory *handle)
293 {
294 	if (!handle || !drm_agp->free_memory) return 0;
295 	drm_agp->free_memory(handle);
296 	return 1;
297 }
298 
DRM(agp_bind_memory)299 int DRM(agp_bind_memory)(agp_memory *handle, off_t start)
300 {
301 	if (!handle || !drm_agp->bind_memory) return -EINVAL;
302 	return drm_agp->bind_memory(handle, start);
303 }
304 
DRM(agp_unbind_memory)305 int DRM(agp_unbind_memory)(agp_memory *handle)
306 {
307 	if (!handle || !drm_agp->unbind_memory) return -EINVAL;
308 	return drm_agp->unbind_memory(handle);
309 }
310 
311 #endif /* __REALLY_HAVE_AGP */
312