xref: /gfx-drm/usr/src/uts/common/io/drm/drm_agpsupport.c (revision 34389f68)
1 /*
2  * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /**
6  * \file drm_agpsupport.c
7  * DRM support for AGP/GART backend
8  *
9  * \author Rickard E. (Rik) Faith <faith@valinux.com>
10  * \author Gareth Hughes <gareth@valinux.com>
11  */
12 
13 /*
14  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
15  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
16  * Copyright (c) 2009, 2013, Intel Corporation.
17  * All Rights Reserved.
18  *
19  * Permission is hereby granted, free of charge, to any person obtaining a
20  * copy of this software and associated documentation files (the "Software"),
21  * to deal in the Software without restriction, including without limitation
22  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
23  * and/or sell copies of the Software, and to permit persons to whom the
24  * Software is furnished to do so, subject to the following conditions:
25  *
26  * The above copyright notice and this permission notice (including the next
27  * paragraph) shall be included in all copies or substantial portions of the
28  * Software.
29  *
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
33  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
34  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
35  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
36  * OTHER DEALINGS IN THE SOFTWARE.
37  */
38 
39 #include "drm.h"
40 #include "drmP.h"
41 
42 #ifndef	AGP_PAGE_SIZE
43 #define	AGP_PAGE_SIZE 4096
44 #define	AGP_PAGE_SHIFT 12
45 #endif
46 
47 /*
48  * The agpa_key field of struct agp_allocate_t actually is
49  * an index to an array. It can be zero. But we will use
50  * this agpa_key as a handle returned to userland. Generally,
51  * 0 is not a valid value for a handle, so we add an offset
52  * to the key to get a handle.
53  */
54 #define	DRM_AGP_KEY_OFFSET	8
55 
drm_agp_cleanup(struct drm_device * dev)56 void drm_agp_cleanup(struct drm_device *dev)
57 {
58 	struct drm_agp_head *agp = dev->agp;
59 
60 	(void) ldi_close(agp->agpgart_lh, FEXCL, kcred);
61 	ldi_ident_release(agp->agpgart_li);
62 }
63 
64 /**
65  * Get AGP information.
66  *
67  * \param inode device inode.
68  * \param file_priv DRM file private.
69  * \param cmd command.
70  * \param arg pointer to a (output) drm_agp_info structure.
71  * \return zero on success or a negative number on failure.
72  *
73  * Verifies the AGP device has been initialized and acquired and fills in the
74  * drm_agp_info structure with the information in drm_agp_head::agp_info.
75  */
drm_agp_info(struct drm_device * dev,struct drm_agp_info * info)76 int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
77 {
78 	agp_info_t *agpinfo;
79 
80 	if (!dev->agp || !dev->agp->acquired)
81 		return -EINVAL;
82 
83 	agpinfo = &dev->agp->agp_info;
84 	info->agp_version_major = agpinfo->agpi_version.agpv_major;
85 	info->agp_version_minor = agpinfo->agpi_version.agpv_minor;
86 	info->mode = agpinfo->agpi_mode;
87 	info->aperture_base = agpinfo->agpi_aperbase;
88 	info->aperture_size = agpinfo->agpi_apersize * 1024 * 1024;
89 	info->memory_allowed = agpinfo->agpi_pgtotal << PAGE_SHIFT;
90 	info->memory_used = agpinfo->agpi_pgused << PAGE_SHIFT;
91 	info->id_vendor = agpinfo->agpi_devid & 0xffff;
92 	info->id_device = agpinfo->agpi_devid >> 16;
93 
94 	return 0;
95 }
96 
97 /* LINTED */
drm_agp_info_ioctl(DRM_IOCTL_ARGS)98 int drm_agp_info_ioctl(DRM_IOCTL_ARGS)
99 {
100 	struct drm_agp_info *info = data;
101 	int err;
102 
103 	err = drm_agp_info(dev, info);
104 	if (err)
105 		return err;
106 
107 	return 0;
108 }
109 
110 /**
111  * Acquire the AGP device.
112  *
113  * \param dev DRM device that is to acquire AGP.
114  * \return zero on success or a negative number on failure.
115  *
116  * Verifies the AGP device hasn't been acquired before and calls
117  * \c agp_backend_acquire.
118  */
drm_agp_acquire(struct drm_device * dev)119 int drm_agp_acquire(struct drm_device * dev)
120 {
121 	if (!dev->agp)
122 		return -ENODEV;
123 	if (dev->agp->acquired)
124 		return -EBUSY;
125 	{
126 		int ret, rval;
127 		if (ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_ACQUIRE,
128 		    (uintptr_t)0, FKIOCTL, kcred, &rval)) {
129 			DRM_ERROR("AGPIOC_ACQUIRE failed");
130 			return -ret;
131 		}
132 	}
133 	dev->agp->acquired = 1;
134 	return 0;
135 }
136 
137 /**
138  * Acquire the AGP device (ioctl).
139  *
140  * \param inode device inode.
141  * \param file_priv DRM file private.
142  * \param cmd command.
143  * \param arg user argument.
144  * \return zero on success or a negative number on failure.
145  *
146  * Verifies the AGP device hasn't been acquired before and calls
147  * \c agp_backend_acquire.
148  */
149 /* LINTED */
drm_agp_acquire_ioctl(DRM_IOCTL_ARGS)150 int drm_agp_acquire_ioctl(DRM_IOCTL_ARGS)
151 {
152 	return drm_agp_acquire((struct drm_device *) file->minor->dev);
153 }
154 
155 /**
156  * Release the AGP device.
157  *
158  * \param dev DRM device that is to release AGP.
159  * \return zero on success or a negative number on failure.
160  *
161  * Verifies the AGP device has been acquired and calls \c agp_backend_release.
162  */
drm_agp_release(struct drm_device * dev)163 int drm_agp_release(struct drm_device * dev)
164 {
165 	if (!dev->agp || !dev->agp->acquired)
166 		return -EINVAL;
167 	{
168 		int ret, rval;
169 		if (ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_RELEASE,
170 		    (intptr_t)0, FKIOCTL, kcred, &rval)) {
171 			DRM_ERROR("AGPIOC_RELEASE failed");
172 			return -ret;
173 		}
174 	}
175 	dev->agp->acquired = 0;
176 	return 0;
177 }
178 
179 /* LINTED */
drm_agp_release_ioctl(DRM_IOCTL_ARGS)180 int drm_agp_release_ioctl(DRM_IOCTL_ARGS)
181 {
182 	return drm_agp_release(dev);
183 }
184 
185 /**
186  * Enable the AGP bus.
187  *
188  * \param dev DRM device that has previously acquired AGP.
189  * \param mode Requested AGP mode.
190  * \return zero on success or a negative number on failure.
191  *
192  * Verifies the AGP device has been acquired but not enabled, and calls
193  * \c agp_enable.
194  */
drm_agp_enable(struct drm_device * dev,struct drm_agp_mode mode)195 int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode)
196 {
197 	if (!dev->agp || !dev->agp->acquired)
198 		return -EINVAL;
199 
200 	dev->agp->mode = mode.mode;
201 	{
202 		agp_setup_t setup;
203 		int ret, rval;
204 		setup.agps_mode = (uint32_t)mode.mode;
205 		if (ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_SETUP,
206 		    (intptr_t)&setup, FKIOCTL, kcred, &rval)) {
207 			DRM_ERROR("AGPIOC_SETUP failed");
208 			return -ret;
209 		}
210 	}
211 	dev->agp->enabled = 1;
212 	return 0;
213 }
214 
215 /* LINTED */
drm_agp_enable_ioctl(DRM_IOCTL_ARGS)216 int drm_agp_enable_ioctl(DRM_IOCTL_ARGS)
217 {
218 	struct drm_agp_mode *mode = data;
219 
220 	return drm_agp_enable(dev, *mode);
221 }
222 
223 /**
224  * Allocate AGP memory.
225  *
226  * \param inode device inode.
227  * \param file_priv file private pointer.
228  * \param cmd command.
229  * \param arg pointer to a drm_agp_buffer structure.
230  * \return zero on success or a negative number on failure.
231  *
232  * Verifies the AGP device is present and has been acquired, allocates the
233  * memory via alloc_agp() and creates a drm_agp_mem entry for it.
234  */
drm_agp_alloc(struct drm_device * dev,struct drm_agp_buffer * request)235 int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
236 {
237 	struct drm_agp_mem *entry;
238 	agp_allocate_t alloc;
239 	unsigned long pages;
240 	int ret, rval;
241 
242 	if (!dev->agp || !dev->agp->acquired)
243 		return -EINVAL;
244 	if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
245 		return -ENOMEM;
246 
247 	(void) memset(entry, 0, sizeof(*entry));
248 
249 	pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
250 
251 	alloc.agpa_pgcount = (uint32_t) pages;
252 	alloc.agpa_type = AGP_NORMAL;
253 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_ALLOCATE,
254 	    (intptr_t)&alloc, FKIOCTL, kcred, &rval);
255 	if (ret) {
256 		DRM_ERROR("AGPIOC_ALLOCATE failed");
257 		kfree(entry, sizeof (*entry));
258 		return -ret;
259 	}
260 
261 	entry->handle = alloc.agpa_key + DRM_AGP_KEY_OFFSET;
262 	entry->bound = 0;
263 	entry->pages = (int) pages;
264 	list_add(&entry->head, &dev->agp->memory, (caddr_t)entry);
265 
266 	request->handle = entry->handle;
267 	request->physical = alloc.agpa_physical;
268 
269 	return 0;
270 }
271 
272 /* LINTED */
drm_agp_alloc_ioctl(DRM_IOCTL_ARGS)273 int drm_agp_alloc_ioctl(DRM_IOCTL_ARGS)
274 {
275 	struct drm_agp_buffer *request = data;
276 
277 	return drm_agp_alloc(dev, request);
278 }
279 
280 /**
281  * Search for the AGP memory entry associated with a handle.
282  *
283  * \param dev DRM device structure.
284  * \param handle AGP memory handle.
285  * \return pointer to the drm_agp_mem structure associated with \p handle.
286  *
287  * Walks through drm_agp_head::memory until finding a matching handle.
288  */
drm_agp_lookup_entry(struct drm_device * dev,unsigned long handle)289 static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
290 					   unsigned long handle)
291 {
292 	struct drm_agp_mem *entry;
293 
294 	list_for_each_entry(entry, struct drm_agp_mem, &dev->agp->memory, head) {
295 		if (entry->handle == handle)
296 			return entry;
297 	}
298 	return NULL;
299 }
300 
301 /**
302  * Unbind AGP memory from the GATT (ioctl).
303  *
304  * \param inode device inode.
305  * \param file_priv DRM file private.
306  * \param cmd command.
307  * \param arg pointer to a drm_agp_binding structure.
308  * \return zero on success or a negative number on failure.
309  *
310  * Verifies the AGP device is present and acquired, looks-up the AGP memory
311  * entry and passes it to the unbind_agp() function.
312  */
drm_agp_unbind(struct drm_device * dev,struct drm_agp_binding * request)313 int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
314 {
315 	struct drm_agp_mem *entry;
316 	int ret;
317 
318 	if (!dev->agp || !dev->agp->acquired)
319 		return -EINVAL;
320 	if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
321 		return -EINVAL;
322 	if (!entry->bound)
323 		return -EINVAL;
324 	{
325 		agp_unbind_t unbind;
326 		int rval;
327 		unbind.agpu_pri = 0;
328 		unbind.agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
329 		if (ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_UNBIND,
330 		    (intptr_t)&unbind, FKIOCTL, kcred, &rval)) {
331 			DRM_ERROR("AGPIOC_UNBIND failed");
332 			return -ret;
333 		}
334 	}
335 		entry->bound = 0;
336 	return ret;
337 }
338 
339 /* LINTED */
drm_agp_unbind_ioctl(DRM_IOCTL_ARGS)340 int drm_agp_unbind_ioctl(DRM_IOCTL_ARGS)
341 {
342 	struct drm_agp_binding *request = data;
343 
344 	return drm_agp_unbind(dev, request);
345 }
346 
347 /**
348  * Bind AGP memory into the GATT (ioctl)
349  *
350  * \param inode device inode.
351  * \param file_priv DRM file private.
352  * \param cmd command.
353  * \param arg pointer to a drm_agp_binding structure.
354  * \return zero on success or a negative number on failure.
355  *
356  * Verifies the AGP device is present and has been acquired and that no memory
357  * is currently bound into the GATT. Looks-up the AGP memory entry and passes
358  * it to bind_agp() function.
359  */
drm_agp_bind(struct drm_device * dev,struct drm_agp_binding * request)360 int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
361 {
362 	struct drm_agp_mem *entry;
363 	int retcode;
364 	int page;
365 
366 	if (!dev->agp || !dev->agp->acquired)
367 		return -EINVAL;
368 	if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
369 		return -EINVAL;
370 	if (entry->bound)
371 		return -EINVAL;
372 	page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
373 	{
374 		uint_t key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
375 		if (retcode = drm_agp_bind_memory(key, page, dev)) {
376 			DRM_ERROR("failed key=0x%x, page=0x%x, "
377 			    "agp_base=0x%lx", key, page, dev->agp->base);
378 			return retcode;
379 		}
380 	}
381 	entry->bound = dev->agp->base + (page << PAGE_SHIFT);
382 	DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
383 		  dev->agp->base, entry->bound);
384 	return 0;
385 }
386 
387 /* LINTED */
drm_agp_bind_ioctl(DRM_IOCTL_ARGS)388 int drm_agp_bind_ioctl(DRM_IOCTL_ARGS)
389 {
390 	struct drm_agp_binding *request = data;
391 
392 	return drm_agp_bind(dev, request);
393 }
394 
395 /**
396  * Free AGP memory (ioctl).
397  *
398  * \param inode device inode.
399  * \param file_priv DRM file private.
400  * \param cmd command.
401  * \param arg pointer to a drm_agp_buffer structure.
402  * \return zero on success or a negative number on failure.
403  *
404  * Verifies the AGP device is present and has been acquired and looks up the
405  * AGP memory entry. If the memory it's currently bound, unbind it via
406  * unbind_agp(). Frees it via free_agp() as well as the entry itself
407  * and unlinks from the doubly linked list it's inserted in.
408  */
drm_agp_free(struct drm_device * dev,struct drm_agp_buffer * request)409 int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
410 {
411 	struct drm_agp_mem *entry;
412 
413 	if (!dev->agp || !dev->agp->acquired)
414 		return -EINVAL;
415 	if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
416 		return -EINVAL;
417 	if (entry->bound)
418 		(void) drm_agp_unbind_memory(request->handle, dev);
419 
420 	list_del(&entry->head);
421 	{
422 		int agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
423 		int ret, rval;
424 		ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_DEALLOCATE,
425 		    (intptr_t)agpu_key, FKIOCTL, kcred, &rval);
426 		if (ret) {
427 			DRM_ERROR("AGPIOC_DEALLOCATE failed,"
428 			    "akey=%d, ret=%d", agpu_key, ret);
429 			return -ret;
430 		}
431 	}
432 	kfree(entry, sizeof (*entry));
433 	return 0;
434 }
435 
436 /* LINTED */
drm_agp_free_ioctl(DRM_IOCTL_ARGS)437 int drm_agp_free_ioctl(DRM_IOCTL_ARGS)
438 {
439 	struct drm_agp_buffer *request = data;
440 
441 	return drm_agp_free(dev, request);
442 }
443 
444 /**
445  * Initialize the AGP resources.
446  *
447  * \return pointer to a drm_agp_head structure.
448  *
449  * Gets the drm_agp_t structure which is made available by the agpgart module
450  * via the inter_module_* functions. Creates and initializes a drm_agp_head
451  * structure.
452  */
drm_agp_init(struct drm_device * dev)453 struct drm_agp_head *drm_agp_init(struct drm_device *dev)
454 {
455 	struct drm_agp_head *head = NULL;
456 	int ret, rval;
457 
458 	if (!(head = kmalloc(sizeof(*head), GFP_KERNEL)))
459 		return NULL;
460 	(void) memset((void *)head, 0, sizeof(*head));
461 	ret = ldi_ident_from_dip(dev->devinfo, &head->agpgart_li);
462 	if (ret) {
463 		DRM_ERROR("failed to get layerd ident, ret=%d", ret);
464 		goto err_1;
465 	}
466 
467 	ret = ldi_open_by_name(AGP_DEVICE, FEXCL, kcred,
468 	    &head->agpgart_lh, head->agpgart_li);
469 	if (ret) {
470 		DRM_ERROR("failed to open %s, ret=%d", AGP_DEVICE, ret);
471 		goto err_2;
472 	}
473 
474 	ret = ldi_ioctl(head->agpgart_lh, AGPIOC_INFO,
475 	    (intptr_t)&head->agp_info, FKIOCTL, kcred, &rval);
476 	if (ret) {
477 		DRM_ERROR("failed to get agpinfo, ret=%d", ret);
478 		goto err_3;
479 	}
480 	INIT_LIST_HEAD(&head->memory);
481 	head->base = head->agp_info.agpi_aperbase;
482 	return head;
483 
484 err_3:
485 	(void) ldi_close(head->agpgart_lh, FEXCL, kcred);
486 err_2:
487 	ldi_ident_release(head->agpgart_li);
488 err_1:
489 	kfree(head, sizeof(*head));
490 	return NULL;
491 }
492 
493 /* LINTED */
drm_agp_allocate_memory(size_t pages,uint32_t type,struct drm_device * dev)494 void *drm_agp_allocate_memory(size_t pages, uint32_t type, struct drm_device *dev)
495 {
496 	return NULL;
497 }
498 
499 /* LINTED */
drm_agp_free_memory(agp_allocate_t * handle,struct drm_device * dev)500 int drm_agp_free_memory(agp_allocate_t *handle, struct drm_device *dev)
501 {
502 	return 1;
503 }
504 
drm_agp_bind_memory(unsigned int key,uint32_t start,struct drm_device * dev)505 int drm_agp_bind_memory(unsigned int key, uint32_t start, struct drm_device *dev)
506 {
507 	agp_bind_t bind;
508 	int ret, rval;
509 
510 	bind.agpb_pgstart = start;
511 	bind.agpb_key = key;
512 	if (ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_BIND,
513 	    (intptr_t)&bind, FKIOCTL, kcred, &rval)) {
514 		DRM_DEBUG("AGPIOC_BIND failed");
515 		return -ret;
516 	}
517 	return 0;
518 }
519 
drm_agp_unbind_memory(unsigned long handle,struct drm_device * dev)520 int drm_agp_unbind_memory(unsigned long handle, struct drm_device *dev)
521 {
522 	struct drm_agp_mem *entry;
523 	agp_unbind_t unbind;
524 	int ret, rval;
525 
526 	if (!dev->agp || !dev->agp->acquired)
527 		return -EINVAL;
528 
529 	entry = drm_agp_lookup_entry(dev, handle);
530 	if (!entry || !entry->bound)
531 		return -EINVAL;
532 
533 	unbind.agpu_pri = 0;
534 	unbind.agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
535 	if (ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_UNBIND,
536 	    (intptr_t)&unbind, FKIOCTL, kcred, &rval)) {
537 		DRM_ERROR("AGPIO_UNBIND failed");
538 		return -ret;
539 	}
540 	entry->bound = 0;
541 	return 0;
542 }
543 
544 /**
545  * Binds a collection of pages into AGP memory at the given offset, returning
546  * the AGP memory structure containing them.
547  *
548  * No reference is held on the pages during this time -- it is up to the
549  * caller to handle that.
550  */
551 int
drm_agp_bind_pages(struct drm_device * dev,pfn_t * pages,unsigned long num_pages,uint32_t gtt_offset,unsigned int agp_type)552 drm_agp_bind_pages(struct drm_device *dev,
553 		    pfn_t *pages,
554 		    unsigned long num_pages,
555 		    uint32_t gtt_offset,
556 		    unsigned int agp_type)
557 {
558 	agp_bind_pages_t bind;
559 	int ret, rval;
560 
561 	bind.agpb_pgstart = gtt_offset / AGP_PAGE_SIZE;
562 	bind.agpb_pgcount = num_pages;
563 	bind.agpb_pages = pages;
564 	bind.agpb_type = agp_type;
565 
566 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_BIND,
567 	    (intptr_t)&bind, FKIOCTL, kcred, &rval);
568 	if (ret) {
569 		DRM_ERROR("AGPIOC_PAGES_BIND failed ret %d", ret);
570 		return -ret;
571 	}
572 	return 0;
573 }
574 
575 int
drm_agp_unbind_pages(struct drm_device * dev,pfn_t * pages,unsigned long num_pages,uint32_t gtt_offset,pfn_t scratch,uint32_t ignored)576 drm_agp_unbind_pages(struct drm_device *dev,
577 		    pfn_t *pages,	/* NULL */
578 		    unsigned long num_pages,
579 		    uint32_t gtt_offset,
580 		    pfn_t scratch,
581 		    uint32_t ignored)	/* old "VT_switch" flag */
582 {
583 	agp_unbind_pages_t unbind;
584 	int ret, rval;
585 
586 	unbind.agpu_pgstart = gtt_offset / AGP_PAGE_SIZE;
587 	unbind.agpu_pgcount = num_pages;
588 	unbind.agpu_scratch = scratch;
589 	unbind.agpu_flags = 0;
590 
591 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_UNBIND,
592 	    (intptr_t)&unbind, FKIOCTL, kcred, &rval);
593 	if (ret) {
594 		DRM_ERROR("AGPIOC_PAGES_UNBIND failed %d", ret);
595 		return -ret;
596 	}
597 	return 0;
598 }
599 
drm_agp_chipset_flush(struct drm_device * dev)600 void drm_agp_chipset_flush(struct drm_device *dev)
601 {
602 	int ret, rval;
603 
604 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_FLUSHCHIPSET,
605 	    (intptr_t)0, FKIOCTL, kcred, &rval);
606 	if (ret)
607 		DRM_ERROR("AGPIOC_FLUSHCHIPSET failed, ret=%d", ret);
608 }
609 
610 int
drm_agp_rw_gtt(struct drm_device * dev,unsigned long num_pages,uint32_t gtt_offset,void * gttp,uint32_t rw_flag)611 drm_agp_rw_gtt(struct drm_device *dev,
612 		    unsigned long num_pages,
613 		    uint32_t gtt_offset,
614 		    void *gttp,
615 		    uint32_t rw_flag)	/* read = 0 write = 1 */
616 {
617 	agp_rw_gtt_t rw;
618 	int ret, rval;
619 
620 	rw.agprw_pgstart = gtt_offset / AGP_PAGE_SIZE;
621 	rw.agprw_pgcount = num_pages;
622 	rw.agprw_addr = gttp;
623 	rw.agprw_flags = rw_flag;
624 
625 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_RW_GTT,
626 	    (intptr_t)&rw, FKIOCTL, kcred, &rval);
627 	if (ret) {
628 		DRM_ERROR("AGPIOC_RW_GTT failed %d", ret);
629 		return -ret;
630 	}
631 	return 0;
632 }
633