xref: /dragonfly/sys/dev/drm/drm_agpsupport.c (revision 795e3215)
1 /**
2  * \file drm_agpsupport.c
3  * DRM support for AGP/GART backend
4  *
5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6  * \author Gareth Hughes <gareth@valinux.com>
7  */
8 
9 /*
10  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12  * All Rights Reserved.
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice (including the next
22  * paragraph) shall be included in all copies or substantial portions of the
23  * Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
28  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31  * OTHER DEALINGS IN THE SOFTWARE.
32  */
33 
34 #include <drm/drmP.h>
35 #include <linux/module.h>
36 #include "drm_legacy.h"
37 
38 #if __OS_HAS_AGP
39 
40 #include <dev/agp/agpreg.h>
41 #include <bus/pci/pcireg.h>
42 
43 /**
44  * Get AGP information.
45  *
46  * \param inode device inode.
47  * \param file_priv DRM file private.
48  * \param cmd command.
49  * \param arg pointer to a (output) drm_agp_info structure.
50  * \return zero on success or a negative number on failure.
51  *
52  * Verifies the AGP device has been initialized and acquired and fills in the
53  * drm_agp_info structure with the information in drm_agp_head::agp_info.
54  */
55 int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
56 {
57 	struct agp_info *kern;
58 
59 	if (!dev->agp || !dev->agp->acquired)
60 		return -EINVAL;
61 
62 	kern = &dev->agp->agp_info;
63 	agp_get_info(dev->agp->agpdev, kern);
64 	info->agp_version_major = 1;
65 	info->agp_version_minor = 0;
66 	info->mode = kern->ai_mode;
67 	info->aperture_base = kern->ai_aperture_base;
68 	info->aperture_size = kern->ai_aperture_size;
69 	info->memory_allowed = kern->ai_memory_allowed;
70 	info->memory_used = kern->ai_memory_used;
71 	info->id_vendor = kern->ai_devid & 0xffff;
72 	info->id_device = kern->ai_devid >> 16;
73 
74 	return 0;
75 }
76 
77 EXPORT_SYMBOL(drm_agp_info);
78 
79 int drm_agp_info_ioctl(struct drm_device *dev, void *data,
80 		       struct drm_file *file_priv)
81 {
82 	struct drm_agp_info info;
83 	int err;
84 
85 	err = drm_agp_info(dev, &info);
86 	if (err)
87 		return err;
88 
89 	*(struct drm_agp_info *) data = info;
90 	return 0;
91 }
92 
93 /**
94  * Acquire the AGP device.
95  *
96  * \param dev DRM device that is to acquire AGP.
97  * \return zero on success or a negative number on failure.
98  *
99  * Verifies the AGP device hasn't been acquired before and calls
100  * \c agp_backend_acquire.
101  */
102 int drm_agp_acquire(struct drm_device * dev)
103 {
104 	int retcode;
105 
106 	if (!dev->agp || dev->agp->acquired)
107 		return -EINVAL;
108 
109 	retcode = -agp_acquire(dev->agp->agpdev);
110 	if (retcode)
111 		return retcode;
112 
113 	dev->agp->acquired = 1;
114 	return 0;
115 }
116 
117 EXPORT_SYMBOL(drm_agp_acquire);
118 
119 /**
120  * Acquire the AGP device (ioctl).
121  *
122  * \param inode device inode.
123  * \param file_priv DRM file private.
124  * \param cmd command.
125  * \param arg user argument.
126  * \return zero on success or a negative number on failure.
127  *
128  * Verifies the AGP device hasn't been acquired before and calls
129  * \c agp_backend_acquire.
130  */
131 int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
132 			  struct drm_file *file_priv)
133 {
134 	return drm_agp_acquire(dev);
135 }
136 
137 /**
138  * Release the AGP device.
139  *
140  * \param dev DRM device that is to release AGP.
141  * \return zero on success or a negative number on failure.
142  *
143  * Verifies the AGP device has been acquired and calls \c agp_backend_release.
144  */
145 int drm_agp_release(struct drm_device * dev)
146 {
147 	if (!dev->agp || !dev->agp->acquired)
148 		return -EINVAL;
149 	agp_release(dev->agp->agpdev);
150 	dev->agp->acquired = 0;
151 	return 0;
152 }
153 EXPORT_SYMBOL(drm_agp_release);
154 
155 int drm_agp_release_ioctl(struct drm_device *dev, void *data,
156 			  struct drm_file *file_priv)
157 {
158 	return drm_agp_release(dev);
159 }
160 
161 /**
162  * Enable the AGP bus.
163  *
164  * \param dev DRM device that has previously acquired AGP.
165  * \param mode Requested AGP mode.
166  * \return zero on success or a negative number on failure.
167  *
168  * Verifies the AGP device has been acquired but not enabled, and calls
169  * \c agp_enable.
170  */
171 int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode)
172 {
173 	if (!dev->agp || !dev->agp->acquired)
174 		return -EINVAL;
175 
176 	dev->agp->mode = mode.mode;
177 	agp_enable(dev->agp->agpdev, mode.mode);
178 	dev->agp->enabled = 1;
179 	return 0;
180 }
181 
182 EXPORT_SYMBOL(drm_agp_enable);
183 
184 int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
185 			 struct drm_file *file_priv)
186 {
187 	struct drm_agp_mode mode;
188 
189 	mode = *(struct drm_agp_mode *) data;
190 
191 	return drm_agp_enable(dev, mode);
192 }
193 
194 static void *drm_agp_allocate_memory(size_t pages, u32 type)
195 {
196 	device_t agpdev;
197 
198 	agpdev = agp_find_device();
199 	if (!agpdev)
200 		return NULL;
201 
202 	return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT);
203 }
204 
205 /**
206  * Allocate AGP memory.
207  *
208  * \param inode device inode.
209  * \param file_priv file private pointer.
210  * \param cmd command.
211  * \param arg pointer to a drm_agp_buffer structure.
212  * \return zero on success or a negative number on failure.
213  *
214  * Verifies the AGP device is present and has been acquired, allocates the
215  * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
216  */
217 int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
218 {
219 	struct drm_agp_mem *entry;
220 	void	         *handle;
221 	unsigned long    pages;
222 	u_int32_t	 type;
223 	struct agp_memory_info info;
224 
225 	if (!dev->agp || !dev->agp->acquired)
226 		return -EINVAL;
227 
228 	entry = kmalloc(sizeof(*entry), M_DRM, M_WAITOK | M_NULLOK | M_ZERO);
229 	if (entry == NULL)
230 		return -ENOMEM;
231 
232 	pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
233 	type = (u_int32_t) request->type;
234 
235 	handle = drm_agp_allocate_memory(pages, type);
236 	if (handle == NULL) {
237 		kfree(entry);
238 		return -ENOMEM;
239 	}
240 
241 	entry->handle    = handle;
242 	entry->bound     = 0;
243 	entry->pages     = pages;
244 	entry->prev      = NULL;
245 	entry->next      = dev->agp->memory;
246 	if (dev->agp->memory)
247 		dev->agp->memory->prev = entry;
248 	dev->agp->memory = entry;
249 
250 	agp_memory_info(dev->agp->agpdev, entry->handle, &info);
251 
252 	request->handle   = (unsigned long) entry->handle;
253 	request->physical = info.ami_physical;
254 
255 	return 0;
256 }
257 EXPORT_SYMBOL(drm_agp_alloc);
258 
259 
260 int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
261 			struct drm_file *file_priv)
262 {
263 	struct drm_agp_buffer request;
264 	int retcode;
265 
266 	request = *(struct drm_agp_buffer *) data;
267 
268 	retcode = drm_agp_alloc(dev, &request);
269 
270 	*(struct drm_agp_buffer *) data = request;
271 
272 	return retcode;
273 }
274 
275 /**
276  * Search for the AGP memory entry associated with a handle.
277  *
278  * \param dev DRM device structure.
279  * \param handle AGP memory handle.
280  * \return pointer to the drm_agp_mem structure associated with \p handle.
281  *
282  * Walks through drm_agp_head::memory until finding a matching handle.
283  */
284 static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
285 					    void *handle)
286 {
287 	struct drm_agp_mem *entry;
288 
289 	for (entry = dev->agp->memory; entry; entry = entry->next) {
290 		if (entry->handle == handle)
291 			return entry;
292 	}
293 	return NULL;
294 }
295 
296 static int drm_agp_unbind_memory(void *handle)
297 {
298 	device_t agpdev;
299 
300 	agpdev = agp_find_device();
301 	if (!agpdev || !handle)
302 		return -EINVAL;
303 
304 	return -agp_unbind_memory(agpdev, handle);
305 }
306 
307 /**
308  * Unbind AGP memory from the GATT (ioctl).
309  *
310  * \param inode device inode.
311  * \param file_priv DRM file private.
312  * \param cmd command.
313  * \param arg pointer to a drm_agp_binding structure.
314  * \return zero on success or a negative number on failure.
315  *
316  * Verifies the AGP device is present and acquired, looks-up the AGP memory
317  * entry and passes it to the unbind_agp() function.
318  */
319 int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
320 {
321 	struct drm_agp_mem *entry;
322 	int ret;
323 
324 	if (!dev->agp || !dev->agp->acquired)
325 		return -EINVAL;
326 	entry = drm_agp_lookup_entry(dev, (void *)request->handle);
327 	if (entry == NULL || !entry->bound)
328 		return -EINVAL;
329 	ret = drm_agp_unbind_memory(entry->handle);
330 	if (ret == 0)
331 		entry->bound = 0;
332 	return ret;
333 }
334 EXPORT_SYMBOL(drm_agp_unbind);
335 
336 
337 int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
338 			 struct drm_file *file_priv)
339 {
340 	struct drm_agp_binding request;
341 
342 	request = *(struct drm_agp_binding *) data;
343 
344 	return drm_agp_unbind(dev, &request);
345 }
346 
347 static int drm_agp_bind_memory(void *handle, off_t start)
348 {
349 	device_t agpdev;
350 
351 	agpdev = agp_find_device();
352 	if (!agpdev || !handle)
353 		return -EINVAL;
354 
355 	return -agp_bind_memory(agpdev, handle, start * PAGE_SIZE);
356 }
357 
358 /**
359  * Bind AGP memory into the GATT (ioctl)
360  *
361  * \param inode device inode.
362  * \param file_priv DRM file private.
363  * \param cmd command.
364  * \param arg pointer to a drm_agp_binding structure.
365  * \return zero on success or a negative number on failure.
366  *
367  * Verifies the AGP device is present and has been acquired and that no memory
368  * is currently bound into the GATT. Looks-up the AGP memory entry and passes
369  * it to bind_agp() function.
370  */
371 int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
372 {
373 	struct drm_agp_mem *entry;
374 	int retcode;
375 	int page;
376 
377 	if (!dev->agp || !dev->agp->acquired)
378 		return -EINVAL;
379 
380 	DRM_DEBUG("agp_bind, page_size=%x\n", (int)PAGE_SIZE);
381 
382 	entry = drm_agp_lookup_entry(dev, (void *)request->handle);
383 	if (entry == NULL || entry->bound)
384 		return -EINVAL;
385 
386 	page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
387 
388 	retcode = drm_agp_bind_memory(entry->handle, page);
389 	if (retcode == 0)
390 		entry->bound = dev->agp->base + (page << PAGE_SHIFT);
391 
392 	return retcode;
393 }
394 EXPORT_SYMBOL(drm_agp_bind);
395 
396 
397 int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
398 		       struct drm_file *file_priv)
399 {
400 	struct drm_agp_binding request;
401 
402 	request = *(struct drm_agp_binding *) data;
403 
404 	return drm_agp_bind(dev, &request);
405 }
406 
407 static int drm_agp_free_memory(void *handle)
408 {
409 	device_t agpdev;
410 
411 	agpdev = agp_find_device();
412 	if (!agpdev || !handle)
413 		return 0;
414 
415 	agp_free_memory(agpdev, handle);
416 	return 1;
417 }
418 
419 /**
420  * Free AGP memory (ioctl).
421  *
422  * \param inode device inode.
423  * \param file_priv DRM file private.
424  * \param cmd command.
425  * \param arg pointer to a drm_agp_buffer structure.
426  * \return zero on success or a negative number on failure.
427  *
428  * Verifies the AGP device is present and has been acquired and looks up the
429  * AGP memory entry. If the memory it's currently bound, unbind it via
430  * unbind_agp(). Frees it via free_agp() as well as the entry itself
431  * and unlinks from the doubly linked list it's inserted in.
432  */
433 int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
434 {
435 	struct drm_agp_mem *entry;
436 
437 	if (!dev->agp || !dev->agp->acquired)
438 		return -EINVAL;
439 	entry = drm_agp_lookup_entry(dev, (void*)request->handle);
440 	if (entry == NULL)
441 		return -EINVAL;
442 
443 	if (entry->prev)
444 		entry->prev->next = entry->next;
445 	else
446 		dev->agp->memory  = entry->next;
447 	if (entry->next)
448 		entry->next->prev = entry->prev;
449 
450 	if (entry->bound)
451 		drm_agp_unbind_memory(entry->handle);
452 
453 	drm_agp_free_memory(entry->handle);
454 	kfree(entry);
455 	return 0;
456 }
457 EXPORT_SYMBOL(drm_agp_free);
458 
459 
460 
461 int drm_agp_free_ioctl(struct drm_device *dev, void *data,
462 		       struct drm_file *file_priv)
463 {
464 	struct drm_agp_buffer request;
465 
466 	request = *(struct drm_agp_buffer *) data;
467 
468 	return drm_agp_free(dev, &request);
469 }
470 
471 /**
472  * Initialize the AGP resources.
473  *
474  * \return pointer to a drm_agp_head structure.
475  *
476  * Gets the drm_agp_t structure which is made available by the agpgart module
477  * via the inter_module_* functions. Creates and initializes a drm_agp_head
478  * structure.
479  *
480  * Note that final cleanup of the kmalloced structure is directly done in
481  * drm_pci_agp_destroy.
482  */
483 struct drm_agp_head *drm_agp_init(struct drm_device *dev)
484 {
485 	device_t agpdev;
486 	struct drm_agp_head *head = NULL;
487 	int      agp_available = 1;
488 
489 	agpdev = agp_find_device();
490 	if (!agpdev)
491 		agp_available = 0;
492 
493 	DRM_DEBUG("agp_available = %d\n", agp_available);
494 
495 	if (agp_available) {
496 		head = kmalloc(sizeof(*head), M_DRM,
497 				M_WAITOK | M_NULLOK | M_ZERO);
498 		if (head == NULL)
499 			return NULL;
500 		head->agpdev = agpdev;
501 		agp_get_info(agpdev, &head->agp_info);
502 		head->base = head->agp_info.ai_aperture_base;
503 		head->memory = NULL;
504 		DRM_INFO("AGP at 0x%08lx %dMB\n",
505 			 (long)head->agp_info.ai_aperture_base,
506 			 (int)(head->agp_info.ai_aperture_size >> 20));
507 	}
508 	return head;
509 }
510 
511 /**
512  * drm_agp_clear - Clear AGP resource list
513  * @dev: DRM device
514  *
515  * Iterate over all AGP resources and remove them. But keep the AGP head
516  * intact so it can still be used. It is safe to call this if AGP is disabled or
517  * was already removed.
518  *
519  * If DRIVER_MODESET is active, nothing is done to protect the modesetting
520  * resources from getting destroyed. Drivers are responsible of cleaning them up
521  * during device shutdown.
522  */
523 void drm_agp_clear(struct drm_device *dev)
524 {
525 	struct drm_agp_mem *entry, *nexte;
526 
527 	if (!dev->agp)
528 		return;
529 	if (drm_core_check_feature(dev, DRIVER_MODESET))
530 		return;
531 
532 	/* Remove AGP resources, but leave dev->agp intact until
533 	 * drm_unload is called.
534 	 */
535 	for (entry = dev->agp->memory; entry; entry = nexte) {
536 		nexte = entry->next;
537 		if (entry->bound)
538 			drm_agp_unbind_memory(entry->handle);
539 		drm_agp_free_memory(entry->handle);
540 		kfree(entry);
541 	}
542 	dev->agp->memory = NULL;
543 
544 	if (dev->agp->acquired)
545 		drm_agp_release(dev);
546 
547 	dev->agp->acquired = 0;
548 	dev->agp->enabled = 0;
549 }
550 
551 #endif /* __OS_HAS_AGP */
552