1e5411345Szrj /**
2e5411345Szrj * \file drm_agpsupport.c
3e5411345Szrj * DRM support for AGP/GART backend
4e5411345Szrj *
5e5411345Szrj * \author Rickard E. (Rik) Faith <faith@valinux.com>
6e5411345Szrj * \author Gareth Hughes <gareth@valinux.com>
7e5411345Szrj */
8e5411345Szrj
9e5411345Szrj /*
107f3c3d6fSHasso Tepper * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
117f3c3d6fSHasso Tepper * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
127f3c3d6fSHasso Tepper * All Rights Reserved.
137f3c3d6fSHasso Tepper *
147f3c3d6fSHasso Tepper * Permission is hereby granted, free of charge, to any person obtaining a
157f3c3d6fSHasso Tepper * copy of this software and associated documentation files (the "Software"),
167f3c3d6fSHasso Tepper * to deal in the Software without restriction, including without limitation
177f3c3d6fSHasso Tepper * the rights to use, copy, modify, merge, publish, distribute, sublicense,
187f3c3d6fSHasso Tepper * and/or sell copies of the Software, and to permit persons to whom the
197f3c3d6fSHasso Tepper * Software is furnished to do so, subject to the following conditions:
207f3c3d6fSHasso Tepper *
217f3c3d6fSHasso Tepper * The above copyright notice and this permission notice (including the next
227f3c3d6fSHasso Tepper * paragraph) shall be included in all copies or substantial portions of the
237f3c3d6fSHasso Tepper * Software.
247f3c3d6fSHasso Tepper *
257f3c3d6fSHasso Tepper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
267f3c3d6fSHasso Tepper * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
277f3c3d6fSHasso Tepper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
287f3c3d6fSHasso Tepper * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
297f3c3d6fSHasso Tepper * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
307f3c3d6fSHasso Tepper * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
317f3c3d6fSHasso Tepper * OTHER DEALINGS IN THE SOFTWARE.
327f3c3d6fSHasso Tepper */
337f3c3d6fSHasso Tepper
3418e26a6dSFrançois Tigeot #include <drm/drmP.h>
351b13d190SFrançois Tigeot #include <linux/module.h>
361b13d190SFrançois Tigeot #include "drm_legacy.h"
377f3c3d6fSHasso Tepper
387f3c3d6fSHasso Tepper #include <dev/agp/agpreg.h>
397f3c3d6fSHasso Tepper #include <bus/pci/pcireg.h>
407f3c3d6fSHasso Tepper
41e5411345Szrj /**
42e5411345Szrj * Get AGP information.
43e5411345Szrj *
44e5411345Szrj * \param inode device inode.
45e5411345Szrj * \param file_priv DRM file private.
46e5411345Szrj * \param cmd command.
47e5411345Szrj * \param arg pointer to a (output) drm_agp_info structure.
48e5411345Szrj * \return zero on success or a negative number on failure.
49e5411345Szrj *
50e5411345Szrj * Verifies the AGP device has been initialized and acquired and fills in the
51e5411345Szrj * drm_agp_info structure with the information in drm_agp_head::agp_info.
527f3c3d6fSHasso Tepper */
drm_agp_info(struct drm_device * dev,struct drm_agp_info * info)53b3705d71SHasso Tepper int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
547f3c3d6fSHasso Tepper {
557f3c3d6fSHasso Tepper struct agp_info *kern;
567f3c3d6fSHasso Tepper
577f3c3d6fSHasso Tepper if (!dev->agp || !dev->agp->acquired)
58b922632fSImre Vadász return -EINVAL;
597f3c3d6fSHasso Tepper
609d567857SJean-Sébastien Pédron kern = &dev->agp->agp_info;
617f3c3d6fSHasso Tepper agp_get_info(dev->agp->agpdev, kern);
627f3c3d6fSHasso Tepper info->agp_version_major = 1;
637f3c3d6fSHasso Tepper info->agp_version_minor = 0;
647f3c3d6fSHasso Tepper info->mode = kern->ai_mode;
657f3c3d6fSHasso Tepper info->aperture_base = kern->ai_aperture_base;
667f3c3d6fSHasso Tepper info->aperture_size = kern->ai_aperture_size;
677f3c3d6fSHasso Tepper info->memory_allowed = kern->ai_memory_allowed;
687f3c3d6fSHasso Tepper info->memory_used = kern->ai_memory_used;
697f3c3d6fSHasso Tepper info->id_vendor = kern->ai_devid & 0xffff;
707f3c3d6fSHasso Tepper info->id_device = kern->ai_devid >> 16;
717f3c3d6fSHasso Tepper
727f3c3d6fSHasso Tepper return 0;
737f3c3d6fSHasso Tepper }
74e5411345Szrj EXPORT_SYMBOL(drm_agp_info);
75e5411345Szrj
drm_agp_info_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)76b3705d71SHasso Tepper int drm_agp_info_ioctl(struct drm_device *dev, void *data,
77b3705d71SHasso Tepper struct drm_file *file_priv)
787f3c3d6fSHasso Tepper {
79b3705d71SHasso Tepper struct drm_agp_info info;
80e5411345Szrj int err;
817f3c3d6fSHasso Tepper
827f3c3d6fSHasso Tepper err = drm_agp_info(dev, &info);
83e5411345Szrj if (err)
847f3c3d6fSHasso Tepper return err;
857f3c3d6fSHasso Tepper
86b3705d71SHasso Tepper *(struct drm_agp_info *) data = info;
877f3c3d6fSHasso Tepper return 0;
887f3c3d6fSHasso Tepper }
897f3c3d6fSHasso Tepper
90e5411345Szrj /**
91e5411345Szrj * Acquire the AGP device.
92e5411345Szrj *
93e5411345Szrj * \param dev DRM device that is to acquire AGP.
94e5411345Szrj * \return zero on success or a negative number on failure.
95e5411345Szrj *
96e5411345Szrj * Verifies the AGP device hasn't been acquired before and calls
97e5411345Szrj * \c agp_backend_acquire.
98e5411345Szrj */
drm_agp_acquire(struct drm_device * dev)99b3705d71SHasso Tepper int drm_agp_acquire(struct drm_device *dev)
1007f3c3d6fSHasso Tepper {
1017f3c3d6fSHasso Tepper int retcode;
1027f3c3d6fSHasso Tepper
1037f3c3d6fSHasso Tepper if (!dev->agp || dev->agp->acquired)
104b922632fSImre Vadász return -EINVAL;
1057f3c3d6fSHasso Tepper
106b922632fSImre Vadász retcode = -agp_acquire(dev->agp->agpdev);
1077f3c3d6fSHasso Tepper if (retcode)
1087f3c3d6fSHasso Tepper return retcode;
1097f3c3d6fSHasso Tepper
1107f3c3d6fSHasso Tepper dev->agp->acquired = 1;
1117f3c3d6fSHasso Tepper return 0;
1127f3c3d6fSHasso Tepper }
113e5411345Szrj EXPORT_SYMBOL(drm_agp_acquire);
114e5411345Szrj
115e5411345Szrj /**
116e5411345Szrj * Acquire the AGP device (ioctl).
117e5411345Szrj *
118e5411345Szrj * \param inode device inode.
119e5411345Szrj * \param file_priv DRM file private.
120e5411345Szrj * \param cmd command.
121e5411345Szrj * \param arg user argument.
122e5411345Szrj * \return zero on success or a negative number on failure.
123e5411345Szrj *
124e5411345Szrj * Verifies the AGP device hasn't been acquired before and calls
125e5411345Szrj * \c agp_backend_acquire.
126e5411345Szrj */
drm_agp_acquire_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)127e5411345Szrj int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
128b3705d71SHasso Tepper struct drm_file *file_priv)
1297f3c3d6fSHasso Tepper {
130e5411345Szrj return drm_agp_acquire(dev);
1317f3c3d6fSHasso Tepper }
1327f3c3d6fSHasso Tepper
133e5411345Szrj /**
134e5411345Szrj * Release the AGP device.
135e5411345Szrj *
136e5411345Szrj * \param dev DRM device that is to release AGP.
137e5411345Szrj * \return zero on success or a negative number on failure.
138e5411345Szrj *
139e5411345Szrj * Verifies the AGP device has been acquired and calls \c agp_backend_release.
140e5411345Szrj */
drm_agp_release(struct drm_device * dev)141b3705d71SHasso Tepper int drm_agp_release(struct drm_device *dev)
1427f3c3d6fSHasso Tepper {
1437f3c3d6fSHasso Tepper if (!dev->agp || !dev->agp->acquired)
144b922632fSImre Vadász return -EINVAL;
1457f3c3d6fSHasso Tepper agp_release(dev->agp->agpdev);
1467f3c3d6fSHasso Tepper dev->agp->acquired = 0;
1477f3c3d6fSHasso Tepper return 0;
1487f3c3d6fSHasso Tepper }
149e5411345Szrj EXPORT_SYMBOL(drm_agp_release);
1507f3c3d6fSHasso Tepper
drm_agp_release_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)151e5411345Szrj int drm_agp_release_ioctl(struct drm_device *dev, void *data,
152e5411345Szrj struct drm_file *file_priv)
153e5411345Szrj {
154e5411345Szrj return drm_agp_release(dev);
155e5411345Szrj }
156e5411345Szrj
157e5411345Szrj /**
158e5411345Szrj * Enable the AGP bus.
159e5411345Szrj *
160e5411345Szrj * \param dev DRM device that has previously acquired AGP.
161e5411345Szrj * \param mode Requested AGP mode.
162e5411345Szrj * \return zero on success or a negative number on failure.
163e5411345Szrj *
164e5411345Szrj * Verifies the AGP device has been acquired but not enabled, and calls
165e5411345Szrj * \c agp_enable.
166e5411345Szrj */
drm_agp_enable(struct drm_device * dev,struct drm_agp_mode mode)167b3705d71SHasso Tepper int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode)
1687f3c3d6fSHasso Tepper {
1697f3c3d6fSHasso Tepper if (!dev->agp || !dev->agp->acquired)
170b922632fSImre Vadász return -EINVAL;
1717f3c3d6fSHasso Tepper
1727f3c3d6fSHasso Tepper dev->agp->mode = mode.mode;
1737f3c3d6fSHasso Tepper agp_enable(dev->agp->agpdev, mode.mode);
1747f3c3d6fSHasso Tepper dev->agp->enabled = 1;
1757f3c3d6fSHasso Tepper return 0;
1767f3c3d6fSHasso Tepper }
177e5411345Szrj EXPORT_SYMBOL(drm_agp_enable);
178e5411345Szrj
drm_agp_enable_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)179b3705d71SHasso Tepper int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
180b3705d71SHasso Tepper struct drm_file *file_priv)
1817f3c3d6fSHasso Tepper {
182b3705d71SHasso Tepper struct drm_agp_mode mode;
1837f3c3d6fSHasso Tepper
184b3705d71SHasso Tepper mode = *(struct drm_agp_mode *) data;
1857f3c3d6fSHasso Tepper
1867f3c3d6fSHasso Tepper return drm_agp_enable(dev, mode);
1877f3c3d6fSHasso Tepper }
1887f3c3d6fSHasso Tepper
drm_agp_allocate_memory(size_t pages,u32 type)189e5411345Szrj static void *drm_agp_allocate_memory(size_t pages, u32 type)
190e5411345Szrj {
191e5411345Szrj device_t agpdev;
192e5411345Szrj
193e5411345Szrj agpdev = agp_find_device();
194e5411345Szrj if (!agpdev)
195e5411345Szrj return NULL;
196e5411345Szrj
197e5411345Szrj return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT);
198e5411345Szrj }
199e5411345Szrj
200e5411345Szrj /**
201e5411345Szrj * Allocate AGP memory.
202e5411345Szrj *
203e5411345Szrj * \param inode device inode.
204e5411345Szrj * \param file_priv file private pointer.
205e5411345Szrj * \param cmd command.
206e5411345Szrj * \param arg pointer to a drm_agp_buffer structure.
207e5411345Szrj * \return zero on success or a negative number on failure.
208e5411345Szrj *
209e5411345Szrj * Verifies the AGP device is present and has been acquired, allocates the
210e5411345Szrj * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
211e5411345Szrj */
drm_agp_alloc(struct drm_device * dev,struct drm_agp_buffer * request)212b3705d71SHasso Tepper int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
2137f3c3d6fSHasso Tepper {
214e5411345Szrj struct drm_agp_mem *entry;
2157f3c3d6fSHasso Tepper void *handle;
2167f3c3d6fSHasso Tepper unsigned long pages;
2177f3c3d6fSHasso Tepper u_int32_t type;
2187f3c3d6fSHasso Tepper struct agp_memory_info info;
2197f3c3d6fSHasso Tepper
2207f3c3d6fSHasso Tepper if (!dev->agp || !dev->agp->acquired)
221b922632fSImre Vadász return -EINVAL;
2227f3c3d6fSHasso Tepper
223f8677ba6SMatthew Dillon entry = kmalloc(sizeof(*entry), M_DRM, M_WAITOK | M_NULLOK | M_ZERO);
2247f3c3d6fSHasso Tepper if (entry == NULL)
225b922632fSImre Vadász return -ENOMEM;
2267f3c3d6fSHasso Tepper
2277f3c3d6fSHasso Tepper pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
2287f3c3d6fSHasso Tepper type = (u_int32_t) request->type;
2297f3c3d6fSHasso Tepper
2307f3c3d6fSHasso Tepper handle = drm_agp_allocate_memory(pages, type);
2317f3c3d6fSHasso Tepper if (handle == NULL) {
232175896dfSzrj kfree(entry);
233b922632fSImre Vadász return -ENOMEM;
2347f3c3d6fSHasso Tepper }
2357f3c3d6fSHasso Tepper
2367f3c3d6fSHasso Tepper entry->handle = handle;
2377f3c3d6fSHasso Tepper entry->bound = 0;
2387f3c3d6fSHasso Tepper entry->pages = pages;
2397f3c3d6fSHasso Tepper entry->prev = NULL;
2407f3c3d6fSHasso Tepper entry->next = dev->agp->memory;
2417f3c3d6fSHasso Tepper if (dev->agp->memory)
2427f3c3d6fSHasso Tepper dev->agp->memory->prev = entry;
2437f3c3d6fSHasso Tepper dev->agp->memory = entry;
2447f3c3d6fSHasso Tepper
2457f3c3d6fSHasso Tepper agp_memory_info(dev->agp->agpdev, entry->handle, &info);
2467f3c3d6fSHasso Tepper
2477f3c3d6fSHasso Tepper request->handle = (unsigned long) entry->handle;
2487f3c3d6fSHasso Tepper request->physical = info.ami_physical;
2497f3c3d6fSHasso Tepper
2507f3c3d6fSHasso Tepper return 0;
2517f3c3d6fSHasso Tepper }
252e5411345Szrj EXPORT_SYMBOL(drm_agp_alloc);
253e5411345Szrj
2547f3c3d6fSHasso Tepper
drm_agp_alloc_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)255b3705d71SHasso Tepper int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
256b3705d71SHasso Tepper struct drm_file *file_priv)
2577f3c3d6fSHasso Tepper {
258b3705d71SHasso Tepper struct drm_agp_buffer request;
2597f3c3d6fSHasso Tepper int retcode;
2607f3c3d6fSHasso Tepper
261b3705d71SHasso Tepper request = *(struct drm_agp_buffer *) data;
2627f3c3d6fSHasso Tepper
2637f3c3d6fSHasso Tepper retcode = drm_agp_alloc(dev, &request);
2647f3c3d6fSHasso Tepper
265b3705d71SHasso Tepper *(struct drm_agp_buffer *) data = request;
2667f3c3d6fSHasso Tepper
2677f3c3d6fSHasso Tepper return retcode;
2687f3c3d6fSHasso Tepper }
2697f3c3d6fSHasso Tepper
270e5411345Szrj /**
271e5411345Szrj * Search for the AGP memory entry associated with a handle.
272e5411345Szrj *
273e5411345Szrj * \param dev DRM device structure.
274e5411345Szrj * \param handle AGP memory handle.
275e5411345Szrj * \return pointer to the drm_agp_mem structure associated with \p handle.
276e5411345Szrj *
277e5411345Szrj * Walks through drm_agp_head::memory until finding a matching handle.
278e5411345Szrj */
drm_agp_lookup_entry(struct drm_device * dev,void * handle)279e5411345Szrj static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
280b3705d71SHasso Tepper void *handle)
2817f3c3d6fSHasso Tepper {
282e5411345Szrj struct drm_agp_mem *entry;
2837f3c3d6fSHasso Tepper
2847f3c3d6fSHasso Tepper for (entry = dev->agp->memory; entry; entry = entry->next) {
285e5411345Szrj if (entry->handle == handle)
286e5411345Szrj return entry;
2877f3c3d6fSHasso Tepper }
2887f3c3d6fSHasso Tepper return NULL;
2897f3c3d6fSHasso Tepper }
2907f3c3d6fSHasso Tepper
drm_agp_unbind_memory(void * handle)291e5411345Szrj static int drm_agp_unbind_memory(void *handle)
292e5411345Szrj {
293e5411345Szrj device_t agpdev;
294e5411345Szrj
295e5411345Szrj agpdev = agp_find_device();
296e5411345Szrj if (!agpdev || !handle)
297e5411345Szrj return -EINVAL;
298e5411345Szrj
299e5411345Szrj return -agp_unbind_memory(agpdev, handle);
300e5411345Szrj }
301e5411345Szrj
302e5411345Szrj /**
303e5411345Szrj * Unbind AGP memory from the GATT (ioctl).
304e5411345Szrj *
305e5411345Szrj * \param inode device inode.
306e5411345Szrj * \param file_priv DRM file private.
307e5411345Szrj * \param cmd command.
308e5411345Szrj * \param arg pointer to a drm_agp_binding structure.
309e5411345Szrj * \return zero on success or a negative number on failure.
310e5411345Szrj *
311e5411345Szrj * Verifies the AGP device is present and acquired, looks-up the AGP memory
312e5411345Szrj * entry and passes it to the unbind_agp() function.
313e5411345Szrj */
drm_agp_unbind(struct drm_device * dev,struct drm_agp_binding * request)314b3705d71SHasso Tepper int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
3157f3c3d6fSHasso Tepper {
316e5411345Szrj struct drm_agp_mem *entry;
317e5411345Szrj int ret;
3187f3c3d6fSHasso Tepper
3197f3c3d6fSHasso Tepper if (!dev->agp || !dev->agp->acquired)
320e5411345Szrj return -EINVAL;
3217f3c3d6fSHasso Tepper entry = drm_agp_lookup_entry(dev, (void *)request->handle);
3227f3c3d6fSHasso Tepper if (entry == NULL || !entry->bound)
323e5411345Szrj return -EINVAL;
324e5411345Szrj ret = drm_agp_unbind_memory(entry->handle);
325e5411345Szrj if (ret == 0)
3267f3c3d6fSHasso Tepper entry->bound = 0;
327e5411345Szrj return ret;
3287f3c3d6fSHasso Tepper }
329e5411345Szrj EXPORT_SYMBOL(drm_agp_unbind);
330e5411345Szrj
3317f3c3d6fSHasso Tepper
drm_agp_unbind_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)332b3705d71SHasso Tepper int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
333b3705d71SHasso Tepper struct drm_file *file_priv)
3347f3c3d6fSHasso Tepper {
335b3705d71SHasso Tepper struct drm_agp_binding request;
3367f3c3d6fSHasso Tepper
337b3705d71SHasso Tepper request = *(struct drm_agp_binding *) data;
3387f3c3d6fSHasso Tepper
339e5411345Szrj return drm_agp_unbind(dev, &request);
3407f3c3d6fSHasso Tepper }
3417f3c3d6fSHasso Tepper
drm_agp_bind_memory(void * handle,off_t start)342e5411345Szrj static int drm_agp_bind_memory(void *handle, off_t start)
343e5411345Szrj {
344e5411345Szrj device_t agpdev;
345e5411345Szrj
346e5411345Szrj agpdev = agp_find_device();
347e5411345Szrj if (!agpdev || !handle)
348e5411345Szrj return -EINVAL;
349e5411345Szrj
350e5411345Szrj return -agp_bind_memory(agpdev, handle, start * PAGE_SIZE);
351e5411345Szrj }
352e5411345Szrj
353e5411345Szrj /**
354e5411345Szrj * Bind AGP memory into the GATT (ioctl)
355e5411345Szrj *
356e5411345Szrj * \param inode device inode.
357e5411345Szrj * \param file_priv DRM file private.
358e5411345Szrj * \param cmd command.
359e5411345Szrj * \param arg pointer to a drm_agp_binding structure.
360e5411345Szrj * \return zero on success or a negative number on failure.
361e5411345Szrj *
362e5411345Szrj * Verifies the AGP device is present and has been acquired and that no memory
363e5411345Szrj * is currently bound into the GATT. Looks-up the AGP memory entry and passes
364e5411345Szrj * it to bind_agp() function.
365e5411345Szrj */
drm_agp_bind(struct drm_device * dev,struct drm_agp_binding * request)366b3705d71SHasso Tepper int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
3677f3c3d6fSHasso Tepper {
368e5411345Szrj struct drm_agp_mem *entry;
3697f3c3d6fSHasso Tepper int retcode;
3707f3c3d6fSHasso Tepper int page;
3717f3c3d6fSHasso Tepper
3727f3c3d6fSHasso Tepper if (!dev->agp || !dev->agp->acquired)
373b922632fSImre Vadász return -EINVAL;
3747f3c3d6fSHasso Tepper
3755718399fSFrançois Tigeot DRM_DEBUG("agp_bind, page_size=%x\n", (int)PAGE_SIZE);
3767f3c3d6fSHasso Tepper
3777f3c3d6fSHasso Tepper entry = drm_agp_lookup_entry(dev, (void *)request->handle);
3787f3c3d6fSHasso Tepper if (entry == NULL || entry->bound)
379b922632fSImre Vadász return -EINVAL;
3807f3c3d6fSHasso Tepper
3817f3c3d6fSHasso Tepper page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
3827f3c3d6fSHasso Tepper
3837f3c3d6fSHasso Tepper retcode = drm_agp_bind_memory(entry->handle, page);
3847f3c3d6fSHasso Tepper if (retcode == 0)
3857f3c3d6fSHasso Tepper entry->bound = dev->agp->base + (page << PAGE_SHIFT);
3867f3c3d6fSHasso Tepper
3877f3c3d6fSHasso Tepper return retcode;
3887f3c3d6fSHasso Tepper }
389e5411345Szrj EXPORT_SYMBOL(drm_agp_bind);
390e5411345Szrj
3917f3c3d6fSHasso Tepper
drm_agp_bind_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)392b3705d71SHasso Tepper int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
393b3705d71SHasso Tepper struct drm_file *file_priv)
3947f3c3d6fSHasso Tepper {
395b3705d71SHasso Tepper struct drm_agp_binding request;
3967f3c3d6fSHasso Tepper
397b3705d71SHasso Tepper request = *(struct drm_agp_binding *) data;
3987f3c3d6fSHasso Tepper
399e5411345Szrj return drm_agp_bind(dev, &request);
4007f3c3d6fSHasso Tepper }
4017f3c3d6fSHasso Tepper
drm_agp_free_memory(void * handle)402e5411345Szrj static int drm_agp_free_memory(void *handle)
403e5411345Szrj {
404e5411345Szrj device_t agpdev;
405e5411345Szrj
406e5411345Szrj agpdev = agp_find_device();
407e5411345Szrj if (!agpdev || !handle)
408e5411345Szrj return 0;
409e5411345Szrj
410e5411345Szrj agp_free_memory(agpdev, handle);
411e5411345Szrj return 1;
412e5411345Szrj }
413e5411345Szrj
414e5411345Szrj /**
415e5411345Szrj * Free AGP memory (ioctl).
416e5411345Szrj *
417e5411345Szrj * \param inode device inode.
418e5411345Szrj * \param file_priv DRM file private.
419e5411345Szrj * \param cmd command.
420e5411345Szrj * \param arg pointer to a drm_agp_buffer structure.
421e5411345Szrj * \return zero on success or a negative number on failure.
422e5411345Szrj *
423e5411345Szrj * Verifies the AGP device is present and has been acquired and looks up the
424e5411345Szrj * AGP memory entry. If the memory it's currently bound, unbind it via
425e5411345Szrj * unbind_agp(). Frees it via free_agp() as well as the entry itself
426e5411345Szrj * and unlinks from the doubly linked list it's inserted in.
427e5411345Szrj */
drm_agp_free(struct drm_device * dev,struct drm_agp_buffer * request)428b3705d71SHasso Tepper int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
4297f3c3d6fSHasso Tepper {
430e5411345Szrj struct drm_agp_mem *entry;
4317f3c3d6fSHasso Tepper
4327f3c3d6fSHasso Tepper if (!dev->agp || !dev->agp->acquired)
433b922632fSImre Vadász return -EINVAL;
4347f3c3d6fSHasso Tepper entry = drm_agp_lookup_entry(dev, (void*)request->handle);
4357f3c3d6fSHasso Tepper if (entry == NULL)
436b922632fSImre Vadász return -EINVAL;
4377f3c3d6fSHasso Tepper
4387f3c3d6fSHasso Tepper if (entry->prev)
4397f3c3d6fSHasso Tepper entry->prev->next = entry->next;
4407f3c3d6fSHasso Tepper else
4417f3c3d6fSHasso Tepper dev->agp->memory = entry->next;
4427f3c3d6fSHasso Tepper if (entry->next)
4437f3c3d6fSHasso Tepper entry->next->prev = entry->prev;
4447f3c3d6fSHasso Tepper
4457f3c3d6fSHasso Tepper if (entry->bound)
4467f3c3d6fSHasso Tepper drm_agp_unbind_memory(entry->handle);
447e5411345Szrj
4487f3c3d6fSHasso Tepper drm_agp_free_memory(entry->handle);
449e5411345Szrj kfree(entry);
4507f3c3d6fSHasso Tepper return 0;
4517f3c3d6fSHasso Tepper }
452e5411345Szrj EXPORT_SYMBOL(drm_agp_free);
453e5411345Szrj
454e5411345Szrj
drm_agp_free_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)455b3705d71SHasso Tepper int drm_agp_free_ioctl(struct drm_device *dev, void *data,
456b3705d71SHasso Tepper struct drm_file *file_priv)
4577f3c3d6fSHasso Tepper {
458b3705d71SHasso Tepper struct drm_agp_buffer request;
4597f3c3d6fSHasso Tepper
460b3705d71SHasso Tepper request = *(struct drm_agp_buffer *) data;
4617f3c3d6fSHasso Tepper
462e5411345Szrj return drm_agp_free(dev, &request);
4637f3c3d6fSHasso Tepper }
4647f3c3d6fSHasso Tepper
465e5411345Szrj /**
466e5411345Szrj * Initialize the AGP resources.
467e5411345Szrj *
468e5411345Szrj * \return pointer to a drm_agp_head structure.
469e5411345Szrj *
470e5411345Szrj * Gets the drm_agp_t structure which is made available by the agpgart module
471e5411345Szrj * via the inter_module_* functions. Creates and initializes a drm_agp_head
472e5411345Szrj * structure.
473e5411345Szrj *
474e5411345Szrj * Note that final cleanup of the kmalloced structure is directly done in
475e5411345Szrj * drm_pci_agp_destroy.
476e5411345Szrj */
drm_agp_init(struct drm_device * dev)477e5411345Szrj struct drm_agp_head *drm_agp_init(struct drm_device *dev)
4787f3c3d6fSHasso Tepper {
4797f3c3d6fSHasso Tepper device_t agpdev;
4801b13d190SFrançois Tigeot struct drm_agp_head *head = NULL;
4817f3c3d6fSHasso Tepper int agp_available = 1;
4827f3c3d6fSHasso Tepper
483e5411345Szrj agpdev = agp_find_device();
4847f3c3d6fSHasso Tepper if (!agpdev)
4857f3c3d6fSHasso Tepper agp_available = 0;
4867f3c3d6fSHasso Tepper
4877f3c3d6fSHasso Tepper DRM_DEBUG("agp_available = %d\n", agp_available);
4887f3c3d6fSHasso Tepper
4897f3c3d6fSHasso Tepper if (agp_available) {
4905a3b77d5SFrançois Tigeot head = kmalloc(sizeof(*head), M_DRM,
491f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | M_ZERO);
4927f3c3d6fSHasso Tepper if (head == NULL)
4937f3c3d6fSHasso Tepper return NULL;
4947f3c3d6fSHasso Tepper head->agpdev = agpdev;
4959d567857SJean-Sébastien Pédron agp_get_info(agpdev, &head->agp_info);
4969d567857SJean-Sébastien Pédron head->base = head->agp_info.ai_aperture_base;
4977f3c3d6fSHasso Tepper head->memory = NULL;
4987f3c3d6fSHasso Tepper DRM_INFO("AGP at 0x%08lx %dMB\n",
4999d567857SJean-Sébastien Pédron (long)head->agp_info.ai_aperture_base,
5009d567857SJean-Sébastien Pédron (int)(head->agp_info.ai_aperture_size >> 20));
5017f3c3d6fSHasso Tepper }
5027f3c3d6fSHasso Tepper return head;
5037f3c3d6fSHasso Tepper }
504*a85cb24fSFrançois Tigeot /* Only exported for i810.ko */
505*a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_agp_init);
5067f3c3d6fSHasso Tepper
507e5411345Szrj /**
5088621f407SFrançois Tigeot * drm_legacy_agp_clear - Clear AGP resource list
509e5411345Szrj * @dev: DRM device
510e5411345Szrj *
511e5411345Szrj * Iterate over all AGP resources and remove them. But keep the AGP head
512e5411345Szrj * intact so it can still be used. It is safe to call this if AGP is disabled or
513e5411345Szrj * was already removed.
514e5411345Szrj *
5151dedbd3bSFrançois Tigeot * Cleanup is only done for drivers who have DRIVER_LEGACY set.
516e5411345Szrj */
drm_legacy_agp_clear(struct drm_device * dev)5178621f407SFrançois Tigeot void drm_legacy_agp_clear(struct drm_device *dev)
5187f3c3d6fSHasso Tepper {
519e5411345Szrj struct drm_agp_mem *entry, *nexte;
5207f3c3d6fSHasso Tepper
521e5411345Szrj if (!dev->agp)
522e5411345Szrj return;
5231dedbd3bSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_LEGACY))
524e5411345Szrj return;
5257f3c3d6fSHasso Tepper
526e5411345Szrj /* Remove AGP resources, but leave dev->agp intact until
527e5411345Szrj * drm_unload is called.
528e5411345Szrj */
529e5411345Szrj for (entry = dev->agp->memory; entry; entry = nexte) {
530e5411345Szrj nexte = entry->next;
531e5411345Szrj if (entry->bound)
532e5411345Szrj drm_agp_unbind_memory(entry->handle);
533e5411345Szrj drm_agp_free_memory(entry->handle);
534e5411345Szrj kfree(entry);
535e5411345Szrj }
536e5411345Szrj dev->agp->memory = NULL;
537e5411345Szrj
538e5411345Szrj if (dev->agp->acquired)
539e5411345Szrj drm_agp_release(dev);
540e5411345Szrj
541e5411345Szrj dev->agp->acquired = 0;
542e5411345Szrj dev->agp->enabled = 0;
5437f3c3d6fSHasso Tepper }
544