blob: 4c7ad46fdd219f59c2830d2d52428763d5e606d2 [file] [log] [blame]
Qian Cai45b2fda2019-07-15 09:42:53 -04001/*
Dave Airlied985c102006-01-02 21:32:48 +11002 * \file drm_agpsupport.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * DRM support for AGP/GART backend
Dave Airlieb5e89ed2005-09-25 14:28:13 +10004 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * \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
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
Sam Ravnborg0500c042019-05-26 19:35:35 +020035#include <linux/pci.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090036#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Eric Anholt1bb88ed2009-01-15 01:16:25 -080038#include <asm/agp.h>
39
Sam Ravnborg0500c042019-05-26 19:35:35 +020040#include <drm/drm_agpsupport.h>
41#include <drm/drm_device.h>
42#include <drm/drm_drv.h>
43#include <drm/drm_file.h>
44#include <drm/drm_print.h>
45
46#include "drm_legacy.h"
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048/**
Dave Airlie7ab98402005-07-10 16:56:52 +100049 * Get AGP information.
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 *
51 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +100052 * \param file_priv DRM file private.
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 * \param cmd command.
54 * \param arg pointer to a (output) drm_agp_info structure.
55 * \return zero on success or a negative number on failure.
56 *
57 * Verifies the AGP device has been initialized and acquired and fills in the
58 * drm_agp_info structure with the information in drm_agp_head::agp_info.
59 */
Dave Airlie84b1fd12007-07-11 15:53:27 +100060int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061{
Daniel Vetterd2e546b2013-12-11 11:34:40 +010062 struct agp_kern_info *kern;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64 if (!dev->agp || !dev->agp->acquired)
65 return -EINVAL;
66
Dave Airlieb5e89ed2005-09-25 14:28:13 +100067 kern = &dev->agp->agp_info;
Dave Airlie7ab98402005-07-10 16:56:52 +100068 info->agp_version_major = kern->version.major;
69 info->agp_version_minor = kern->version.minor;
Dave Airlieb5e89ed2005-09-25 14:28:13 +100070 info->mode = kern->mode;
71 info->aperture_base = kern->aper_base;
72 info->aperture_size = kern->aper_size * 1024 * 1024;
73 info->memory_allowed = kern->max_memory << PAGE_SHIFT;
74 info->memory_used = kern->current_memory << PAGE_SHIFT;
75 info->id_vendor = kern->device->vendor;
76 info->id_device = kern->device->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Dave Airlie7ab98402005-07-10 16:56:52 +100078 return 0;
79}
80EXPORT_SYMBOL(drm_agp_info);
81
Eric Anholtc153f452007-09-03 12:06:45 +100082int drm_agp_info_ioctl(struct drm_device *dev, void *data,
83 struct drm_file *file_priv)
Dave Airlie7ab98402005-07-10 16:56:52 +100084{
Eric Anholtc153f452007-09-03 12:06:45 +100085 struct drm_agp_info *info = data;
Dave Airlie7ab98402005-07-10 16:56:52 +100086 int err;
87
Eric Anholtc153f452007-09-03 12:06:45 +100088 err = drm_agp_info(dev, info);
Dave Airlie7ab98402005-07-10 16:56:52 +100089 if (err)
90 return err;
Dave Airlieb5e89ed2005-09-25 14:28:13 +100091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 return 0;
93}
94
95/**
Dave Airlie7ab98402005-07-10 16:56:52 +100096 * Acquire the AGP device.
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 *
Dave Airlied985c102006-01-02 21:32:48 +110098 * \param dev DRM device that is to acquire AGP.
Dave Airlieb5e89ed2005-09-25 14:28:13 +100099 * \return zero on success or a negative number on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 *
101 * Verifies the AGP device hasn't been acquired before and calls
Dave Airlie7ab98402005-07-10 16:56:52 +1000102 * \c agp_backend_acquire.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 */
Meghana Madhyasthae3cbeaf2017-09-14 13:39:14 +0530104int drm_agp_acquire(struct drm_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 if (!dev->agp)
107 return -ENODEV;
108 if (dev->agp->acquired)
109 return -EBUSY;
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530110 dev->agp->bridge = agp_backend_acquire(dev->pdev);
111 if (!dev->agp->bridge)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 return -ENODEV;
113 dev->agp->acquired = 1;
114 return 0;
115}
Dave Airlie7ab98402005-07-10 16:56:52 +1000116EXPORT_SYMBOL(drm_agp_acquire);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118/**
Dave Airlie7ab98402005-07-10 16:56:52 +1000119 * Acquire the AGP device (ioctl).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 *
121 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +1000122 * \param file_priv DRM file private.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 * \param cmd command.
124 * \param arg user argument.
125 * \return zero on success or a negative number on failure.
126 *
Dave Airlie7ab98402005-07-10 16:56:52 +1000127 * Verifies the AGP device hasn't been acquired before and calls
128 * \c agp_backend_acquire.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 */
Eric Anholtc153f452007-09-03 12:06:45 +1000130int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
131 struct drm_file *file_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
Dave Airlie2c14f282008-04-21 16:47:32 +1000133 return drm_agp_acquire((struct drm_device *) file_priv->minor->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134}
135
136/**
137 * Release the AGP device.
138 *
Dave Airlied985c102006-01-02 21:32:48 +1100139 * \param dev DRM device that is to release AGP.
Dave Airlie7ab98402005-07-10 16:56:52 +1000140 * \return zero on success or a negative number on failure.
141 *
142 * Verifies the AGP device has been acquired and calls \c agp_backend_release.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 */
Meghana Madhyasthae3cbeaf2017-09-14 13:39:14 +0530144int drm_agp_release(struct drm_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
Dave Airlie7ab98402005-07-10 16:56:52 +1000146 if (!dev->agp || !dev->agp->acquired)
147 return -EINVAL;
148 agp_backend_release(dev->agp->bridge);
149 dev->agp->acquired = 0;
150 return 0;
151}
152EXPORT_SYMBOL(drm_agp_release);
153
Eric Anholtc153f452007-09-03 12:06:45 +1000154int drm_agp_release_ioctl(struct drm_device *dev, void *data,
155 struct drm_file *file_priv)
Dave Airlie7ab98402005-07-10 16:56:52 +1000156{
Dave Airlie7ab98402005-07-10 16:56:52 +1000157 return drm_agp_release(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158}
159
160/**
161 * Enable the AGP bus.
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000162 *
Dave Airlie7ab98402005-07-10 16:56:52 +1000163 * \param dev DRM device that has previously acquired AGP.
164 * \param mode Requested AGP mode.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 * \return zero on success or a negative number on failure.
166 *
167 * Verifies the AGP device has been acquired but not enabled, and calls
Dave Airlie7ab98402005-07-10 16:56:52 +1000168 * \c agp_enable.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 */
Meghana Madhyasthae3cbeaf2017-09-14 13:39:14 +0530170int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 if (!dev->agp || !dev->agp->acquired)
173 return -EINVAL;
174
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000175 dev->agp->mode = mode.mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 agp_enable(dev->agp->bridge, mode.mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 dev->agp->enabled = 1;
178 return 0;
179}
Dave Airlie7ab98402005-07-10 16:56:52 +1000180EXPORT_SYMBOL(drm_agp_enable);
181
Eric Anholtc153f452007-09-03 12:06:45 +1000182int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
183 struct drm_file *file_priv)
Dave Airlie7ab98402005-07-10 16:56:52 +1000184{
Eric Anholtc153f452007-09-03 12:06:45 +1000185 struct drm_agp_mode *mode = data;
Dave Airlie7ab98402005-07-10 16:56:52 +1000186
Eric Anholtc153f452007-09-03 12:06:45 +1000187 return drm_agp_enable(dev, *mode);
Dave Airlie7ab98402005-07-10 16:56:52 +1000188}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190/**
191 * Allocate AGP memory.
192 *
193 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +1000194 * \param file_priv file private pointer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 * \param cmd command.
196 * \param arg pointer to a drm_agp_buffer structure.
197 * \return zero on success or a negative number on failure.
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000198 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 * Verifies the AGP device is present and has been acquired, allocates the
Daniel Vetter89c37262010-08-23 22:53:36 +0200200 * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 */
Dave Airlie84b1fd12007-07-11 15:53:27 +1000202int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203{
Dave Airlie55910512007-07-11 16:53:40 +1000204 struct drm_agp_mem *entry;
Daniel Vetterd2e546b2013-12-11 11:34:40 +0100205 struct agp_memory *memory;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000206 unsigned long pages;
207 u32 type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 if (!dev->agp || !dev->agp->acquired)
210 return -EINVAL;
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530211 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
212 if (!entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 return -ENOMEM;
214
Wambui Karugab8c8a852019-10-25 12:49:07 +0300215 pages = DIV_ROUND_UP(request->size, PAGE_SIZE);
Dave Airlieefa58392005-11-11 22:33:39 +1100216 type = (u32) request->type;
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530217 memory = agp_allocate_memory(dev->agp->bridge, pages, type);
218 if (!memory) {
Eric Anholt9a298b22009-03-24 12:23:04 -0700219 kfree(entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return -ENOMEM;
221 }
222
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000223 entry->handle = (unsigned long)memory->key + 1;
224 entry->memory = memory;
225 entry->bound = 0;
226 entry->pages = pages;
Dave Airliebd1b3312007-05-26 05:01:51 +1000227 list_add(&entry->head, &dev->agp->memory);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Dave Airlieefa58392005-11-11 22:33:39 +1100229 request->handle = entry->handle;
230 request->physical = memory->physical;
231
232 return 0;
233}
234EXPORT_SYMBOL(drm_agp_alloc);
235
Eric Anholtc153f452007-09-03 12:06:45 +1000236
237int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
238 struct drm_file *file_priv)
Dave Airlieefa58392005-11-11 22:33:39 +1100239{
Eric Anholtc153f452007-09-03 12:06:45 +1000240 struct drm_agp_buffer *request = data;
Dave Airlieefa58392005-11-11 22:33:39 +1100241
Eric Anholtc153f452007-09-03 12:06:45 +1000242 return drm_agp_alloc(dev, request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245/**
246 * Search for the AGP memory entry associated with a handle.
247 *
248 * \param dev DRM device structure.
249 * \param handle AGP memory handle.
250 * \return pointer to the drm_agp_mem structure associated with \p handle.
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000251 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 * Walks through drm_agp_head::memory until finding a matching handle.
253 */
Meghana Madhyasthae3cbeaf2017-09-14 13:39:14 +0530254static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device *dev,
255 unsigned long handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
Dave Airlie55910512007-07-11 16:53:40 +1000257 struct drm_agp_mem *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Dave Airliebd1b3312007-05-26 05:01:51 +1000259 list_for_each_entry(entry, &dev->agp->memory, head) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 if (entry->handle == handle)
261 return entry;
262 }
263 return NULL;
264}
265
266/**
267 * Unbind AGP memory from the GATT (ioctl).
268 *
269 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +1000270 * \param file_priv DRM file private.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 * \param cmd command.
272 * \param arg pointer to a drm_agp_binding structure.
273 * \return zero on success or a negative number on failure.
274 *
275 * Verifies the AGP device is present and acquired, looks-up the AGP memory
276 * entry and passes it to the unbind_agp() function.
277 */
Dave Airlie84b1fd12007-07-11 15:53:27 +1000278int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Dave Airlie55910512007-07-11 16:53:40 +1000280 struct drm_agp_mem *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 int ret;
282
283 if (!dev->agp || !dev->agp->acquired)
284 return -EINVAL;
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530285 entry = drm_agp_lookup_entry(dev, request->handle);
286 if (!entry || !entry->bound)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 return -EINVAL;
288 ret = drm_unbind_agp(entry->memory);
289 if (ret == 0)
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000290 entry->bound = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return ret;
292}
Dave Airlieefa58392005-11-11 22:33:39 +1100293EXPORT_SYMBOL(drm_agp_unbind);
294
Eric Anholtc153f452007-09-03 12:06:45 +1000295
296int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
297 struct drm_file *file_priv)
Dave Airlieefa58392005-11-11 22:33:39 +1100298{
Eric Anholtc153f452007-09-03 12:06:45 +1000299 struct drm_agp_binding *request = data;
Dave Airlieefa58392005-11-11 22:33:39 +1100300
Eric Anholtc153f452007-09-03 12:06:45 +1000301 return drm_agp_unbind(dev, request);
Dave Airlieefa58392005-11-11 22:33:39 +1100302}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304/**
305 * Bind AGP memory into the GATT (ioctl)
306 *
307 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +1000308 * \param file_priv DRM file private.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 * \param cmd command.
310 * \param arg pointer to a drm_agp_binding structure.
311 * \return zero on success or a negative number on failure.
312 *
313 * Verifies the AGP device is present and has been acquired and that no memory
314 * is currently bound into the GATT. Looks-up the AGP memory entry and passes
315 * it to bind_agp() function.
316 */
Dave Airlie84b1fd12007-07-11 15:53:27 +1000317int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Dave Airlie55910512007-07-11 16:53:40 +1000319 struct drm_agp_mem *entry;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000320 int retcode;
321 int page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 if (!dev->agp || !dev->agp->acquired)
324 return -EINVAL;
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530325 entry = drm_agp_lookup_entry(dev, request->handle);
326 if (!entry || entry->bound)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 return -EINVAL;
Wambui Karugab8c8a852019-10-25 12:49:07 +0300328 page = DIV_ROUND_UP(request->offset, PAGE_SIZE);
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530329 retcode = drm_bind_agp(entry->memory, page);
330 if (retcode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 return retcode;
332 entry->bound = dev->agp->base + (page << PAGE_SHIFT);
333 DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
334 dev->agp->base, entry->bound);
335 return 0;
336}
Dave Airlieefa58392005-11-11 22:33:39 +1100337EXPORT_SYMBOL(drm_agp_bind);
338
Eric Anholtc153f452007-09-03 12:06:45 +1000339
340int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
341 struct drm_file *file_priv)
Dave Airlieefa58392005-11-11 22:33:39 +1100342{
Eric Anholtc153f452007-09-03 12:06:45 +1000343 struct drm_agp_binding *request = data;
Dave Airlieefa58392005-11-11 22:33:39 +1100344
Eric Anholtc153f452007-09-03 12:06:45 +1000345 return drm_agp_bind(dev, request);
Dave Airlieefa58392005-11-11 22:33:39 +1100346}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348/**
349 * Free AGP memory (ioctl).
350 *
351 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +1000352 * \param file_priv DRM file private.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 * \param cmd command.
354 * \param arg pointer to a drm_agp_buffer structure.
355 * \return zero on success or a negative number on failure.
356 *
357 * Verifies the AGP device is present and has been acquired and looks up the
Matt Roper1e55a532019-02-01 17:23:26 -0800358 * AGP memory entry. If the memory is currently bound, unbind it via
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 * unbind_agp(). Frees it via free_agp() as well as the entry itself
360 * and unlinks from the doubly linked list it's inserted in.
361 */
Dave Airlie84b1fd12007-07-11 15:53:27 +1000362int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Dave Airlie55910512007-07-11 16:53:40 +1000364 struct drm_agp_mem *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 if (!dev->agp || !dev->agp->acquired)
367 return -EINVAL;
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530368 entry = drm_agp_lookup_entry(dev, request->handle);
369 if (!entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return -EINVAL;
371 if (entry->bound)
372 drm_unbind_agp(entry->memory);
373
Dave Airliebd1b3312007-05-26 05:01:51 +1000374 list_del(&entry->head);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 drm_free_agp(entry->memory, entry->pages);
Eric Anholt9a298b22009-03-24 12:23:04 -0700377 kfree(entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 return 0;
379}
Dave Airlieefa58392005-11-11 22:33:39 +1100380EXPORT_SYMBOL(drm_agp_free);
381
Eric Anholtc153f452007-09-03 12:06:45 +1000382
Eric Anholtc153f452007-09-03 12:06:45 +1000383int drm_agp_free_ioctl(struct drm_device *dev, void *data,
384 struct drm_file *file_priv)
Dave Airlieefa58392005-11-11 22:33:39 +1100385{
Eric Anholtc153f452007-09-03 12:06:45 +1000386 struct drm_agp_buffer *request = data;
Dave Airlieefa58392005-11-11 22:33:39 +1100387
Eric Anholtc153f452007-09-03 12:06:45 +1000388 return drm_agp_free(dev, request);
Dave Airlieefa58392005-11-11 22:33:39 +1100389}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
391/**
392 * Initialize the AGP resources.
393 *
394 * \return pointer to a drm_agp_head structure.
395 *
Dave Airlied985c102006-01-02 21:32:48 +1100396 * Gets the drm_agp_t structure which is made available by the agpgart module
397 * via the inter_module_* functions. Creates and initializes a drm_agp_head
398 * structure.
Daniel Vetterd6e4b282013-12-11 11:34:37 +0100399 *
400 * Note that final cleanup of the kmalloced structure is directly done in
401 * drm_pci_agp_destroy.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 */
Dave Airlie55910512007-07-11 16:53:40 +1000403struct drm_agp_head *drm_agp_init(struct drm_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Dave Airlie55910512007-07-11 16:53:40 +1000405 struct drm_agp_head *head = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530407 head = kzalloc(sizeof(*head), GFP_KERNEL);
408 if (!head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 head->bridge = agp_find_bridge(dev->pdev);
411 if (!head->bridge) {
Meghana Madhyastha182e61d2017-09-14 13:40:49 +0530412 head->bridge = agp_backend_acquire(dev->pdev);
413 if (!head->bridge) {
Eric Anholt9a298b22009-03-24 12:23:04 -0700414 kfree(head);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return NULL;
416 }
417 agp_copy_info(head->bridge, &head->agp_info);
418 agp_backend_release(head->bridge);
419 } else {
420 agp_copy_info(head->bridge, &head->agp_info);
421 }
422 if (head->agp_info.chipset == NOT_SUPPORTED) {
Eric Anholt9a298b22009-03-24 12:23:04 -0700423 kfree(head);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return NULL;
425 }
Dave Airliebd1b3312007-05-26 05:01:51 +1000426 INIT_LIST_HEAD(&head->memory);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 head->cant_use_aperture = head->agp_info.cant_use_aperture;
428 head->page_mask = head->agp_info.page_mask;
Eric Anholt8b409582007-11-22 16:40:37 +1000429 head->base = head->agp_info.aper_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 return head;
431}
Daniel Vetter49d66d82017-01-25 07:26:50 +0100432/* Only exported for i810.ko */
433EXPORT_SYMBOL(drm_agp_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Eric Anholt673a3942008-07-30 12:06:12 -0700435/**
Daniel Vetter366884b2016-04-26 19:29:34 +0200436 * drm_legacy_agp_clear - Clear AGP resource list
David Herrmann28ec7112013-07-27 16:37:00 +0200437 * @dev: DRM device
438 *
439 * Iterate over all AGP resources and remove them. But keep the AGP head
440 * intact so it can still be used. It is safe to call this if AGP is disabled or
441 * was already removed.
442 *
Daniel Vetterfa538642016-08-03 21:11:10 +0200443 * Cleanup is only done for drivers who have DRIVER_LEGACY set.
David Herrmann28ec7112013-07-27 16:37:00 +0200444 */
Daniel Vetter366884b2016-04-26 19:29:34 +0200445void drm_legacy_agp_clear(struct drm_device *dev)
David Herrmann28ec7112013-07-27 16:37:00 +0200446{
447 struct drm_agp_mem *entry, *tempe;
448
Daniel Vetterd9906752013-12-11 11:34:35 +0100449 if (!dev->agp)
David Herrmann28ec7112013-07-27 16:37:00 +0200450 return;
Daniel Vetterfa538642016-08-03 21:11:10 +0200451 if (!drm_core_check_feature(dev, DRIVER_LEGACY))
David Herrmann28ec7112013-07-27 16:37:00 +0200452 return;
453
454 list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
455 if (entry->bound)
456 drm_unbind_agp(entry->memory);
457 drm_free_agp(entry->memory, entry->pages);
458 kfree(entry);
459 }
460 INIT_LIST_HEAD(&dev->agp->memory);
461
462 if (dev->agp->acquired)
463 drm_agp_release(dev);
464
465 dev->agp->acquired = 0;
466 dev->agp->enabled = 0;
467}