xref: /onnv-gate/usr/src/uts/common/io/drm/drm_agpsupport.c (revision 11260:eb8c6f2097e8)
12820Skz151634 /*
2*11260SMiao.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
32820Skz151634  * Use is subject to license terms.
42820Skz151634  */
52820Skz151634 
62820Skz151634 /*
72820Skz151634  * drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*-
82820Skz151634  * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
92820Skz151634  */
102820Skz151634 /*
112820Skz151634  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
122820Skz151634  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13*11260SMiao.Chen@Sun.COM  * Copyright (c) 2009, Intel Corporation.
142820Skz151634  * All Rights Reserved.
152820Skz151634  *
162820Skz151634  * Permission is hereby granted, free of charge, to any person obtaining a
172820Skz151634  * copy of this software and associated documentation files (the "Software"),
182820Skz151634  * to deal in the Software without restriction, including without limitation
192820Skz151634  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
202820Skz151634  * and/or sell copies of the Software, and to permit persons to whom the
212820Skz151634  * Software is furnished to do so, subject to the following conditions:
222820Skz151634  *
232820Skz151634  * The above copyright notice and this permission notice (including the next
242820Skz151634  * paragraph) shall be included in all copies or substantial portions of the
252820Skz151634  * Software.
262820Skz151634  *
272820Skz151634  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
282820Skz151634  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
292820Skz151634  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
302820Skz151634  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
312820Skz151634  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
322820Skz151634  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
332820Skz151634  * OTHER DEALINGS IN THE SOFTWARE.
342820Skz151634  *
352820Skz151634  * Author:
362820Skz151634  *    Rickard E. (Rik) Faith <faith@valinux.com>
372820Skz151634  *    Gareth Hughes <gareth@valinux.com>
382820Skz151634  *
392820Skz151634  */
402820Skz151634 
412820Skz151634 #include "drm.h"
422820Skz151634 #include "drmP.h"
432820Skz151634 
442820Skz151634 #ifndef	AGP_PAGE_SIZE
452820Skz151634 #define	AGP_PAGE_SIZE 4096
462820Skz151634 #define	AGP_PAGE_SHIFT 12
472820Skz151634 #endif
482820Skz151634 
495804Scg149915 /*
505804Scg149915  * The agpa_key field of struct agp_allocate_t actually is
515804Scg149915  * an index to an array. It can be zero. But we will use
525804Scg149915  * this agpa_key as a handle returned to userland. Generally,
535804Scg149915  * 0 is not a valid value for a handle, so we add an offset
545804Scg149915  * to the key to get a handle.
555804Scg149915  */
565804Scg149915 #define	DRM_AGP_KEY_OFFSET	8
575804Scg149915 
585804Scg149915 extern int drm_supp_device_capability(void *handle, int capid);
595804Scg149915 
602820Skz151634 /*ARGSUSED*/
612820Skz151634 int
drm_device_is_agp(drm_device_t * dev)625804Scg149915 drm_device_is_agp(drm_device_t *dev)
632820Skz151634 {
645804Scg149915 	int ret;
655804Scg149915 
665804Scg149915 	if (dev->driver->device_is_agp != NULL) {
675804Scg149915 		/*
685804Scg149915 		 * device_is_agp returns a tristate:
695804Scg149915 		 * 	0 = not AGP;
705804Scg149915 		 * 	1 = definitely AGP;
715804Scg149915 		 * 	2 = fall back to PCI capability
725804Scg149915 		 */
735804Scg149915 		ret = (*dev->driver->device_is_agp)(dev);
745804Scg149915 		if (ret != DRM_MIGHT_BE_AGP)
755804Scg149915 			return (ret);
765804Scg149915 	}
775804Scg149915 
785804Scg149915 	return (drm_supp_device_capability(dev->drm_handle, PCIY_AGP));
795804Scg149915 
802820Skz151634 }
812820Skz151634 
822820Skz151634 /*ARGSUSED*/
832820Skz151634 int
drm_device_is_pcie(drm_device_t * dev)845804Scg149915 drm_device_is_pcie(drm_device_t *dev)
852820Skz151634 {
865804Scg149915 	return (drm_supp_device_capability(dev->drm_handle, PCIY_EXPRESS));
872820Skz151634 }
882820Skz151634 
892820Skz151634 
902820Skz151634 /*ARGSUSED*/
912820Skz151634 int
drm_agp_info(DRM_IOCTL_ARGS)922820Skz151634 drm_agp_info(DRM_IOCTL_ARGS)
932820Skz151634 {
942820Skz151634 	DRM_DEVICE;
955804Scg149915 	agp_info_t		*agpinfo;
965804Scg149915 	drm_agp_info_t		info;
972820Skz151634 
982820Skz151634 	if (!dev->agp || !dev->agp->acquired)
995804Scg149915 		return (EINVAL);
1002820Skz151634 
1015804Scg149915 	agpinfo = &dev->agp->agp_info;
1025804Scg149915 	info.agp_version_major	= agpinfo->agpi_version.agpv_major;
1035804Scg149915 	info.agp_version_minor	= agpinfo->agpi_version.agpv_minor;
1045804Scg149915 	info.mode		= agpinfo->agpi_mode;
1055804Scg149915 	info.aperture_base	= agpinfo->agpi_aperbase;
1065804Scg149915 	info.aperture_size	= agpinfo->agpi_apersize* 1024 * 1024;
1075804Scg149915 	info.memory_allowed	= agpinfo->agpi_pgtotal << PAGE_SHIFT;
1085804Scg149915 	info.memory_used	= agpinfo->agpi_pgused << PAGE_SHIFT;
1095804Scg149915 	info.id_vendor		= agpinfo->agpi_devid & 0xffff;
1105804Scg149915 	info.id_device		= agpinfo->agpi_devid >> 16;
1115804Scg149915 
1125804Scg149915 	DRM_COPYTO_WITH_RETURN((void *)data, &info, sizeof (info));
1132820Skz151634 	return (0);
1142820Skz151634 }
1152820Skz151634 
1162820Skz151634 /*ARGSUSED*/
1172820Skz151634 int
drm_agp_acquire(DRM_IOCTL_ARGS)1182820Skz151634 drm_agp_acquire(DRM_IOCTL_ARGS)
1192820Skz151634 {
1202820Skz151634 	DRM_DEVICE;
1212820Skz151634 	int	ret, rval;
1222820Skz151634 
1232820Skz151634 	if (!dev->agp) {
1245804Scg149915 		DRM_ERROR("drm_agp_acquire : agp isn't initialized yet");
1255804Scg149915 		return (ENODEV);
1262820Skz151634 	}
1275804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_ACQUIRE,
1282820Skz151634 	    (uintptr_t)0, FKIOCTL, kcred, &rval);
1292820Skz151634 	if (ret) {
1302820Skz151634 		DRM_ERROR("drm_agp_acquired: AGPIOC_ACQUIRE failed\n");
1315804Scg149915 		return (EIO);
1322820Skz151634 	}
1332820Skz151634 	dev->agp->acquired = 1;
1342820Skz151634 
1352820Skz151634 	return (0);
1362820Skz151634 }
1372820Skz151634 
1382820Skz151634 /*ARGSUSED*/
1392820Skz151634 int
drm_agp_release(DRM_IOCTL_ARGS)1402820Skz151634 drm_agp_release(DRM_IOCTL_ARGS)
1412820Skz151634 {
1422820Skz151634 	DRM_DEVICE;
1432820Skz151634 	int ret, rval;
1442820Skz151634 
1452820Skz151634 	if (!dev->agp)
1465804Scg149915 		return (ENODEV);
1472820Skz151634 	if (!dev->agp->acquired)
1485804Scg149915 		return (EBUSY);
1492820Skz151634 
1505804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_RELEASE,
1515804Scg149915 	    (intptr_t)0, FKIOCTL, kcred, &rval);
1525804Scg149915 	if (ret) {
1535804Scg149915 		DRM_ERROR("drm_agp_release: AGPIOC_RELEASE failed\n");
1545804Scg149915 		return (ENXIO);
1552820Skz151634 	}
1562820Skz151634 	dev->agp->acquired = 0;
1572820Skz151634 
1585804Scg149915 	return (ret);
1595804Scg149915 }
1605804Scg149915 
1615804Scg149915 
1625804Scg149915 int
drm_agp_do_release(drm_device_t * dev)1635804Scg149915 drm_agp_do_release(drm_device_t *dev)
1645804Scg149915 {
1655804Scg149915 	int ret, rval;
1665804Scg149915 
1675804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_RELEASE,
1685804Scg149915 	    (intptr_t)0, FKIOCTL, kcred, &rval);
1695804Scg149915 
1705804Scg149915 	if (ret == 0)
1715804Scg149915 		dev->agp->acquired = 0;
1725804Scg149915 
1735804Scg149915 	return (ret);
1742820Skz151634 }
1752820Skz151634 
1762820Skz151634 /*ARGSUSED*/
1772820Skz151634 int
drm_agp_enable(DRM_IOCTL_ARGS)1782820Skz151634 drm_agp_enable(DRM_IOCTL_ARGS)
1792820Skz151634 {
1802820Skz151634 	DRM_DEVICE;
1812820Skz151634 	drm_agp_mode_t modes;
1822820Skz151634 	agp_setup_t setup;
1832820Skz151634 	int ret, rval;
1842820Skz151634 
1852820Skz151634 	if (!dev->agp)
1865804Scg149915 		return (ENODEV);
1872820Skz151634 	if (!dev->agp->acquired)
1885804Scg149915 		return (EBUSY);
1892820Skz151634 
1905804Scg149915 	DRM_COPYFROM_WITH_RETURN(&modes, (void *)data, sizeof (modes));
1912820Skz151634 
1922820Skz151634 	dev->agp->mode = modes.mode;
1935804Scg149915 	setup.agps_mode = (uint32_t)modes.mode;
1942820Skz151634 
195*11260SMiao.Chen@Sun.COM 
1962820Skz151634 	DRM_DEBUG("drm_agp_enable: dev->agp->mode=%lx", modes.mode);
1972820Skz151634 
1985804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_SETUP,
1995804Scg149915 	    (intptr_t)&setup, FKIOCTL, kcred, &rval);
2002820Skz151634 	if (ret) {
2015804Scg149915 		DRM_ERROR("drm_agp_enable: failed");
2025804Scg149915 		return (EIO);
2032820Skz151634 	}
2042820Skz151634 
2052820Skz151634 	dev->agp->base = dev->agp->agp_info.agpi_aperbase;
2062820Skz151634 	dev->agp->enabled = 1;
2072820Skz151634 
208*11260SMiao.Chen@Sun.COM 	DRM_DEBUG("drm_agp_enable: dev->agp->base=0x%lx", dev->agp->base);
2092820Skz151634 	return (0);
2102820Skz151634 }
2112820Skz151634 
2122820Skz151634 /*ARGSUSED*/
2132820Skz151634 int
drm_agp_alloc(DRM_IOCTL_ARGS)2142820Skz151634 drm_agp_alloc(DRM_IOCTL_ARGS)
2152820Skz151634 {
2162820Skz151634 	DRM_DEVICE;
2172820Skz151634 	drm_agp_mem_t    	*entry;
2182820Skz151634 	agp_allocate_t		alloc;
2192820Skz151634 	drm_agp_buffer_t	request;
2202820Skz151634 	int pages;
2212820Skz151634 	int ret, rval;
2222820Skz151634 
2232820Skz151634 	if (!dev->agp || !dev->agp->acquired)
2245804Scg149915 		return (EINVAL);
2252820Skz151634 
2265804Scg149915 	DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request));
2272820Skz151634 
2285804Scg149915 	entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
2295804Scg149915 
2302820Skz151634 	pages = btopr(request.size);
2312820Skz151634 	alloc.agpa_pgcount = pages;
2325804Scg149915 	alloc.agpa_type = AGP_NORMAL;
2335804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_ALLOCATE,
2345804Scg149915 	    (intptr_t)&alloc, FKIOCTL, kcred, &rval);
2352820Skz151634 	if (ret) {
2365804Scg149915 		DRM_ERROR("drm_agp_alloc: AGPIOC_ALLOCATE failed, ret=%d", ret);
2375804Scg149915 		kmem_free(entry, sizeof (*entry));
2385804Scg149915 		return (ret);
2392820Skz151634 	}
2402820Skz151634 
2412820Skz151634 	entry->bound = 0;
2422820Skz151634 	entry->pages = pages;
2435804Scg149915 	entry->handle = (void*)(uintptr_t)(alloc.agpa_key + DRM_AGP_KEY_OFFSET);
2442820Skz151634 	entry->prev = NULL;
2455804Scg149915 	entry->phys_addr = (void*)(uintptr_t)alloc.agpa_physical;
2462820Skz151634 	entry->next = dev->agp->memory;
2472820Skz151634 	if (dev->agp->memory)
2485804Scg149915 		dev->agp->memory->prev = entry;
2492820Skz151634 	dev->agp->memory = entry;
2502820Skz151634 
251*11260SMiao.Chen@Sun.COM 	DRM_DEBUG("entry->phys_addr %lx", entry->phys_addr);
252*11260SMiao.Chen@Sun.COM 
2535804Scg149915 	/* physical is used only by i810 driver */
2542820Skz151634 	request.physical = alloc.agpa_physical;
2555804Scg149915 	request.handle = (unsigned long)entry->handle;
2562820Skz151634 
2575804Scg149915 	/*
2585804Scg149915 	 * If failed to ddi_copyout(), we will free allocated AGP memory
2595804Scg149915 	 * when closing drm
2605804Scg149915 	 */
2615804Scg149915 	DRM_COPYTO_WITH_RETURN((void *)data, &request, sizeof (request));
2622820Skz151634 
2632820Skz151634 	return (0);
2642820Skz151634 }
2652820Skz151634 
2662820Skz151634 /*ARGSUSED*/
2672820Skz151634 static drm_agp_mem_t *
drm_agp_lookup_entry(drm_device_t * dev,void * handle)2685804Scg149915 drm_agp_lookup_entry(drm_device_t *dev, void *handle)
2692820Skz151634 {
2702820Skz151634 	drm_agp_mem_t *entry;
2712820Skz151634 
2722820Skz151634 	for (entry = dev->agp->memory; entry; entry = entry->next) {
2732820Skz151634 		if (entry->handle == handle)
2742820Skz151634 			return (entry);
2752820Skz151634 	}
2762820Skz151634 
2772820Skz151634 	return (NULL);
2782820Skz151634 }
2792820Skz151634 
2802820Skz151634 /*ARGSUSED*/
2812820Skz151634 int
drm_agp_unbind(DRM_IOCTL_ARGS)2822820Skz151634 drm_agp_unbind(DRM_IOCTL_ARGS)
2832820Skz151634 {
2842820Skz151634 	DRM_DEVICE;
2852820Skz151634 	agp_unbind_t unbind;
2862820Skz151634 	drm_agp_binding_t request;
2872820Skz151634 	drm_agp_mem_t *entry;
2882820Skz151634 	int ret, rval;
2892820Skz151634 
2902820Skz151634 	if (!dev->agp || !dev->agp->acquired)
2915804Scg149915 		return (EINVAL);
2925804Scg149915 
2935804Scg149915 	DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request));
2942820Skz151634 
2952820Skz151634 	if (!(entry = drm_agp_lookup_entry(dev, (void *)request.handle)))
2965804Scg149915 		return (EINVAL);
2972820Skz151634 	if (!entry->bound)
2985804Scg149915 		return (EINVAL);
2992820Skz151634 
3002820Skz151634 	unbind.agpu_pri = 0;
3015804Scg149915 	unbind.agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
3022820Skz151634 
3035804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_UNBIND,
3042820Skz151634 	    (intptr_t)&unbind, FKIOCTL, kcred, &rval);
3052820Skz151634 	if (ret) {
3062820Skz151634 		DRM_ERROR("drm_agp_unbind: AGPIOC_UNBIND failed");
3075804Scg149915 		return (EIO);
3082820Skz151634 	}
3092820Skz151634 	entry->bound = 0;
3102820Skz151634 	return (0);
3112820Skz151634 }
3122820Skz151634 
3132820Skz151634 /*ARGSUSED*/
3142820Skz151634 int
drm_agp_bind(DRM_IOCTL_ARGS)3152820Skz151634 drm_agp_bind(DRM_IOCTL_ARGS)
3162820Skz151634 {
3172820Skz151634 	DRM_DEVICE;
3182820Skz151634 	drm_agp_binding_t request;
3192820Skz151634 	drm_agp_mem_t   *entry;
3205804Scg149915 	int			start;
3215804Scg149915 	uint_t		key;
3222820Skz151634 
3232820Skz151634 	if (!dev->agp || !dev->agp->acquired)
3245804Scg149915 		return (EINVAL);
3255804Scg149915 
3265804Scg149915 	DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request));
3275804Scg149915 
3285804Scg149915 	entry = drm_agp_lookup_entry(dev, (void *)request.handle);
3295804Scg149915 	if (!entry || entry->bound)
3305804Scg149915 		return (EINVAL);
3312820Skz151634 
3325804Scg149915 	key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
3335804Scg149915 	start = btopr(request.offset);
3345804Scg149915 	if (drm_agp_bind_memory(key, start, dev)) {
3355804Scg149915 		DRM_ERROR("drm_agp_bind: failed key=%x, start=0x%x, "
3365804Scg149915 		    "agp_base=0x%lx", key, start, dev->agp->base);
3375804Scg149915 		return (EIO);
3385804Scg149915 	}
3392820Skz151634 
3405804Scg149915 	entry->bound = dev->agp->base + (start << AGP_PAGE_SHIFT);
3412820Skz151634 
3422820Skz151634 	return (0);
3432820Skz151634 }
3442820Skz151634 
3452820Skz151634 /*ARGSUSED*/
3462820Skz151634 int
drm_agp_free(DRM_IOCTL_ARGS)3472820Skz151634 drm_agp_free(DRM_IOCTL_ARGS)
3482820Skz151634 {
3492820Skz151634 	DRM_DEVICE;
3502820Skz151634 	drm_agp_buffer_t request;
3512820Skz151634 	drm_agp_mem_t	*entry;
3522820Skz151634 	int	ret, rval;
3535804Scg149915 	int	agpu_key;
3542820Skz151634 
3555804Scg149915 	DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request));
3562820Skz151634 	if (!dev->agp || !dev->agp->acquired)
3575804Scg149915 		return (EINVAL);
3582820Skz151634 	if (!(entry = drm_agp_lookup_entry(dev, (void *)request.handle)))
3595804Scg149915 		return (EINVAL);
3602820Skz151634 	if (entry->bound)
3615804Scg149915 		(void) drm_agp_unbind_memory(request.handle, dev);
3622820Skz151634 
3635804Scg149915 	if (entry == dev->agp->memory)
3645804Scg149915 		dev->agp->memory = entry->next;
3652820Skz151634 	if (entry->prev)
3662820Skz151634 		entry->prev->next = entry->next;
3672820Skz151634 	if (entry->next)
3682820Skz151634 		entry->next->prev = entry->prev;
3692820Skz151634 
3705804Scg149915 	agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
3715804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_DEALLOCATE,
3725804Scg149915 	    (intptr_t)agpu_key, FKIOCTL, kcred, &rval);
3735804Scg149915 	if (ret) {
3745804Scg149915 		DRM_ERROR("drm_agp_free: AGPIOC_DEALLOCATE failed,"
3755804Scg149915 		    "akey=%d, ret=%d", agpu_key, ret);
3765804Scg149915 		return (EIO);
3775804Scg149915 	}
3782820Skz151634 	drm_free(entry, sizeof (*entry), DRM_MEM_AGPLISTS);
3792820Skz151634 	return (0);
3802820Skz151634 }
3812820Skz151634 
3822820Skz151634 /*ARGSUSED*/
3832820Skz151634 drm_agp_head_t *
drm_agp_init(drm_device_t * dev)3845804Scg149915 drm_agp_init(drm_device_t *dev)
3852820Skz151634 {
3865804Scg149915 	drm_agp_head_t *agp   = NULL;
3875804Scg149915 	int	retval, rval;
3882820Skz151634 
3895804Scg149915 	agp = kmem_zalloc(sizeof (drm_agp_head_t), KM_SLEEP);
3905804Scg149915 
3915804Scg149915 	retval = ldi_ident_from_dip(dev->dip, &agp->agpgart_li);
3925804Scg149915 	if (retval != 0) {
3935804Scg149915 		DRM_ERROR("drm_agp_init: failed to get layerd ident, retval=%d",
3945804Scg149915 		    retval);
3955804Scg149915 		goto err_1;
3965804Scg149915 	}
3975804Scg149915 
3985804Scg149915 	retval = ldi_open_by_name(AGP_DEVICE, FEXCL, kcred,
3995804Scg149915 	    &agp->agpgart_lh, agp->agpgart_li);
4005804Scg149915 	if (retval != 0) {
4015804Scg149915 		DRM_ERROR("drm_agp_init: failed to open %s, retval=%d",
4025804Scg149915 		    AGP_DEVICE, retval);
4035804Scg149915 		goto err_2;
4045804Scg149915 	}
4055804Scg149915 
4065804Scg149915 	retval = ldi_ioctl(agp->agpgart_lh, AGPIOC_INFO,
4075804Scg149915 	    (intptr_t)&agp->agp_info, FKIOCTL, kcred, &rval);
4085804Scg149915 
4095804Scg149915 	if (retval != 0) {
4105804Scg149915 		DRM_ERROR("drm_agp_init: failed to get agpinfo, retval=%d",
4115804Scg149915 		    retval);
4125804Scg149915 		goto err_3;
4135804Scg149915 	}
4145804Scg149915 
4155804Scg149915 	return (agp);
4165804Scg149915 
4175804Scg149915 err_3:
4185804Scg149915 	(void) ldi_close(agp->agpgart_lh, FEXCL, kcred);
4195804Scg149915 
4205804Scg149915 err_2:
4215804Scg149915 	ldi_ident_release(agp->agpgart_li);
4225804Scg149915 
4235804Scg149915 err_1:
4245804Scg149915 	kmem_free(agp, sizeof (drm_agp_head_t));
4252820Skz151634 	return (NULL);
4262820Skz151634 }
4272820Skz151634 
4282820Skz151634 /*ARGSUSED*/
4292820Skz151634 void
drm_agp_fini(drm_device_t * dev)4305804Scg149915 drm_agp_fini(drm_device_t *dev)
4312820Skz151634 {
4325804Scg149915 	drm_agp_head_t *agp = dev->agp;
4335804Scg149915 	(void) ldi_close(agp->agpgart_lh, FEXCL, kcred);
4345804Scg149915 	ldi_ident_release(agp->agpgart_li);
4355804Scg149915 	kmem_free(agp, sizeof (drm_agp_head_t));
4365804Scg149915 	dev->agp = NULL;
4372820Skz151634 }
4382820Skz151634 
4392820Skz151634 
4402820Skz151634 /*ARGSUSED*/
4412820Skz151634 void *
drm_agp_allocate_memory(size_t pages,uint32_t type,drm_device_t * dev)442*11260SMiao.Chen@Sun.COM drm_agp_allocate_memory(size_t pages, uint32_t type, drm_device_t *dev)
4432820Skz151634 {
4442820Skz151634 	return (NULL);
4452820Skz151634 }
4462820Skz151634 
4472820Skz151634 /*ARGSUSED*/
4482820Skz151634 int
drm_agp_free_memory(agp_allocate_t * handle,drm_device_t * dev)449*11260SMiao.Chen@Sun.COM drm_agp_free_memory(agp_allocate_t *handle, drm_device_t *dev)
4502820Skz151634 {
4512820Skz151634 	return (1);
4522820Skz151634 }
4532820Skz151634 
4542820Skz151634 /*ARGSUSED*/
4552820Skz151634 int
drm_agp_bind_memory(unsigned int key,uint32_t start,drm_device_t * dev)4562820Skz151634 drm_agp_bind_memory(unsigned int key, uint32_t start, drm_device_t *dev)
4572820Skz151634 {
4582820Skz151634 	agp_bind_t bind;
4592820Skz151634 	int	ret, rval;
4602820Skz151634 
4612820Skz151634 	bind.agpb_pgstart = start;
4622820Skz151634 	bind.agpb_key = key;
4635804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_BIND,
4642820Skz151634 	    (intptr_t)&bind, FKIOCTL, kcred, &rval);
4652820Skz151634 	if (ret) {
4662820Skz151634 		DRM_DEBUG("drm_agp_bind_meory: AGPIOC_BIND failed");
4675804Scg149915 		return (EIO);
4682820Skz151634 	}
4692820Skz151634 	return (0);
4702820Skz151634 }
4712820Skz151634 
4722820Skz151634 /*ARGSUSED*/
4732820Skz151634 int
drm_agp_unbind_memory(unsigned long handle,drm_device_t * dev)4745804Scg149915 drm_agp_unbind_memory(unsigned long handle, drm_device_t *dev)
4752820Skz151634 {
4762820Skz151634 	agp_unbind_t unbind;
4772820Skz151634 	drm_agp_mem_t   *entry;
4782820Skz151634 	int ret, rval;
4792820Skz151634 
4802820Skz151634 	if (!dev->agp || !dev->agp->acquired)
4815804Scg149915 		return (EINVAL);
4822820Skz151634 
4835804Scg149915 	entry = drm_agp_lookup_entry(dev, (void *)handle);
4845804Scg149915 	if (!entry || !entry->bound)
4855804Scg149915 		return (EINVAL);
4862820Skz151634 
4872820Skz151634 	unbind.agpu_pri = 0;
4885804Scg149915 	unbind.agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET;
4892820Skz151634 
4905804Scg149915 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_UNBIND,
4915804Scg149915 	    (intptr_t)&unbind, FKIOCTL, kcred, &rval);
4922820Skz151634 	if (ret) {
4932820Skz151634 		DRM_ERROR("drm_agp_unbind: AGPIO_UNBIND failed");
4945804Scg149915 		return (EIO);
4952820Skz151634 	}
4962820Skz151634 	entry->bound = 0;
4972820Skz151634 	return (0);
4982820Skz151634 }
499*11260SMiao.Chen@Sun.COM 
500*11260SMiao.Chen@Sun.COM /*
501*11260SMiao.Chen@Sun.COM  * Binds a collection of pages into AGP memory at the given offset, returning
502*11260SMiao.Chen@Sun.COM  * the AGP memory structure containing them.
503*11260SMiao.Chen@Sun.COM  *
504*11260SMiao.Chen@Sun.COM  * No reference is held on the pages during this time -- it is up to the
505*11260SMiao.Chen@Sun.COM  * caller to handle that.
506*11260SMiao.Chen@Sun.COM  */
507*11260SMiao.Chen@Sun.COM int
drm_agp_bind_pages(drm_device_t * dev,pfn_t * pages,unsigned long num_pages,uint32_t gtt_offset)508*11260SMiao.Chen@Sun.COM drm_agp_bind_pages(drm_device_t *dev,
509*11260SMiao.Chen@Sun.COM 		    pfn_t *pages,
510*11260SMiao.Chen@Sun.COM 		    unsigned long num_pages,
511*11260SMiao.Chen@Sun.COM 		    uint32_t gtt_offset)
512*11260SMiao.Chen@Sun.COM {
513*11260SMiao.Chen@Sun.COM 
514*11260SMiao.Chen@Sun.COM 	agp_bind_pages_t bind;
515*11260SMiao.Chen@Sun.COM 	int	ret, rval;
516*11260SMiao.Chen@Sun.COM 
517*11260SMiao.Chen@Sun.COM 	bind.agpb_pgstart = gtt_offset / AGP_PAGE_SIZE;
518*11260SMiao.Chen@Sun.COM 	bind.agpb_pgcount = num_pages;
519*11260SMiao.Chen@Sun.COM 	bind.agpb_pages = pages;
520*11260SMiao.Chen@Sun.COM 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_BIND,
521*11260SMiao.Chen@Sun.COM 	    (intptr_t)&bind, FKIOCTL, kcred, &rval);
522*11260SMiao.Chen@Sun.COM 	if (ret) {
523*11260SMiao.Chen@Sun.COM 		DRM_ERROR("AGPIOC_PAGES_BIND failed ret %d", ret);
524*11260SMiao.Chen@Sun.COM 		return (ret);
525*11260SMiao.Chen@Sun.COM 	}
526*11260SMiao.Chen@Sun.COM 	return (0);
527*11260SMiao.Chen@Sun.COM }
528*11260SMiao.Chen@Sun.COM 
529*11260SMiao.Chen@Sun.COM int
drm_agp_unbind_pages(drm_device_t * dev,unsigned long num_pages,uint32_t gtt_offset,uint32_t type)530*11260SMiao.Chen@Sun.COM drm_agp_unbind_pages(drm_device_t *dev,
531*11260SMiao.Chen@Sun.COM 		    unsigned long num_pages,
532*11260SMiao.Chen@Sun.COM 		    uint32_t gtt_offset,
533*11260SMiao.Chen@Sun.COM 		    uint32_t type)
534*11260SMiao.Chen@Sun.COM {
535*11260SMiao.Chen@Sun.COM 
536*11260SMiao.Chen@Sun.COM 	agp_unbind_pages_t unbind;
537*11260SMiao.Chen@Sun.COM 	int	ret, rval;
538*11260SMiao.Chen@Sun.COM 
539*11260SMiao.Chen@Sun.COM 	unbind.agpb_pgstart = gtt_offset / AGP_PAGE_SIZE;
540*11260SMiao.Chen@Sun.COM 	unbind.agpb_pgcount = num_pages;
541*11260SMiao.Chen@Sun.COM 	unbind.agpb_type = type;
542*11260SMiao.Chen@Sun.COM 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_UNBIND,
543*11260SMiao.Chen@Sun.COM 	    (intptr_t)&unbind, FKIOCTL, kcred, &rval);
544*11260SMiao.Chen@Sun.COM 	if (ret) {
545*11260SMiao.Chen@Sun.COM 		DRM_DEBUG("drm_agp_unbind_pages AGPIOC_PAGES_UNBIND failed");
546*11260SMiao.Chen@Sun.COM 		return (ret);
547*11260SMiao.Chen@Sun.COM 	}
548*11260SMiao.Chen@Sun.COM 	return (0);
549*11260SMiao.Chen@Sun.COM }
550*11260SMiao.Chen@Sun.COM 
551*11260SMiao.Chen@Sun.COM /*
552*11260SMiao.Chen@Sun.COM  * Certain Intel chipsets contains a global write buffer, and this can require
553*11260SMiao.Chen@Sun.COM  * flushing from the drm or X.org to make sure all data has hit RAM before
554*11260SMiao.Chen@Sun.COM  * initiating a GPU transfer, due to a lack of coherency with the integrated
555*11260SMiao.Chen@Sun.COM  * graphics device and this buffer.
556*11260SMiao.Chen@Sun.COM  */
557*11260SMiao.Chen@Sun.COM void
drm_agp_chipset_flush(struct drm_device * dev)558*11260SMiao.Chen@Sun.COM drm_agp_chipset_flush(struct drm_device *dev)
559*11260SMiao.Chen@Sun.COM {
560*11260SMiao.Chen@Sun.COM 	int ret, rval;
561*11260SMiao.Chen@Sun.COM 
562*11260SMiao.Chen@Sun.COM 	DRM_DEBUG("agp_chipset_flush");
563*11260SMiao.Chen@Sun.COM 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_FLUSHCHIPSET,
564*11260SMiao.Chen@Sun.COM 	    (intptr_t)0, FKIOCTL, kcred, &rval);
565*11260SMiao.Chen@Sun.COM 	if (ret != 0) {
566*11260SMiao.Chen@Sun.COM 		DRM_ERROR("Failed to drm_agp_chipset_flush ret %d", ret);
567*11260SMiao.Chen@Sun.COM 	}
568*11260SMiao.Chen@Sun.COM }
569*11260SMiao.Chen@Sun.COM 
570*11260SMiao.Chen@Sun.COM /*
571*11260SMiao.Chen@Sun.COM  * The pages are evict on suspend, so re-bind it at resume time
572*11260SMiao.Chen@Sun.COM  */
573*11260SMiao.Chen@Sun.COM void
drm_agp_rebind(struct drm_device * dev)574*11260SMiao.Chen@Sun.COM drm_agp_rebind(struct drm_device *dev)
575*11260SMiao.Chen@Sun.COM {
576*11260SMiao.Chen@Sun.COM 	int ret, rval;
577*11260SMiao.Chen@Sun.COM 
578*11260SMiao.Chen@Sun.COM 	if (!dev->agp) {
579*11260SMiao.Chen@Sun.COM 		return;
580*11260SMiao.Chen@Sun.COM 	}
581*11260SMiao.Chen@Sun.COM 
582*11260SMiao.Chen@Sun.COM 	ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_REBIND,
583*11260SMiao.Chen@Sun.COM 	    (intptr_t)0, FKIOCTL, kcred, &rval);
584*11260SMiao.Chen@Sun.COM 	if (ret != 0) {
585*11260SMiao.Chen@Sun.COM 		DRM_ERROR("rebind failed %d", ret);
586*11260SMiao.Chen@Sun.COM 	}
587*11260SMiao.Chen@Sun.COM }
588