xref: /onnv-gate/usr/src/uts/intel/io/agpgart/agpgart.c (revision 5036:4879e862fff8)
13446Smrj /*
24478Skz151634  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
33446Smrj  * Use is subject to license terms.
43446Smrj  */
53446Smrj /*
63446Smrj  * Portions Philip Brown phil@bolthole.com Dec 2001
73446Smrj  */
83446Smrj 
93446Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
103446Smrj 
113446Smrj /*
123446Smrj  * agpgart driver
133446Smrj  *
143446Smrj  * This driver is primary targeted at providing memory support for INTEL
153446Smrj  * AGP device, INTEL memory less video card, and AMD64 cpu GART devices.
163446Smrj  * So there are four main architectures, ARC_IGD810, ARC_IGD830, ARC_INTELAGP,
173446Smrj  * ARC_AMD64AGP, ARC_AMD64NOAGP to agpgart driver. However, the memory
183446Smrj  * interfaces are the same for these architectures. The difference is how to
193446Smrj  * manage the hardware GART table for them.
203446Smrj  *
213446Smrj  * For large memory allocation, this driver use direct mapping to userland
223446Smrj  * application interface to save kernel virtual memory .
233446Smrj  */
243446Smrj 
253446Smrj #include <sys/types.h>
263446Smrj #include <sys/pci.h>
273446Smrj #include <sys/systm.h>
283446Smrj #include <sys/conf.h>
293446Smrj #include <sys/file.h>
303446Smrj #include <sys/kstat.h>
313446Smrj #include <sys/stat.h>
323446Smrj #include <sys/modctl.h>
333446Smrj #include <sys/ddi.h>
343446Smrj #include <sys/sunddi.h>
353446Smrj #include <sys/sunldi.h>
363446Smrj #include <sys/policy.h>
373446Smrj #include <sys/ddidevmap.h>
383446Smrj #include <vm/seg_dev.h>
393446Smrj #include <sys/pmem.h>
403446Smrj #include <sys/agpgart.h>
413446Smrj #include <sys/agp/agpdefs.h>
423446Smrj #include <sys/agp/agpgart_impl.h>
433446Smrj #include <sys/agp/agpamd64gart_io.h>
443446Smrj #include <sys/agp/agpmaster_io.h>
453446Smrj #include <sys/agp/agptarget_io.h>
463446Smrj 
473446Smrj /* Dynamic debug support */
483446Smrj int agp_debug_var = 0;
493446Smrj #define	AGPDB_PRINT1(fmt)	if (agp_debug_var == 1) cmn_err fmt
503446Smrj #define	AGPDB_PRINT2(fmt)	if (agp_debug_var >= 1) cmn_err fmt
513446Smrj 
523446Smrj /* Driver global softstate handle */
533446Smrj static void *agpgart_glob_soft_handle;
543446Smrj 
553446Smrj #define	MAX_INSTNUM			16
563446Smrj 
573446Smrj #define	AGP_DEV2INST(devt)	(getminor((devt)) >> 4)
583446Smrj #define	AGP_INST2MINOR(instance)	((instance) << 4)
593446Smrj #define	IS_INTEL_830(type)	((type) == ARC_IGD830)
603446Smrj #define	IS_TRUE_AGP(type)	(((type) == ARC_INTELAGP) || \
613446Smrj 	((type) == ARC_AMD64AGP))
623446Smrj 
633446Smrj #define	agpinfo_default_to_32(v, v32)	\
643446Smrj 	{				\
653446Smrj 		(v32).agpi32_version = (v).agpi_version;	\
663446Smrj 		(v32).agpi32_devid = (v).agpi_devid;	\
673446Smrj 		(v32).agpi32_mode = (v).agpi_mode;	\
683446Smrj 		(v32).agpi32_aperbase = (v).agpi_aperbase;	\
693446Smrj 		(v32).agpi32_apersize = (v).agpi_apersize;	\
703446Smrj 		(v32).agpi32_pgtotal = (v).agpi_pgtotal;	\
713446Smrj 		(v32).agpi32_pgsystem = (v).agpi_pgsystem;	\
723446Smrj 		(v32).agpi32_pgused = (v).agpi_pgused;	\
733446Smrj 	}
743446Smrj 
753446Smrj static ddi_dma_attr_t agpgart_dma_attr = {
763446Smrj 	DMA_ATTR_V0,
773446Smrj 	0U,				/* dma_attr_addr_lo */
783446Smrj 	0xffffffffU,			/* dma_attr_addr_hi */
793446Smrj 	0xffffffffU,			/* dma_attr_count_max */
803446Smrj 	(uint64_t)AGP_PAGE_SIZE,	/* dma_attr_align */
813446Smrj 	1,				/* dma_attr_burstsizes */
823446Smrj 	1,				/* dma_attr_minxfer */
833446Smrj 	0xffffffffU,			/* dma_attr_maxxfer */
843446Smrj 	0xffffffffU,			/* dma_attr_seg */
853446Smrj 	1,				/* dma_attr_sgllen, variable */
863446Smrj 	4,				/* dma_attr_granular */
873446Smrj 	0				/* dma_attr_flags */
883446Smrj };
893446Smrj 
903446Smrj /*
913446Smrj  * AMD64 supports gart table above 4G. See alloc_gart_table.
923446Smrj  */
933446Smrj static ddi_dma_attr_t garttable_dma_attr = {
943446Smrj 	DMA_ATTR_V0,
953446Smrj 	0U,				/* dma_attr_addr_lo */
963446Smrj 	0xffffffffU,			/* dma_attr_addr_hi */
973446Smrj 	0xffffffffU,			/* dma_attr_count_max */
983446Smrj 	(uint64_t)AGP_PAGE_SIZE,	/* dma_attr_align */
993446Smrj 	1,				/* dma_attr_burstsizes */
1003446Smrj 	1,				/* dma_attr_minxfer */
1013446Smrj 	0xffffffffU,			/* dma_attr_maxxfer */
1023446Smrj 	0xffffffffU,			/* dma_attr_seg */
1033446Smrj 	1,				/* dma_attr_sgllen, variable */
1043446Smrj 	4,				/* dma_attr_granular */
1053446Smrj 	0				/* dma_attr_flags */
1063446Smrj };
1073446Smrj 
1083446Smrj /*
1093446Smrj  * AGPGART table need a physical contiguous memory. To assure that
1103446Smrj  * each access to gart table is strongly ordered and uncachable,
1113446Smrj  * we use DDI_STRICTORDER_ACC.
1123446Smrj  */
1133446Smrj static ddi_device_acc_attr_t gart_dev_acc_attr = {
1143446Smrj 	DDI_DEVICE_ATTR_V0,
1153446Smrj 	DDI_NEVERSWAP_ACC,
1163446Smrj 	DDI_STRICTORDER_ACC	/* must be DDI_STRICTORDER_ACC */
1173446Smrj };
1183446Smrj 
1193446Smrj /*
1203446Smrj  * AGP memory is usually used as texture memory or for a framebuffer, so we
1213446Smrj  * can set the memory attribute to write combining. Video drivers will
1223446Smrj  * determine the frame buffer attributes, for example the memory is write
1233446Smrj  * combinging or non-cachable. However, the interface between Xorg and agpgart
1243446Smrj  * driver to support attribute selcetion doesn't exist yet. So we set agp memory
1253446Smrj  * to non-cachable by default now. This attribute might be overridden
1263446Smrj  * by MTTR in X86.
1273446Smrj  */
1283446Smrj static ddi_device_acc_attr_t mem_dev_acc_attr = {
1293446Smrj 	DDI_DEVICE_ATTR_V0,
1303446Smrj 	DDI_NEVERSWAP_ACC,
1313446Smrj 	DDI_STRICTORDER_ACC	/* Can be DDI_MERGING_OK_ACC */
1323446Smrj };
1333446Smrj 
1343446Smrj static keytable_ent_t *
1353446Smrj agp_find_bound_keyent(agpgart_softstate_t *softstate, uint32_t pg_offset);
1363446Smrj static void
1373446Smrj amd64_gart_unregister(amd64_garts_dev_t *cpu_garts);
1383446Smrj 
1393446Smrj 
1403446Smrj static void
1413446Smrj agp_devmap_unmap(devmap_cookie_t handle, void *devprivate,
1423446Smrj     offset_t off, size_t len, devmap_cookie_t new_handle1,
1433446Smrj     void **new_devprivate1, devmap_cookie_t new_handle2,
1443446Smrj     void **new_devprivate2)
1453446Smrj {
1463446Smrj 
1473446Smrj 	struct keytable_ent *mementry;
1483446Smrj 	agpgart_softstate_t *softstate;
1493446Smrj 	agpgart_ctx_t *ctxp, *newctxp1, *newctxp2;
1503446Smrj 
1513446Smrj 	ASSERT(AGP_ALIGNED(len) && AGP_ALIGNED(off));
1523446Smrj 	ASSERT(devprivate);
1533446Smrj 	ASSERT(handle);
1543446Smrj 
1553446Smrj 	ctxp = (agpgart_ctx_t *)devprivate;
1563446Smrj 	softstate = ctxp->actx_sc;
1573446Smrj 	ASSERT(softstate);
1583446Smrj 
1593446Smrj 	if (new_handle1 != NULL) {
1603446Smrj 		newctxp1 = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP);
1613446Smrj 		newctxp1->actx_sc = softstate;
1623446Smrj 		newctxp1->actx_off = ctxp->actx_off;
1633446Smrj 		*new_devprivate1 = newctxp1;
1643446Smrj 	}
1653446Smrj 
1663446Smrj 	if (new_handle2 != NULL) {
1673446Smrj 		newctxp2 = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP);
1683446Smrj 		newctxp2->actx_sc = softstate;
1693446Smrj 		newctxp2->actx_off = off + len;
1703446Smrj 		*new_devprivate2 = newctxp2;
1713446Smrj 	}
1723446Smrj 
1733446Smrj 	mutex_enter(&softstate->asoft_instmutex);
1743446Smrj 	if ((new_handle1 == NULL) && (new_handle2 == NULL)) {
1753446Smrj 		mementry =
1763446Smrj 		    agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(off));
1773446Smrj 		ASSERT(mementry);
1783446Smrj 		mementry->kte_refcnt--;
1793446Smrj 	} else if ((new_handle1 != NULL) && (new_handle2 != NULL)) {
1803446Smrj 		mementry =
1813446Smrj 		    agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(off));
1823446Smrj 		ASSERT(mementry);
1833446Smrj 		mementry->kte_refcnt++;
1843446Smrj 	}
1853446Smrj 	ASSERT(mementry->kte_refcnt >= 0);
1863446Smrj 	mutex_exit(&softstate->asoft_instmutex);
1873446Smrj 	kmem_free(ctxp, sizeof (struct agpgart_ctx));
1883446Smrj }
1893446Smrj 
1903446Smrj /*ARGSUSED*/
1913446Smrj static int
1923446Smrj agp_devmap_map(devmap_cookie_t handle, dev_t dev,
1933446Smrj     uint_t flags, offset_t offset, size_t len, void **new_devprivate)
1943446Smrj {
1953446Smrj 	agpgart_softstate_t *softstate;
1963446Smrj 	int instance;
1973446Smrj 	struct keytable_ent *mementry;
1983446Smrj 	agpgart_ctx_t *newctxp;
1993446Smrj 
2003446Smrj 	ASSERT(handle);
2013446Smrj 	instance = AGP_DEV2INST(dev);
2023446Smrj 	softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
2033446Smrj 	if (softstate == NULL) {
2043446Smrj 		AGPDB_PRINT2((CE_WARN, "agp_devmap_map: get soft state err"));
2053446Smrj 		return (ENXIO);
2063446Smrj 	}
2073446Smrj 
2083446Smrj 	ASSERT(softstate);
2093446Smrj 	ASSERT(mutex_owned(&softstate->asoft_instmutex));
2103446Smrj 	ASSERT(len);
2113446Smrj 	ASSERT(AGP_ALIGNED(offset) && AGP_ALIGNED(len));
2123446Smrj 
2133446Smrj 	mementry =
2143446Smrj 	    agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(offset));
2153446Smrj 	ASSERT(mementry);
2163446Smrj 	mementry->kte_refcnt++;
2173446Smrj 	ASSERT(mementry->kte_refcnt >= 0);
2183446Smrj 	newctxp = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP);
2193446Smrj 	newctxp->actx_off = offset;
2203446Smrj 	newctxp->actx_sc = softstate;
2213446Smrj 	*new_devprivate = newctxp;
2223446Smrj 
2233446Smrj 	return (0);
2243446Smrj }
2253446Smrj 
2263446Smrj /*ARGSUSED*/
2273446Smrj static int agp_devmap_dup(devmap_cookie_t handle, void *devprivate,
2283446Smrj     devmap_cookie_t new_handle, void **new_devprivate)
2293446Smrj {
2303446Smrj 	struct keytable_ent *mementry;
2313446Smrj 	agpgart_ctx_t *newctxp, *ctxp;
2323446Smrj 	agpgart_softstate_t *softstate;
2333446Smrj 
2343446Smrj 	ASSERT(devprivate);
2353446Smrj 	ASSERT(handle && new_handle);
2363446Smrj 
2373446Smrj 	ctxp = (agpgart_ctx_t *)devprivate;
2383446Smrj 	ASSERT(AGP_ALIGNED(ctxp->actx_off));
2393446Smrj 
2403446Smrj 	newctxp = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP);
2413446Smrj 	newctxp->actx_off = ctxp->actx_off;
2423446Smrj 	newctxp->actx_sc = ctxp->actx_sc;
2433446Smrj 	softstate = (agpgart_softstate_t *)newctxp->actx_sc;
2443446Smrj 
2453446Smrj 	mutex_enter(&softstate->asoft_instmutex);
2463446Smrj 	mementry = agp_find_bound_keyent(softstate,
2473446Smrj 	    AGP_BYTES2PAGES(newctxp->actx_off));
2483446Smrj 	mementry->kte_refcnt++;
2493446Smrj 	ASSERT(mementry->kte_refcnt >= 0);
2503446Smrj 	mutex_exit(&softstate->asoft_instmutex);
2513446Smrj 	*new_devprivate = newctxp;
2523446Smrj 
2533446Smrj 	return (0);
2543446Smrj }
2553446Smrj 
2563446Smrj struct devmap_callback_ctl agp_devmap_cb = {
2573446Smrj 	DEVMAP_OPS_REV,		/* rev */
2583446Smrj 	agp_devmap_map,		/* map */
2593446Smrj 	NULL,			/* access */
2603446Smrj 	agp_devmap_dup,		/* dup */
2613446Smrj 	agp_devmap_unmap,	/* unmap */
2623446Smrj };
2633446Smrj 
2643446Smrj /*
2653446Smrj  * agp_master_regis_byname()
2663446Smrj  *
2673446Smrj  * Description:
2683446Smrj  * 	Open the AGP master device node by device path name and
2693446Smrj  * 	register the device handle for later operations.
2703446Smrj  * 	We check all possible driver instance from 0
2713446Smrj  * 	to MAX_INSTNUM because the master device could be
2723446Smrj  * 	at any instance number. Only one AGP master is supported.
2733446Smrj  *
2743446Smrj  * Arguments:
2753446Smrj  * 	master_hdlp		AGP master device LDI handle pointer
2763446Smrj  *	agpgart_l		AGPGART driver LDI identifier
2773446Smrj  *
2783446Smrj  * Returns:
2793446Smrj  * 	-1			failed
2803446Smrj  * 	0			success
2813446Smrj  */
2823446Smrj static int
2833446Smrj agp_master_regis_byname(ldi_handle_t *master_hdlp, ldi_ident_t agpgart_li)
2843446Smrj {
2853446Smrj 	int	i;
2863446Smrj 	char	buf[MAXPATHLEN];
2873446Smrj 
2883446Smrj 	ASSERT(master_hdlp);
2893446Smrj 	ASSERT(agpgart_li);
2903446Smrj 
2913446Smrj 	/*
2923446Smrj 	 * Search all possible instance numbers for the agp master device.
2933446Smrj 	 * Only one master device is supported now, so the search ends
2943446Smrj 	 * when one master device is found.
2953446Smrj 	 */
2963446Smrj 	for (i = 0; i < MAX_INSTNUM; i++) {
2973446Smrj 		(void) snprintf(buf, MAXPATHLEN, "%s%d", AGPMASTER_DEVLINK, i);
2983446Smrj 		if ((ldi_open_by_name(buf, 0, kcred,
2993446Smrj 		    master_hdlp, agpgart_li)))
3003446Smrj 			continue;
3013446Smrj 		AGPDB_PRINT1((CE_NOTE,
3023446Smrj 		    "master device found: instance number=%d", i));
3033446Smrj 		break;
3043446Smrj 
3053446Smrj 	}
3063446Smrj 
3073446Smrj 	/* AGP master device not found */
3083446Smrj 	if (i == MAX_INSTNUM)
3093446Smrj 		return (-1);
3103446Smrj 
3113446Smrj 	return (0);
3123446Smrj }
3133446Smrj 
3143446Smrj /*
3153446Smrj  * agp_target_regis_byname()
3163446Smrj  *
3173446Smrj  * Description:
3183446Smrj  * 	This function opens agp bridge device node by
3193446Smrj  * 	device path name and registers the device handle
3203446Smrj  * 	for later operations.
3213446Smrj  * 	We check driver instance from 0 to MAX_INSTNUM
3223446Smrj  * 	because the master device could be at any instance
3233446Smrj  * 	number. Only one agp target is supported.
3243446Smrj  *
3253446Smrj  *
3263446Smrj  * Arguments:
3273446Smrj  *	target_hdlp		AGP target device LDI handle pointer
3283446Smrj  *	agpgart_l		AGPGART driver LDI identifier
3293446Smrj  *
3303446Smrj  * Returns:
3313446Smrj  * 	-1			failed
3323446Smrj  * 	0			success
3333446Smrj  */
3343446Smrj static int
3353446Smrj agp_target_regis_byname(ldi_handle_t *target_hdlp, ldi_ident_t agpgart_li)
3363446Smrj {
3373446Smrj 	int	i;
3383446Smrj 	char	buf[MAXPATHLEN];
3393446Smrj 
3403446Smrj 	ASSERT(target_hdlp);
3413446Smrj 	ASSERT(agpgart_li);
3423446Smrj 
3433446Smrj 	for (i = 0; i < MAX_INSTNUM; i++) {
3443446Smrj 		(void) snprintf(buf, MAXPATHLEN, "%s%d", AGPTARGET_DEVLINK, i);
3453446Smrj 		if ((ldi_open_by_name(buf, 0, kcred,
3463446Smrj 		    target_hdlp, agpgart_li)))
3473446Smrj 			continue;
3483446Smrj 
3493446Smrj 		AGPDB_PRINT1((CE_NOTE,
3503446Smrj 		    "bridge device found: instance number=%d", i));
3513446Smrj 		break;
3523446Smrj 
3533446Smrj 	}
3543446Smrj 
3553446Smrj 	/* AGP bridge device not found */
3563446Smrj 	if (i == MAX_INSTNUM) {
3573446Smrj 		AGPDB_PRINT2((CE_WARN, "bridge device not found"));
3583446Smrj 		return (-1);
3593446Smrj 	}
3603446Smrj 
3613446Smrj 	return (0);
3623446Smrj }
3633446Smrj 
3643446Smrj /*
3653446Smrj  * amd64_gart_regis_byname()
3663446Smrj  *
3673446Smrj  * Description:
3683446Smrj  * 	Open all amd64 gart device nodes by deice path name and
3693446Smrj  * 	register the device handles for later operations. Each cpu
3703446Smrj  * 	has its own amd64 gart device.
3713446Smrj  *
3723446Smrj  * Arguments:
3733446Smrj  * 	cpu_garts		cpu garts device list header
3743446Smrj  *	agpgart_l		AGPGART driver LDI identifier
3753446Smrj  *
3763446Smrj  * Returns:
3773446Smrj  * 	-1			failed
3783446Smrj  * 	0			success
3793446Smrj  */
3803446Smrj static int
3813446Smrj amd64_gart_regis_byname(amd64_garts_dev_t *cpu_garts, ldi_ident_t agpgart_li)
3823446Smrj {
3833446Smrj 	amd64_gart_dev_list_t	*gart_list;
3843446Smrj 	int			i;
3853446Smrj 	char			buf[MAXPATHLEN];
3863446Smrj 	ldi_handle_t		gart_hdl;
3873446Smrj 	int			ret;
3883446Smrj 
3893446Smrj 	ASSERT(cpu_garts);
3903446Smrj 	ASSERT(agpgart_li);
3913446Smrj 
3923446Smrj 	/*
3933446Smrj 	 * Search all possible instance numbers for the gart devices.
3943446Smrj 	 * There can be multiple on-cpu gart devices for Opteron server.
3953446Smrj 	 */
3963446Smrj 	for (i = 0; i < MAX_INSTNUM; i++) {
3973446Smrj 		(void) snprintf(buf, MAXPATHLEN, "%s%d", CPUGART_DEVLINK, i);
3983446Smrj 		ret = ldi_open_by_name(buf, 0, kcred,
3993446Smrj 		    &gart_hdl, agpgart_li);
4003446Smrj 
4013446Smrj 		if (ret == ENODEV)
4023446Smrj 			continue;
4033446Smrj 		else if (ret != 0) { /* There was an error opening the device */
4043446Smrj 			amd64_gart_unregister(cpu_garts);
4053446Smrj 			return (ret);
4063446Smrj 		}
4073446Smrj 
4083446Smrj 		AGPDB_PRINT1((CE_NOTE,
4093446Smrj 		    "amd64 gart device found: instance number=%d", i));
4103446Smrj 
4113446Smrj 		gart_list = (amd64_gart_dev_list_t *)
4123446Smrj 		    kmem_zalloc(sizeof (amd64_gart_dev_list_t), KM_SLEEP);
4133446Smrj 
4143446Smrj 		/* Add new item to the head of the gart device list */
4153446Smrj 		gart_list->gart_devhdl = gart_hdl;
4163446Smrj 		gart_list->next = cpu_garts->gart_dev_list_head;
4173446Smrj 		cpu_garts->gart_dev_list_head = gart_list;
4183446Smrj 		cpu_garts->gart_device_num++;
4193446Smrj 	}
4203446Smrj 
4213446Smrj 	if (cpu_garts->gart_device_num == 0)
4223446Smrj 		return (ENODEV);
4233446Smrj 	return (0);
4243446Smrj }
4253446Smrj 
4263446Smrj /*
4273446Smrj  * Unregister agp master device handle
4283446Smrj  */
4293446Smrj static void
4303446Smrj agp_master_unregister(ldi_handle_t *master_hdlp)
4313446Smrj {
4323446Smrj 	ASSERT(master_hdlp);
4333446Smrj 
4343446Smrj 	if (master_hdlp) {
4353446Smrj 		(void) ldi_close(*master_hdlp, 0, kcred);
4363446Smrj 		*master_hdlp = NULL;
4373446Smrj 	}
4383446Smrj }
4393446Smrj 
4403446Smrj /*
4413446Smrj  * Unregister agp bridge device handle
4423446Smrj  */
4433446Smrj static void
4443446Smrj agp_target_unregister(ldi_handle_t *target_hdlp)
4453446Smrj {
4463446Smrj 	if (target_hdlp) {
4473446Smrj 		(void) ldi_close(*target_hdlp, 0, kcred);
4483446Smrj 		*target_hdlp = NULL;
4493446Smrj 	}
4503446Smrj }
4513446Smrj 
4523446Smrj /*
4533446Smrj  * Unregister all amd64 gart device handles
4543446Smrj  */
4553446Smrj static void
4563446Smrj amd64_gart_unregister(amd64_garts_dev_t *cpu_garts)
4573446Smrj {
4583446Smrj 	amd64_gart_dev_list_t	*gart_list;
4593446Smrj 	amd64_gart_dev_list_t	*next;
4603446Smrj 
4613446Smrj 	ASSERT(cpu_garts);
4623446Smrj 
4633446Smrj 	for (gart_list = cpu_garts->gart_dev_list_head;
4643446Smrj 	    gart_list; gart_list = next) {
4653446Smrj 
4663446Smrj 		ASSERT(gart_list->gart_devhdl);
4673446Smrj 		(void) ldi_close(gart_list->gart_devhdl, 0, kcred);
4683446Smrj 		next = gart_list->next;
4693446Smrj 		/* Free allocated memory */
4703446Smrj 		kmem_free(gart_list, sizeof (amd64_gart_dev_list_t));
4713446Smrj 	}
4723446Smrj 	cpu_garts->gart_dev_list_head = NULL;
4733446Smrj 	cpu_garts->gart_device_num = 0;
4743446Smrj }
4753446Smrj 
4763446Smrj /*
4773446Smrj  * lyr_detect_master_type()
4783446Smrj  *
4793446Smrj  * Description:
4803446Smrj  * 	This function gets agp master type by querying agp master device.
4813446Smrj  *
4823446Smrj  * Arguments:
4833446Smrj  * 	master_hdlp		agp master device ldi handle pointer
4843446Smrj  *
4853446Smrj  * Returns:
4863446Smrj  * 	-1			unsupported device
4873446Smrj  * 	DEVICE_IS_I810		i810 series
4883446Smrj  * 	DEVICE_IS_I810		i830 series
4893446Smrj  * 	DEVICE_IS_AGP		true agp master
4903446Smrj  */
4913446Smrj static int
4923446Smrj lyr_detect_master_type(ldi_handle_t *master_hdlp)
4933446Smrj {
4943446Smrj 	int vtype;
4953446Smrj 	int err;
4963446Smrj 
4973446Smrj 	ASSERT(master_hdlp);
4983446Smrj 
4993446Smrj 	/* ldi_ioctl(agpmaster) */
5003446Smrj 	err = ldi_ioctl(*master_hdlp, DEVICE_DETECT,
5013446Smrj 	    (intptr_t)&vtype, FKIOCTL, kcred, 0);
5023446Smrj 	if (err) /* Unsupported graphics device */
5033446Smrj 		return (-1);
5043446Smrj 	return (vtype);
5053446Smrj }
5063446Smrj 
5073446Smrj /*
5083446Smrj  * devtect_target_type()
5093446Smrj  *
5103446Smrj  * Description:
5113446Smrj  * 	This function gets the host bridge chipset type by querying the agp
5123446Smrj  *	target device.
5133446Smrj  *
5143446Smrj  * Arguments:
5153446Smrj  * 	target_hdlp		agp target device LDI handle pointer
5163446Smrj  *
5173446Smrj  * Returns:
5183446Smrj  * 	CHIP_IS_INTEL		Intel agp chipsets
5193446Smrj  * 	CHIP_IS_AMD		AMD agp chipset
5203446Smrj  * 	-1			unsupported chipset
5213446Smrj  */
5223446Smrj static int
5233446Smrj lyr_detect_target_type(ldi_handle_t *target_hdlp)
5243446Smrj {
5253446Smrj 	int btype;
5263446Smrj 	int err;
5273446Smrj 
5283446Smrj 	ASSERT(target_hdlp);
5293446Smrj 
5303446Smrj 	err = ldi_ioctl(*target_hdlp, CHIP_DETECT, (intptr_t)&btype,
5313446Smrj 	    FKIOCTL, kcred, 0);
5323446Smrj 	if (err)	/* Unsupported bridge device */
5333446Smrj 		return (-1);
5343446Smrj 	return (btype);
5353446Smrj }
5363446Smrj 
5373446Smrj /*
5383446Smrj  * lyr_init()
5393446Smrj  *
5403446Smrj  * Description:
5413446Smrj  * 	This function detects the  graphics system architecture and
5423446Smrj  * 	registers all relative device handles in a global structure
5433446Smrj  * 	"agp_regdev". Then it stores the system arc type in driver
5443446Smrj  * 	soft state.
5453446Smrj  *
5463446Smrj  * Arguments:
5473446Smrj  *	agp_regdev		AGP devices registration struct pointer
5483446Smrj  *	agpgart_l		AGPGART driver LDI identifier
5493446Smrj  *
5503446Smrj  * Returns:
5513446Smrj  * 	0	System arc supported and agp devices registration successed.
5523446Smrj  * 	-1	System arc not supported or device registration failed.
5533446Smrj  */
5543446Smrj int
5553446Smrj lyr_init(agp_registered_dev_t *agp_regdev, ldi_ident_t agpgart_li)
5563446Smrj {
5573446Smrj 	ldi_handle_t *master_hdlp;
5583446Smrj 	ldi_handle_t *target_hdlp;
5593446Smrj 	amd64_garts_dev_t *garts_dev;
5603446Smrj 	int card_type, chip_type;
5613446Smrj 	int ret;
5623446Smrj 
5633446Smrj 	ASSERT(agp_regdev);
5643446Smrj 
5653446Smrj 	bzero(agp_regdev, sizeof (agp_registered_dev_t));
5663446Smrj 	agp_regdev->agprd_arctype = ARC_UNKNOWN;
5673446Smrj 	/*
5683446Smrj 	 * Register agp devices, assuming all instances attached, and
5693446Smrj 	 * detect which agp architucture this server belongs to. This
5703446Smrj 	 * must be done before the agpgart driver starts to use layered
5713446Smrj 	 * driver interfaces.
5723446Smrj 	 */
5733446Smrj 	master_hdlp = &agp_regdev->agprd_masterhdl;
5743446Smrj 	target_hdlp = &agp_regdev->agprd_targethdl;
5753446Smrj 	garts_dev = &agp_regdev->agprd_cpugarts;
5763446Smrj 
5773446Smrj 	/* Check whether the system is amd64 arc */
5783446Smrj 	if ((ret = amd64_gart_regis_byname(garts_dev, agpgart_li)) == ENODEV) {
5793446Smrj 		/* No amd64 gart devices */
5803446Smrj 		AGPDB_PRINT1((CE_NOTE,
5813446Smrj 		    "lyr_init: this is not an amd64 system"));
5823446Smrj 		if (agp_master_regis_byname(master_hdlp, agpgart_li)) {
5833446Smrj 			AGPDB_PRINT2((CE_WARN,
5843446Smrj 			    "lyr_init: register master device unsuccessful"));
5853446Smrj 			goto err1;
5863446Smrj 		}
5873446Smrj 		if (agp_target_regis_byname(target_hdlp, agpgart_li)) {
5883446Smrj 			AGPDB_PRINT2((CE_WARN,
5893446Smrj 			    "lyr_init: register target device unsuccessful"));
5903446Smrj 			goto err2;
5913446Smrj 		}
5923446Smrj 		card_type = lyr_detect_master_type(master_hdlp);
5933446Smrj 		/*
5943446Smrj 		 * Detect system arc by master device. If it is a intel
5953446Smrj 		 * integrated device, finish the detection successfully.
5963446Smrj 		 */
5973446Smrj 		switch (card_type) {
5983446Smrj 		case DEVICE_IS_I810:	/* I810 likewise graphics */
5993446Smrj 			AGPDB_PRINT1((CE_NOTE,
6003446Smrj 			    "lyr_init: the system is Intel 810 arch"));
6013446Smrj 			agp_regdev->agprd_arctype = ARC_IGD810;
6023446Smrj 			return (0);
6033446Smrj 		case DEVICE_IS_I830:	/* I830 likewise graphics */
6043446Smrj 			AGPDB_PRINT1((CE_NOTE,
6053446Smrj 			    "lyr_init: the system is Intel 830 arch"));
6063446Smrj 			agp_regdev->agprd_arctype = ARC_IGD830;
6073446Smrj 			return (0);
6083446Smrj 		case DEVICE_IS_AGP:	/* AGP graphics */
6093446Smrj 			break;
6103446Smrj 		default:		/* Non IGD/AGP graphics */
6113446Smrj 			AGPDB_PRINT2((CE_WARN,
6123446Smrj 			    "lyr_init: non-supported master device"));
6133446Smrj 			goto err3;
6143446Smrj 		}
6153446Smrj 
6163446Smrj 		chip_type = lyr_detect_target_type(target_hdlp);
6173446Smrj 
6183446Smrj 		/* Continue to detect AGP arc by target device */
6193446Smrj 		switch (chip_type) {
6203446Smrj 		case CHIP_IS_INTEL:	/* Intel chipset */
6213446Smrj 			AGPDB_PRINT1((CE_NOTE,
6223446Smrj 			    "lyr_init: Intel AGP arch detected"));
6233446Smrj 			agp_regdev->agprd_arctype = ARC_INTELAGP;
6243446Smrj 			return (0);
6253446Smrj 		case CHIP_IS_AMD:	/* AMD chipset */
6263446Smrj 			AGPDB_PRINT2((CE_WARN,
6273446Smrj 			    "lyr_init: no cpu gart, but have AMD64 chipsets"));
6283446Smrj 			goto err3;
6293446Smrj 		default:		/* Non supported chipset */
6303446Smrj 			AGPDB_PRINT2((CE_WARN,
6313446Smrj 			    "lyr_init: detection can not continue"));
6323446Smrj 			goto err3;
6333446Smrj 		}
6343446Smrj 
6353446Smrj 	}
6363446Smrj 
6373446Smrj 	if (ret)
6383446Smrj 		return (-1); /* Errors in open amd64 cpu gart devices */
6393446Smrj 
6403446Smrj 	/*
6413446Smrj 	 * AMD64 cpu gart device exsits, continue detection
6423446Smrj 	 */
6433446Smrj 
6443446Smrj 	if (agp_master_regis_byname(master_hdlp, agpgart_li)) {
6453446Smrj 		AGPDB_PRINT1((CE_NOTE,
6463446Smrj 		    "lyr_init: register master device unsuccessful"));
6473446Smrj 
6483446Smrj 		agp_regdev->agprd_arctype = ARC_AMD64NOAGP;
6493446Smrj 		AGPDB_PRINT1((CE_NOTE,
6503446Smrj 		    "lyr_init: no AGP master, but supports IOMMU in amd64"));
6513446Smrj 		return (0); /* Finished successfully */
6523446Smrj 	}
6533446Smrj 
6543446Smrj 	if (agp_target_regis_byname(target_hdlp, agpgart_li)) {
6553446Smrj 		AGPDB_PRINT1((CE_NOTE,
6563446Smrj 		    "lyr_init: register target device unsuccessful"));
6573446Smrj 
6583446Smrj 		agp_regdev->agprd_arctype = ARC_AMD64NOAGP;
6593446Smrj 
6603446Smrj 		AGPDB_PRINT1((CE_NOTE,
6613446Smrj 		    "lyr_init: no AGP bridge, but supports IOMMU in amd64"));
6623446Smrj 
6633446Smrj 		agp_master_unregister(&agp_regdev->agprd_masterhdl);
6643446Smrj 		return (0); /* Finished successfully */
6653446Smrj 
6663446Smrj 	}
6673446Smrj 
6683446Smrj 
6693446Smrj 	AGPDB_PRINT1((CE_NOTE,
6703446Smrj 	    "lyr_init: the system is AMD64 AGP architecture"));
6713446Smrj 
6723446Smrj 	agp_regdev->agprd_arctype = ARC_AMD64AGP;
6733446Smrj 
6743446Smrj 	return (0); /* Finished successfully */
6753446Smrj 
6763446Smrj err3:
6773446Smrj 	agp_target_unregister(&agp_regdev->agprd_targethdl);
6783446Smrj err2:
6793446Smrj 	agp_master_unregister(&agp_regdev->agprd_masterhdl);
6803446Smrj err1:
6813446Smrj 	agp_regdev->agprd_arctype = ARC_UNKNOWN;
6823446Smrj 	return (-1);
6833446Smrj }
6843446Smrj 
6853446Smrj void
6863446Smrj lyr_end(agp_registered_dev_t *agp_regdev)
6873446Smrj {
6883446Smrj 	ASSERT(agp_regdev);
6893446Smrj 
6903446Smrj 	switch (agp_regdev->agprd_arctype) {
6913446Smrj 	case ARC_IGD810:
6923446Smrj 	case ARC_IGD830:
6933446Smrj 	case ARC_INTELAGP:
6943446Smrj 		agp_master_unregister(&agp_regdev->agprd_masterhdl);
6953446Smrj 		agp_target_unregister(&agp_regdev->agprd_targethdl);
6963446Smrj 
6973446Smrj 		return;
6983446Smrj 	case ARC_AMD64AGP:
6993446Smrj 		agp_master_unregister(&agp_regdev->agprd_masterhdl);
7003446Smrj 		agp_target_unregister(&agp_regdev->agprd_targethdl);
7013446Smrj 		amd64_gart_unregister(&agp_regdev->agprd_cpugarts);
7023446Smrj 
7033446Smrj 		return;
7043446Smrj 	case ARC_AMD64NOAGP:
7053446Smrj 		amd64_gart_unregister(&agp_regdev->agprd_cpugarts);
7063446Smrj 
7073446Smrj 		return;
7083446Smrj 	default:
7093446Smrj 		ASSERT(0);
7103446Smrj 		return;
7113446Smrj 	}
7123446Smrj }
7133446Smrj 
7143446Smrj int
7153446Smrj lyr_get_info(agp_kern_info_t *info, agp_registered_dev_t *agp_regdev)
7163446Smrj {
7173446Smrj 	ldi_handle_t hdl;
7183446Smrj 	igd_info_t value1;
7193446Smrj 	i_agp_info_t value2;
7203446Smrj 	amdgart_info_t value3;
7213446Smrj 	size_t prealloc_size;
7223446Smrj 	int err;
7233446Smrj 	amd64_gart_dev_list_t	*gart_head;
7243446Smrj 
7253446Smrj 	ASSERT(info);
7263446Smrj 	ASSERT(agp_regdev);
7273446Smrj 
7283446Smrj 	switch (agp_regdev->agprd_arctype) {
7293446Smrj 	case ARC_IGD810:
7303446Smrj 		hdl = agp_regdev->agprd_masterhdl;
7313446Smrj 		err = ldi_ioctl(hdl, I8XX_GET_INFO, (intptr_t)&value1,
7323446Smrj 		    FKIOCTL, kcred, 0);
7333446Smrj 		if (err)
7343446Smrj 			return (-1);
7353446Smrj 		info->agpki_mdevid = value1.igd_devid;
7363446Smrj 		info->agpki_aperbase = value1.igd_aperbase;
7373446Smrj 		info->agpki_apersize = value1.igd_apersize;
7383446Smrj 
7393446Smrj 		hdl = agp_regdev->agprd_targethdl;
7403446Smrj 		err = ldi_ioctl(hdl, I8XX_GET_PREALLOC_SIZE,
7413446Smrj 		    (intptr_t)&prealloc_size, FKIOCTL, kcred, 0);
7423446Smrj 		if (err)
7433446Smrj 			return (-1);
7443446Smrj 		info->agpki_presize = prealloc_size;
7453446Smrj 
7463446Smrj 		break;
7473446Smrj 
7483446Smrj 	case ARC_IGD830:
7493446Smrj 		hdl = agp_regdev->agprd_masterhdl;
7503446Smrj 		err = ldi_ioctl(hdl, I8XX_GET_INFO, (intptr_t)&value1,
7513446Smrj 		    FKIOCTL, kcred, 0);
7523446Smrj 		if (err)
7533446Smrj 			return (-1);
7543446Smrj 		info->agpki_mdevid = value1.igd_devid;
7553446Smrj 		info->agpki_aperbase = value1.igd_aperbase;
7563446Smrj 		info->agpki_apersize = value1.igd_apersize;
7573446Smrj 
7583446Smrj 		hdl = agp_regdev->agprd_targethdl;
7593446Smrj 		err = ldi_ioctl(hdl, I8XX_GET_PREALLOC_SIZE,
7603446Smrj 		    (intptr_t)&prealloc_size, FKIOCTL, kcred, 0);
7613446Smrj 		if (err)
7623446Smrj 			return (-1);
7633446Smrj 
7643446Smrj 		/*
7653446Smrj 		 * Assume all units are kilobytes unless explicitly
7663446Smrj 		 * stated below:
7673446Smrj 		 * preallocated GTT memory = preallocated memory - GTT size
7683446Smrj 		 * 	- scratch page size
7693446Smrj 		 *
7703446Smrj 		 * scratch page size = 4
771*5036Skz151634 		 * GTT size (KB) = aperture size (MB)
7723446Smrj 		 * this algorithm came from Xorg source code
7733446Smrj 		 */
774*5036Skz151634 		if (prealloc_size > (info->agpki_apersize + 4))
775*5036Skz151634 			prealloc_size =
776*5036Skz151634 			    prealloc_size - info->agpki_apersize - 4;
777*5036Skz151634 		else {
778*5036Skz151634 			AGPDB_PRINT2((CE_WARN, "lyr_get_info: "
779*5036Skz151634 			    "pre-allocated memory too small, setting to zero"));
780*5036Skz151634 			prealloc_size = 0;
781*5036Skz151634 		}
7823446Smrj 		info->agpki_presize = prealloc_size;
7834478Skz151634 		AGPDB_PRINT2((CE_NOTE,
7844478Skz151634 		    "lyr_get_info: prealloc_size = %ldKB, apersize = %dMB",
7854478Skz151634 		    prealloc_size, info->agpki_apersize));
7863446Smrj 		break;
7873446Smrj 	case ARC_INTELAGP:
7883446Smrj 	case ARC_AMD64AGP:
7893446Smrj 		/* AGP devices */
7903446Smrj 		hdl = agp_regdev->agprd_masterhdl;
7913446Smrj 		err = ldi_ioctl(hdl, AGP_MASTER_GETINFO,
7923446Smrj 		    (intptr_t)&value2, FKIOCTL, kcred, 0);
7933446Smrj 		if (err)
7943446Smrj 			return (-1);
7953446Smrj 		info->agpki_mdevid = value2.iagp_devid;
7963446Smrj 		info->agpki_mver = value2.iagp_ver;
7973446Smrj 		info->agpki_mstatus = value2.iagp_mode;
7983446Smrj 		hdl = agp_regdev->agprd_targethdl;
7993446Smrj 		err = ldi_ioctl(hdl, AGP_TARGET_GETINFO,
8003446Smrj 		    (intptr_t)&value2, FKIOCTL, kcred, 0);
8013446Smrj 		if (err)
8023446Smrj 			return (-1);
8033446Smrj 		info->agpki_tdevid = value2.iagp_devid;
8043446Smrj 		info->agpki_tver = value2.iagp_ver;
8053446Smrj 		info->agpki_tstatus = value2.iagp_mode;
8063446Smrj 		info->agpki_aperbase = value2.iagp_aperbase;
8073446Smrj 		info->agpki_apersize = value2.iagp_apersize;
8083446Smrj 		break;
8093446Smrj 	case ARC_AMD64NOAGP:
8103446Smrj 		/* Meaningful for IOMMU support only */
8113446Smrj 		gart_head = agp_regdev->agprd_cpugarts.gart_dev_list_head;
8123446Smrj 		err = ldi_ioctl(gart_head->gart_devhdl, AMD64_GET_INFO,
8133446Smrj 		    (intptr_t)&value3, FKIOCTL, kcred, 0);
8143446Smrj 		if (err)
8153446Smrj 			return (-1);
8163446Smrj 		info->agpki_aperbase = value3.cgart_aperbase;
8173446Smrj 		info->agpki_apersize = value3.cgart_apersize;
8183446Smrj 		break;
8193446Smrj 	default:
8203446Smrj 		AGPDB_PRINT2((CE_WARN,
8213446Smrj 		    "lyr_get_info: function doesn't work for unknown arc"));
8223446Smrj 		return (-1);
8233446Smrj 	}
8243446Smrj 	if ((info->agpki_apersize >= MAXAPERMEGAS) ||
8253446Smrj 	    (info->agpki_apersize == 0) ||
8263446Smrj 	    (info->agpki_aperbase == 0)) {
8273446Smrj 		AGPDB_PRINT2((CE_WARN,
8283446Smrj 		    "lyr_get_info: aperture is not programmed correctly!"));
8293446Smrj 		return (-1);
8303446Smrj 	}
8313446Smrj 
8323446Smrj 	return (0);
8333446Smrj }
8343446Smrj 
8353446Smrj /*
8363446Smrj  * lyr_i8xx_add_to_gtt()
8373446Smrj  *
8383446Smrj  * Description:
8393446Smrj  * 	This function sets up the integrated video device gtt table
8403446Smrj  * 	via an ioclt to the AGP master driver.
8413446Smrj  *
8423446Smrj  * Arguments:
8433446Smrj  * 	pg_offset	The start entry to be setup
8443446Smrj  * 	keyent		Keytable entity pointer
8453446Smrj  *	agp_regdev	AGP devices registration struct pointer
8463446Smrj  *
8473446Smrj  * Returns:
8483446Smrj  * 	0		success
8493446Smrj  * 	-1		invalid operations
8503446Smrj  */
8513446Smrj int
8523446Smrj lyr_i8xx_add_to_gtt(uint32_t pg_offset, keytable_ent_t *keyent,
8533446Smrj     agp_registered_dev_t *agp_regdev)
8543446Smrj {
8553446Smrj 	int err = 0;
8563446Smrj 	int rval;
8573446Smrj 	ldi_handle_t hdl;
8583446Smrj 	igd_gtt_seg_t gttseg;
8593446Smrj 	uint32_t *addrp, i;
8603446Smrj 	uint32_t npages;
8613446Smrj 
8623446Smrj 	ASSERT(keyent);
8633446Smrj 	ASSERT(agp_regdev);
8643446Smrj 	gttseg.igs_pgstart =  pg_offset;
8653446Smrj 	npages = keyent->kte_pages;
8663446Smrj 	gttseg.igs_npage = npages;
8673446Smrj 	gttseg.igs_type = keyent->kte_type;
8683446Smrj 	gttseg.igs_phyaddr = (uint32_t *)kmem_zalloc
8694478Skz151634 	    (sizeof (uint32_t) * gttseg.igs_npage, KM_SLEEP);
8703446Smrj 
8713446Smrj 	addrp = gttseg.igs_phyaddr;
8723446Smrj 	for (i = 0; i < npages; i++, addrp++) {
8733446Smrj 		*addrp =
8743446Smrj 		    (uint32_t)((keyent->kte_pfnarray[i]) << GTT_PAGE_SHIFT);
8753446Smrj 	}
8763446Smrj 
8773446Smrj 	hdl = agp_regdev->agprd_masterhdl;
8783446Smrj 	if (ldi_ioctl(hdl, I8XX_ADD2GTT, (intptr_t)&gttseg, FKIOCTL,
8793446Smrj 	    kcred, &rval)) {
8803446Smrj 		AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: ldi_ioctl error"));
8813446Smrj 		AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: pg_start=0x%x",
8823446Smrj 		    gttseg.igs_pgstart));
8833446Smrj 		AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: pages=0x%x",
8843446Smrj 		    gttseg.igs_npage));
8853446Smrj 		AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: type=0x%x",
8863446Smrj 		    gttseg.igs_type));
8873446Smrj 		err = -1;
8883446Smrj 	}
8893446Smrj 	kmem_free(gttseg.igs_phyaddr, sizeof (uint32_t) * gttseg.igs_npage);
8903446Smrj 	return (err);
8913446Smrj }
8923446Smrj 
8933446Smrj /*
8943446Smrj  * lyr_i8xx_remove_from_gtt()
8953446Smrj  *
8963446Smrj  * Description:
8973446Smrj  * 	This function clears the integrated video device gtt table via
8983446Smrj  * 	an ioctl to the agp master device.
8993446Smrj  *
9003446Smrj  * Arguments:
9013446Smrj  * 	pg_offset	The starting entry to be cleared
9023446Smrj  * 	npage		The number of entries to be cleared
9033446Smrj  *	agp_regdev	AGP devices struct pointer
9043446Smrj  *
9053446Smrj  * Returns:
9063446Smrj  * 	0		success
9073446Smrj  * 	-1		invalid operations
9083446Smrj  */
9093446Smrj int
9103446Smrj lyr_i8xx_remove_from_gtt(uint32_t pg_offset, uint32_t npage,
9113446Smrj     agp_registered_dev_t *agp_regdev)
9123446Smrj {
9133446Smrj 	int			rval;
9143446Smrj 	ldi_handle_t		hdl;
9153446Smrj 	igd_gtt_seg_t		gttseg;
9163446Smrj 
9173446Smrj 	gttseg.igs_pgstart =  pg_offset;
9183446Smrj 	gttseg.igs_npage = npage;
9193446Smrj 
9203446Smrj 	hdl = agp_regdev->agprd_masterhdl;
9213446Smrj 	if (ldi_ioctl(hdl, I8XX_REM_GTT, (intptr_t)&gttseg, FKIOCTL,
9223446Smrj 	    kcred, &rval))
9233446Smrj 		return (-1);
9243446Smrj 
9253446Smrj 	return (0);
9263446Smrj }
9273446Smrj 
9283446Smrj /*
9293446Smrj  * lyr_set_gart_addr()
9303446Smrj  *
9313446Smrj  * Description:
9323446Smrj  *	This function puts the gart table physical address in the
9333446Smrj  * 	gart base register.
9343446Smrj  *	Please refer to gart and gtt table base register format for
9353446Smrj  *	gart base register format in agpdefs.h.
9363446Smrj  *
9373446Smrj  * Arguments:
9383446Smrj  * 	phy_base	The base physical address of gart table
9393446Smrj  *	agp_regdev	AGP devices registration struct pointer
9403446Smrj  *
9413446Smrj  * Returns:
9423446Smrj  * 	0		success
9433446Smrj  * 	-1		failed
9443446Smrj  *
9453446Smrj  */
9463446Smrj 
9473446Smrj int
9483446Smrj lyr_set_gart_addr(uint64_t phy_base, agp_registered_dev_t *agp_regdev)
9493446Smrj {
9503446Smrj 	amd64_gart_dev_list_t	*gart_list;
9513446Smrj 	ldi_handle_t		hdl;
9523446Smrj 	int			err = 0;
9533446Smrj 
9543446Smrj 	ASSERT(agp_regdev);
9553446Smrj 	switch (agp_regdev->agprd_arctype) {
9563446Smrj 	case ARC_IGD810:
9573446Smrj 	{
9583446Smrj 		uint32_t base;
9593446Smrj 
9603446Smrj 		ASSERT((phy_base & ~I810_POINTER_MASK) == 0);
9613446Smrj 		base = (uint32_t)phy_base;
9623446Smrj 
9633446Smrj 		hdl = agp_regdev->agprd_masterhdl;
9643446Smrj 		err = ldi_ioctl(hdl, I810_SET_GTT_BASE,
9653446Smrj 		    (intptr_t)&base, FKIOCTL, kcred, 0);
9663446Smrj 		break;
9673446Smrj 	}
9683446Smrj 	case ARC_INTELAGP:
9693446Smrj 	{
9703446Smrj 		uint32_t addr;
9713446Smrj 		addr = (uint32_t)phy_base;
9723446Smrj 
9733446Smrj 		ASSERT((phy_base & ~GTT_POINTER_MASK) == 0);
9743446Smrj 		hdl = agp_regdev->agprd_targethdl;
9753446Smrj 		err = ldi_ioctl(hdl, AGP_TARGET_SET_GATTADDR,
9763446Smrj 		    (intptr_t)&addr, FKIOCTL, kcred, 0);
9773446Smrj 		break;
9783446Smrj 	}
9793446Smrj 	case ARC_AMD64NOAGP:
9803446Smrj 	case ARC_AMD64AGP:
9813446Smrj 	{
9823446Smrj 		uint32_t addr;
9833446Smrj 
9843446Smrj 		ASSERT((phy_base & ~AMD64_POINTER_MASK) == 0);
9853446Smrj 		addr = (uint32_t)((phy_base >> AMD64_GARTBASE_SHIFT)
9863446Smrj 		    & AMD64_GARTBASE_MASK);
9873446Smrj 
9883446Smrj 		for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head;
9893446Smrj 		    gart_list;
9903446Smrj 		    gart_list = gart_list->next) {
9913446Smrj 			hdl = gart_list->gart_devhdl;
9923446Smrj 			if (ldi_ioctl(hdl, AMD64_SET_GART_ADDR,
9933446Smrj 			    (intptr_t)&addr, FKIOCTL, kcred, 0)) {
9943446Smrj 				err = -1;
9953446Smrj 				break;
9963446Smrj 			}
9973446Smrj 		}
9983446Smrj 		break;
9993446Smrj 	}
10003446Smrj 	default:
10013446Smrj 		err = -1;
10023446Smrj 	}
10033446Smrj 
10043446Smrj 	if (err)
10053446Smrj 		return (-1);
10063446Smrj 
10073446Smrj 	return (0);
10083446Smrj }
10093446Smrj 
10103446Smrj int
10113446Smrj lyr_set_agp_cmd(uint32_t cmd, agp_registered_dev_t *agp_regdev)
10123446Smrj {
10133446Smrj 	ldi_handle_t hdl;
10143446Smrj 	uint32_t command;
10153446Smrj 
10163446Smrj 	ASSERT(agp_regdev);
10173446Smrj 	command = cmd;
10183446Smrj 	hdl = agp_regdev->agprd_targethdl;
10193446Smrj 	if (ldi_ioctl(hdl, AGP_TARGET_SETCMD,
10203446Smrj 	    (intptr_t)&command, FKIOCTL, kcred, 0))
10213446Smrj 		return (-1);
10223446Smrj 	hdl = agp_regdev->agprd_masterhdl;
10233446Smrj 	if (ldi_ioctl(hdl, AGP_MASTER_SETCMD,
10243446Smrj 	    (intptr_t)&command, FKIOCTL, kcred, 0))
10253446Smrj 		return (-1);
10263446Smrj 
10273446Smrj 	return (0);
10283446Smrj }
10293446Smrj 
10303446Smrj int
10313446Smrj lyr_config_devices(agp_registered_dev_t *agp_regdev)
10323446Smrj {
10333446Smrj 	amd64_gart_dev_list_t	*gart_list;
10343446Smrj 	ldi_handle_t		hdl;
10353446Smrj 	int			rc = 0;
10363446Smrj 
10373446Smrj 	ASSERT(agp_regdev);
10383446Smrj 	switch (agp_regdev->agprd_arctype) {
10393446Smrj 	case ARC_IGD830:
10403446Smrj 	case ARC_IGD810:
10413446Smrj 		break;
10423446Smrj 	case ARC_INTELAGP:
10433446Smrj 	{
10443446Smrj 		hdl = agp_regdev->agprd_targethdl;
10453446Smrj 		rc = ldi_ioctl(hdl, AGP_TARGET_CONFIGURE,
10463446Smrj 		    0, FKIOCTL, kcred, 0);
10473446Smrj 		break;
10483446Smrj 	}
10493446Smrj 	case ARC_AMD64NOAGP:
10503446Smrj 	case ARC_AMD64AGP:
10513446Smrj 	{
10523446Smrj 		/*
10533446Smrj 		 * BIOS always shadow registers such like Aperture Base
10543446Smrj 		 * register, Aperture Size Register from the AGP bridge
10553446Smrj 		 * to the AMD64 CPU host bridge. If future BIOSes are broken
10563446Smrj 		 * in this regard, we may need to shadow these registers
10573446Smrj 		 * in driver.
10583446Smrj 		 */
10593446Smrj 
10603446Smrj 		for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head;
10613446Smrj 		    gart_list;
10623446Smrj 		    gart_list = gart_list->next) {
10633446Smrj 			hdl = gart_list->gart_devhdl;
10643446Smrj 			if (ldi_ioctl(hdl, AMD64_CONFIGURE,
10653446Smrj 			    0, FKIOCTL, kcred, 0)) {
10663446Smrj 				rc = -1;
10673446Smrj 				break;
10683446Smrj 			}
10693446Smrj 		}
10703446Smrj 		break;
10713446Smrj 	}
10723446Smrj 	default:
10733446Smrj 		rc = -1;
10743446Smrj 	}
10753446Smrj 
10763446Smrj 	if (rc)
10773446Smrj 		return (-1);
10783446Smrj 
10793446Smrj 	return (0);
10803446Smrj }
10813446Smrj 
10823446Smrj int
10833446Smrj lyr_unconfig_devices(agp_registered_dev_t *agp_regdev)
10843446Smrj {
10853446Smrj 	amd64_gart_dev_list_t	*gart_list;
10863446Smrj 	ldi_handle_t		hdl;
10873446Smrj 	int			rc = 0;
10883446Smrj 
10893446Smrj 	ASSERT(agp_regdev);
10903446Smrj 	switch (agp_regdev->agprd_arctype) {
10913446Smrj 	case ARC_IGD830:
10923446Smrj 	case ARC_IGD810:
10933446Smrj 	{
10943446Smrj 		hdl = agp_regdev->agprd_masterhdl;
10953446Smrj 		rc = ldi_ioctl(hdl, I8XX_UNCONFIG, 0, FKIOCTL, kcred, 0);
10963446Smrj 		break;
10973446Smrj 	}
10983446Smrj 	case ARC_INTELAGP:
10993446Smrj 	{
11003446Smrj 		hdl = agp_regdev->agprd_targethdl;
11013446Smrj 		rc = ldi_ioctl(hdl, AGP_TARGET_UNCONFIG,
11023446Smrj 		    0, FKIOCTL, kcred, 0);
11033446Smrj 		break;
11043446Smrj 	}
11053446Smrj 	case ARC_AMD64NOAGP:
11063446Smrj 	case ARC_AMD64AGP:
11073446Smrj 	{
11083446Smrj 		for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head;
11093446Smrj 		    gart_list; gart_list = gart_list->next) {
11103446Smrj 			hdl = gart_list->gart_devhdl;
11113446Smrj 			if (ldi_ioctl(hdl, AMD64_UNCONFIG,
11123446Smrj 			    0, FKIOCTL, kcred, 0)) {
11133446Smrj 				rc = -1;
11143446Smrj 				break;
11153446Smrj 			}
11163446Smrj 		}
11173446Smrj 		break;
11183446Smrj 	}
11193446Smrj 	default:
11203446Smrj 		rc = -1;
11213446Smrj 	}
11223446Smrj 
11233446Smrj 	if (rc)
11243446Smrj 		return (-1);
11253446Smrj 
11263446Smrj 	return (0);
11273446Smrj }
11283446Smrj 
11293446Smrj /*
11303446Smrj  * lyr_flush_gart_cache()
11313446Smrj  *
11323446Smrj  * Description:
11333446Smrj  * 	This function flushes the GART translation look-aside buffer. All
11343446Smrj  * 	GART translation caches will be flushed after this operation.
11353446Smrj  *
11363446Smrj  * Arguments:
11373446Smrj  *	agp_regdev	AGP devices struct pointer
11383446Smrj  */
11393446Smrj void
11403446Smrj lyr_flush_gart_cache(agp_registered_dev_t *agp_regdev)
11413446Smrj {
11423446Smrj 	amd64_gart_dev_list_t	*gart_list;
11433446Smrj 	ldi_handle_t		hdl;
11443446Smrj 
11453446Smrj 	ASSERT(agp_regdev);
11463446Smrj 	if ((agp_regdev->agprd_arctype == ARC_AMD64AGP) ||
11473446Smrj 	    (agp_regdev->agprd_arctype == ARC_AMD64NOAGP)) {
11483446Smrj 		for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head;
11493446Smrj 		    gart_list; gart_list = gart_list->next) {
11503446Smrj 			hdl = gart_list->gart_devhdl;
11513446Smrj 			(void) ldi_ioctl(hdl, AMD64_FLUSH_GTLB,
11523446Smrj 			    0, FKIOCTL, kcred, 0);
11533446Smrj 		}
11543446Smrj 	} else if (agp_regdev->agprd_arctype == ARC_INTELAGP) {
11553446Smrj 		hdl = agp_regdev->agprd_targethdl;
11563446Smrj 		(void) ldi_ioctl(hdl, AGP_TARGET_FLUSH_GTLB, 0,
11573446Smrj 		    FKIOCTL, kcred, 0);
11583446Smrj 	}
11593446Smrj }
11603446Smrj 
11613446Smrj /*
11623446Smrj  * get_max_pages()
11633446Smrj  *
11643446Smrj  * Description:
11653446Smrj  * 	This function compute the total pages allowed for agp aperture
11663446Smrj  *	based on the ammount of physical pages.
11673446Smrj  * 	The algorithm is: compare the aperture size with 1/4 of total
11683446Smrj  *	physical pages, and use the smaller one to for the max available
11693446Smrj  * 	pages.
11703446Smrj  *
11713446Smrj  * Arguments:
11723446Smrj  * 	aper_size	system agp aperture size (in MB)
11733446Smrj  *
11743446Smrj  * Returns:
11753446Smrj  * 	The max possible number of agp memory pages available to users
11763446Smrj  */
11773446Smrj static uint32_t
11783446Smrj get_max_pages(uint32_t aper_size)
11793446Smrj {
11803446Smrj 	uint32_t i, j;
11813446Smrj 
11823446Smrj 	ASSERT(aper_size <= MAXAPERMEGAS);
11833446Smrj 
11843446Smrj 	i = AGP_MB2PAGES(aper_size);
11853446Smrj 	j = (physmem >> 2);
11863446Smrj 
11873446Smrj 	return ((i < j) ? i : j);
11883446Smrj }
11893446Smrj 
11903446Smrj /*
11913446Smrj  * agp_fill_empty_keyent()
11923446Smrj  *
11933446Smrj  * Description:
11943446Smrj  * 	This function finds a empty key table slot and
11953446Smrj  * 	fills it with a new entity.
11963446Smrj  *
11973446Smrj  * Arguments:
11983446Smrj  * 	softsate	driver soft state pointer
11993446Smrj  * 	entryp		new entity data pointer
12003446Smrj  *
12013446Smrj  * Returns:
12023446Smrj  * 	NULL	no key table slot available
12033446Smrj  * 	entryp	the new entity slot pointer
12043446Smrj  */
12053446Smrj static keytable_ent_t *
12063446Smrj agp_fill_empty_keyent(agpgart_softstate_t *softstate, keytable_ent_t *entryp)
12073446Smrj {
12083446Smrj 	int key;
12093446Smrj 	keytable_ent_t *newentryp;
12103446Smrj 
12113446Smrj 	ASSERT(softstate);
12123446Smrj 	ASSERT(entryp);
12133446Smrj 	ASSERT(entryp->kte_memhdl);
12143446Smrj 	ASSERT(entryp->kte_pfnarray);
12153446Smrj 	ASSERT(mutex_owned(&softstate->asoft_instmutex));
12163446Smrj 
12173446Smrj 	for (key = 0; key < AGP_MAXKEYS; key++) {
12183446Smrj 		newentryp = &softstate->asoft_table[key];
12193446Smrj 		if (newentryp->kte_memhdl == NULL) {
12203446Smrj 			break;
12213446Smrj 		}
12223446Smrj 	}
12233446Smrj 
12243446Smrj 	if (key >= AGP_MAXKEYS) {
12253446Smrj 		AGPDB_PRINT2((CE_WARN,
12263446Smrj 		    "agp_fill_empty_keyent: key table exhausted"));
12273446Smrj 		return (NULL);
12283446Smrj 	}
12293446Smrj 
12303446Smrj 	ASSERT(newentryp->kte_pfnarray == NULL);
12313446Smrj 	bcopy(entryp, newentryp, sizeof (keytable_ent_t));
12323446Smrj 	newentryp->kte_key = key;
12333446Smrj 
12343446Smrj 	return (newentryp);
12353446Smrj }
12363446Smrj 
12373446Smrj /*
12383446Smrj  * agp_find_bound_keyent()
12393446Smrj  *
12403446Smrj  * Description:
12413446Smrj  * 	This function finds the key table entity by agp aperture page offset.
12423446Smrj  * 	Every keytable entity will have an agp aperture range after the binding
12433446Smrj  *	operation.
12443446Smrj  *
12453446Smrj  * Arguments:
12463446Smrj  * 	softsate	driver soft state pointer
12473446Smrj  * 	pg_offset	agp aperture page offset
12483446Smrj  *
12493446Smrj  * Returns:
12503446Smrj  * 	NULL		no such keytable entity
12513446Smrj  * 	pointer		key table entity pointer found
12523446Smrj  */
12533446Smrj static keytable_ent_t *
12543446Smrj agp_find_bound_keyent(agpgart_softstate_t *softstate, uint32_t pg_offset)
12553446Smrj {
12563446Smrj 	int keycount;
12573446Smrj 	keytable_ent_t *entryp;
12583446Smrj 
12593446Smrj 	ASSERT(softstate);
12603446Smrj 	ASSERT(mutex_owned(&softstate->asoft_instmutex));
12613446Smrj 
12623446Smrj 	for (keycount = 0; keycount < AGP_MAXKEYS; keycount++) {
12633446Smrj 		entryp = &softstate->asoft_table[keycount];
12643446Smrj 		if (entryp->kte_bound == 0) {
12653446Smrj 			continue;
12663446Smrj 		}
12673446Smrj 
12683446Smrj 		if (pg_offset < entryp->kte_pgoff)
12693446Smrj 			continue;
12703446Smrj 		if (pg_offset >= (entryp->kte_pgoff + entryp->kte_pages))
12713446Smrj 			continue;
12723446Smrj 
12733446Smrj 		ASSERT(entryp->kte_memhdl);
12743446Smrj 		ASSERT(entryp->kte_pfnarray);
12753446Smrj 
12763446Smrj 		return (entryp);
12773446Smrj 	}
12783446Smrj 
12793446Smrj 	return (NULL);
12803446Smrj }
12813446Smrj 
12823446Smrj /*
12833446Smrj  * agp_check_off()
12843446Smrj  *
12853446Smrj  * Description:
12863446Smrj  * 	This function checks whether an AGP aperture range to be bound
12873446Smrj  *	overlaps with AGP offset already bound.
12883446Smrj  *
12893446Smrj  * Arguments:
12903446Smrj  *	entryp		key table start entry pointer
12913446Smrj  * 	pg_start	AGP range start page offset
12923446Smrj  *	pg_num		pages number to be bound
12933446Smrj  *
12943446Smrj  * Returns:
12953446Smrj  *	0		Does not overlap
12963446Smrj  *	-1		Overlaps
12973446Smrj  */
12983446Smrj 
12993446Smrj static int
13003446Smrj agp_check_off(keytable_ent_t *entryp, uint32_t pg_start, uint32_t pg_num)
13013446Smrj {
13023446Smrj 	int key;
13033446Smrj 	uint64_t pg_end;
13043446Smrj 	uint64_t kpg_end;
13053446Smrj 
13063446Smrj 	ASSERT(entryp);
13073446Smrj 
13083446Smrj 	pg_end = pg_start + pg_num;
13093446Smrj 	for (key = 0; key < AGP_MAXKEYS; key++) {
13103446Smrj 		if (!entryp[key].kte_bound)
13113446Smrj 			continue;
13123446Smrj 
13133446Smrj 		kpg_end = entryp[key].kte_pgoff + entryp[key].kte_pages;
13143446Smrj 		if (!((pg_end <= entryp[key].kte_pgoff) ||
13153446Smrj 		    (pg_start >= kpg_end)))
13163446Smrj 			break;
13173446Smrj 	}
13183446Smrj 
13193446Smrj 	if (key == AGP_MAXKEYS)
13203446Smrj 		return (0);
13213446Smrj 	else
13223446Smrj 		return (-1);
13233446Smrj }
13243446Smrj 
13253446Smrj static int
13263446Smrj is_controlling_proc(agpgart_softstate_t *st)
13273446Smrj {
13283446Smrj 	ASSERT(st);
13293446Smrj 
13303446Smrj 	if (!st->asoft_acquired) {
13313446Smrj 		AGPDB_PRINT2((CE_WARN,
13323446Smrj 		    "ioctl_agpgart_setup: gart not acquired"));
13333446Smrj 		return (-1);
13343446Smrj 	}
13353446Smrj 	if (st->asoft_curpid != ddi_get_pid()) {
13363446Smrj 		AGPDB_PRINT2((CE_WARN,
13373446Smrj 		    "ioctl_agpgart_release: not  controlling process"));
13383446Smrj 		return (-1);
13393446Smrj 	}
13403446Smrj 
13413446Smrj 	return (0);
13423446Smrj }
13433446Smrj 
13443446Smrj static void release_control(agpgart_softstate_t *st)
13453446Smrj {
13463446Smrj 	st->asoft_curpid = 0;
13473446Smrj 	st->asoft_acquired = 0;
13483446Smrj }
13493446Smrj 
13503446Smrj static void acquire_control(agpgart_softstate_t *st)
13513446Smrj {
13523446Smrj 	st->asoft_curpid = ddi_get_pid();
13533446Smrj 	st->asoft_acquired = 1;
13543446Smrj }
13553446Smrj 
13563446Smrj /*
13573446Smrj  * agp_remove_from_gart()
13583446Smrj  *
13593446Smrj  * Description:
13603446Smrj  * 	This function fills the gart table entries by a given page
13613446Smrj  * 	frame number array and setup the agp aperture page to physical
13623446Smrj  * 	memory page translation.
13633446Smrj  * Arguments:
13643446Smrj  * 	pg_offset	Starting aperture page to be bound
13653446Smrj  * 	entries		the number of pages to be bound
13663446Smrj  * 	acc_hdl		GART table dma memory acc handle
13673446Smrj  * 	tablep		GART table kernel virtual address
13683446Smrj  */
13693446Smrj static void
13703446Smrj agp_remove_from_gart(
13713446Smrj     uint32_t pg_offset,
13723446Smrj     uint32_t entries,
13733446Smrj     ddi_dma_handle_t dma_hdl,
13743446Smrj     uint32_t *tablep)
13753446Smrj {
13763446Smrj 	uint32_t items = 0;
13773446Smrj 	uint32_t *entryp;
13783446Smrj 
13793446Smrj 	entryp = tablep + pg_offset;
13803446Smrj 	while (items < entries) {
13813446Smrj 		*(entryp + items) = 0;
13823446Smrj 		items++;
13833446Smrj 	}
13843446Smrj 	(void) ddi_dma_sync(dma_hdl, pg_offset * sizeof (uint32_t),
13853446Smrj 	    entries * sizeof (uint32_t), DDI_DMA_SYNC_FORDEV);
13863446Smrj }
13873446Smrj 
13883446Smrj /*
13893446Smrj  * agp_unbind_key()
13903446Smrj  *
13913446Smrj  * Description:
13923446Smrj  * 	This function unbinds AGP memory from the gart table. It will clear
13933446Smrj  * 	all the gart entries related to this agp memory.
13943446Smrj  *
13953446Smrj  * Arguments:
13963446Smrj  * 	softstate		driver soft state pointer
13973446Smrj  * 	entryp			key table entity pointer
13983446Smrj  *
13993446Smrj  * Returns:
14003446Smrj  * 	EINVAL		invalid key table entity pointer
14013446Smrj  * 	0		success
14023446Smrj  *
14033446Smrj  */
14043446Smrj static int
14053446Smrj agp_unbind_key(agpgart_softstate_t *softstate, keytable_ent_t *entryp)
14063446Smrj {
14073446Smrj 	int retval = 0;
14083446Smrj 
14093446Smrj 	ASSERT(entryp);
14103446Smrj 	ASSERT((entryp->kte_key >= 0) && (entryp->kte_key < AGP_MAXKEYS));
14113446Smrj 
14123446Smrj 	if (!entryp->kte_bound) {
14133446Smrj 		AGPDB_PRINT2((CE_WARN,
14143446Smrj 		    "agp_unbind_key: key = 0x%x, not bound",
14153446Smrj 		    entryp->kte_key));
14163446Smrj 		return (EINVAL);
14173446Smrj 	}
14183446Smrj 	if (entryp->kte_refcnt) {
14193446Smrj 		AGPDB_PRINT2((CE_WARN,
14203446Smrj 		    "agp_unbind_key: memory is exported to users"));
14213446Smrj 		return (EINVAL);
14223446Smrj 	}
14233446Smrj 
14243446Smrj 	ASSERT((entryp->kte_pgoff + entryp->kte_pages) <=
14253446Smrj 	    AGP_MB2PAGES(softstate->asoft_info.agpki_apersize));
14263446Smrj 	ASSERT((softstate->asoft_devreg.agprd_arctype != ARC_UNKNOWN));
14273446Smrj 
14283446Smrj 	switch (softstate->asoft_devreg.agprd_arctype) {
14293446Smrj 	case ARC_IGD810:
14303446Smrj 	case ARC_IGD830:
14313446Smrj 		retval = lyr_i8xx_remove_from_gtt(
14323446Smrj 		    entryp->kte_pgoff, entryp->kte_pages,
14333446Smrj 		    &softstate->asoft_devreg);
14343446Smrj 		if (retval) {
14353446Smrj 			AGPDB_PRINT2((CE_WARN,
14363446Smrj 			    "agp_unbind_key: Key = 0x%x, clear table error",
14373446Smrj 			    entryp->kte_key));
14383446Smrj 			return (EIO);
14393446Smrj 		}
14403446Smrj 		break;
14413446Smrj 	case ARC_INTELAGP:
14423446Smrj 	case ARC_AMD64NOAGP:
14433446Smrj 	case ARC_AMD64AGP:
14443446Smrj 		agp_remove_from_gart(entryp->kte_pgoff,
14453446Smrj 		    entryp->kte_pages,
14463446Smrj 		    softstate->gart_dma_handle,
14473446Smrj 		    (uint32_t *)softstate->gart_vbase);
14483446Smrj 		/* Flush GTLB table */
14493446Smrj 		lyr_flush_gart_cache(&softstate->asoft_devreg);
14503446Smrj 
14513446Smrj 		break;
14523446Smrj 	}
14533446Smrj 
14543446Smrj 	entryp->kte_bound = 0;
14553446Smrj 
14563446Smrj 	return (0);
14573446Smrj }
14583446Smrj 
14593446Smrj /*
14603446Smrj  * agp_dealloc_kmem()
14613446Smrj  *
14623446Smrj  * Description:
14633446Smrj  * 	This function deallocates dma memory resources for userland
14643446Smrj  * 	applications.
14653446Smrj  *
14663446Smrj  * Arguments:
14673446Smrj  * 	entryp		keytable entity pointer
14683446Smrj  */
14693446Smrj static void
14703446Smrj agp_dealloc_kmem(keytable_ent_t *entryp)
14713446Smrj {
14723446Smrj 	kmem_free(entryp->kte_pfnarray, sizeof (pfn_t) * entryp->kte_pages);
14733446Smrj 	entryp->kte_pfnarray = NULL;
14743446Smrj 
14753446Smrj 	(void) ddi_dma_unbind_handle(KMEMP(entryp->kte_memhdl)->kmem_handle);
14763446Smrj 	KMEMP(entryp->kte_memhdl)->kmem_cookies_num = 0;
14773446Smrj 	ddi_dma_mem_free(&KMEMP(entryp->kte_memhdl)->kmem_acchdl);
14783446Smrj 	KMEMP(entryp->kte_memhdl)->kmem_acchdl = NULL;
14793446Smrj 	KMEMP(entryp->kte_memhdl)->kmem_reallen = 0;
14803446Smrj 	KMEMP(entryp->kte_memhdl)->kmem_kvaddr = NULL;
14813446Smrj 
14823446Smrj 	ddi_dma_free_handle(&(KMEMP(entryp->kte_memhdl)->kmem_handle));
14833446Smrj 	KMEMP(entryp->kte_memhdl)->kmem_handle = NULL;
14843446Smrj 
14853446Smrj 	kmem_free(entryp->kte_memhdl, sizeof (agp_kmem_handle_t));
14863446Smrj 	entryp->kte_memhdl = NULL;
14873446Smrj }
14883446Smrj 
14893446Smrj /*
14903446Smrj  * agp_dealloc_pmem()
14913446Smrj  *
14923446Smrj  * Description:
14933446Smrj  * 	This function deallocates memory resource for direct mapping to
14943446Smrj  * 	userland applications.
14953446Smrj  *
14963446Smrj  * Arguments:
14973446Smrj  * 	entryp		key table entity pointer
14983446Smrj  *
14993446Smrj  */
15003446Smrj static void
15013446Smrj agp_dealloc_pmem(keytable_ent_t *entryp)
15023446Smrj {
15033446Smrj 	devmap_pmem_free(PMEMP(entryp->kte_memhdl)->pmem_cookie);
15043446Smrj 	PMEMP(entryp->kte_memhdl)->pmem_cookie = NULL;
15053446Smrj 	kmem_free(entryp->kte_memhdl, sizeof (agp_pmem_handle_t));
15063446Smrj 	entryp->kte_memhdl = NULL;
15073446Smrj 
15083446Smrj 	/* free the page frame number array */
15093446Smrj 	kmem_free(entryp->kte_pfnarray, sizeof (pfn_t) * entryp->kte_pages);
15103446Smrj 	entryp->kte_pfnarray = NULL;
15113446Smrj }
15123446Smrj 
15133446Smrj /*
15143446Smrj  * agp_dealloc_mem()
15153446Smrj  *
15163446Smrj  * Description:
15173446Smrj  * 	This function deallocates physical memory resources allocated for
15183446Smrj  *	userland applications.
15193446Smrj  *
15203446Smrj  * Arguments:
15213446Smrj  * 	st		driver soft state pointer
15223446Smrj  * 	entryp		key table entity pointer
15233446Smrj  *
15243446Smrj  * Returns:
15253446Smrj  * 	-1		not a valid memory type or the memory is mapped by
15263446Smrj  * 			user area applications
15273446Smrj  * 	0		success
15283446Smrj  */
15293446Smrj static int
15303446Smrj agp_dealloc_mem(agpgart_softstate_t *st, keytable_ent_t	*entryp)
15313446Smrj {
15323446Smrj 
15333446Smrj 	ASSERT(entryp);
15343446Smrj 	ASSERT(st);
15353446Smrj 	ASSERT(entryp->kte_memhdl);
15363446Smrj 	ASSERT(mutex_owned(&st->asoft_instmutex));
15373446Smrj 
15383446Smrj 	/* auto unbind here */
15393446Smrj 	if (entryp->kte_bound && !entryp->kte_refcnt) {
15403446Smrj 		AGPDB_PRINT2((CE_WARN,
15413446Smrj 		    "agp_dealloc_mem: key=0x%x, auto unbind",
15423446Smrj 		    entryp->kte_key));
15433446Smrj 
15443446Smrj 		/*
15453446Smrj 		 * agp_dealloc_mem may be called indirectly by agp_detach.
15463446Smrj 		 * In the agp_detach function, agpgart_close is already
15473446Smrj 		 * called which will free the gart table. agp_unbind_key
15483446Smrj 		 * will panic if no valid gart table exists. So test if
15493446Smrj 		 * gart table exsits here.
15503446Smrj 		 */
15513446Smrj 		if (st->asoft_opened)
15524478Skz151634 			(void) agp_unbind_key(st, entryp);
15533446Smrj 	}
15543446Smrj 	if (entryp->kte_refcnt) {
15553446Smrj 		AGPDB_PRINT2((CE_WARN,
15563446Smrj 		    "agp_dealloc_pmem: memory is exported to users"));
15573446Smrj 		return (-1);
15583446Smrj 	}
15593446Smrj 
15603446Smrj 	switch (entryp->kte_type) {
15613446Smrj 	case AGP_NORMAL:
15623446Smrj 		agp_dealloc_pmem(entryp);
15633446Smrj 		break;
15643446Smrj 	case AGP_PHYSICAL:
15653446Smrj 		agp_dealloc_kmem(entryp);
15663446Smrj 		break;
15673446Smrj 	default:
15683446Smrj 		return (-1);
15693446Smrj 	}
15703446Smrj 
15713446Smrj 	return (0);
15723446Smrj }
15733446Smrj 
15743446Smrj /*
15753446Smrj  * agp_del_allkeys()
15763446Smrj  *
15773446Smrj  * Description:
15783446Smrj  * 	This function calls agp_dealloc_mem to release all the agp memory
15793446Smrj  *	resource allocated.
15803446Smrj  *
15813446Smrj  * Arguments:
15823446Smrj  * 	softsate	driver soft state pointer
15833446Smrj  * Returns:
15843446Smrj  * 	-1		can not free all agp memory
15853446Smrj  * 	0		success
15863446Smrj  *
15873446Smrj  */
15883446Smrj static int
15893446Smrj agp_del_allkeys(agpgart_softstate_t *softstate)
15903446Smrj {
15913446Smrj 	int key;
15923446Smrj 	int ret = 0;
15933446Smrj 
15943446Smrj 	ASSERT(softstate);
15953446Smrj 	for (key = 0; key < AGP_MAXKEYS; key++) {
15963446Smrj 		if (softstate->asoft_table[key].kte_memhdl != NULL) {
15973446Smrj 			/*
15983446Smrj 			 * Check if we can free agp memory now.
15993446Smrj 			 * If agp memory is exported to user
16003446Smrj 			 * applications, agp_dealloc_mem will fail.
16013446Smrj 			 */
16023446Smrj 			if (agp_dealloc_mem(softstate,
16033446Smrj 			    &softstate->asoft_table[key]))
16043446Smrj 				ret = -1;
16053446Smrj 		}
16063446Smrj 	}
16073446Smrj 
16083446Smrj 	return (ret);
16093446Smrj }
16103446Smrj 
16113446Smrj /*
16123446Smrj  * pfn2gartentry()
16133446Smrj  *
16143446Smrj  * Description:
16153446Smrj  *	This function converts a physical address to GART entry.
16163446Smrj  *	For AMD64, hardware only support addresses below 40bits,
16173446Smrj  *	about 1024G physical address, so the largest pfn
16183446Smrj  *	number is below 28 bits. Please refer to GART and GTT entry
16193446Smrj  *	format table in agpdefs.h for entry format. Intel IGD only
16203446Smrj  * 	only supports GTT entry below 1G. Intel AGP only supports
16213446Smrj  * 	GART entry below 4G.
16223446Smrj  *
16233446Smrj  * Arguments:
16243446Smrj  * 	arc_type		system agp arc type
16253446Smrj  * 	pfn			page frame number
16263446Smrj  * 	itemv			the entry item to be returned
16273446Smrj  * Returns:
16283446Smrj  * 	-1			not a invalid page frame
16293446Smrj  * 	0			conversion success
16303446Smrj  */
16313446Smrj static int
16323446Smrj pfn2gartentry(agp_arc_type_t arc_type, pfn_t pfn, uint32_t *itemv)
16333446Smrj {
16343446Smrj 	uint64_t paddr;
16353446Smrj 
16363446Smrj 	paddr = pfn<<AGP_PAGE_SHIFT;
16373446Smrj 
16383446Smrj 	switch (arc_type) {
16393446Smrj 	case ARC_INTELAGP:
16403446Smrj 	{
16413446Smrj 		/* Only support 32-bit hardware address */
16423446Smrj 		if ((paddr & ~AGP_INTEL_POINTER_MASK) != 0) {
16433446Smrj 			AGPDB_PRINT2((CE_WARN,
16443446Smrj 			    "INTEL AGP Hardware only support 32 bits"));
16453446Smrj 			return (-1);
16463446Smrj 		}
16473446Smrj 		*itemv =  (pfn << AGP_PAGE_SHIFT) | AGP_ENTRY_VALID;
16483446Smrj 
16493446Smrj 		break;
16503446Smrj 	}
16513446Smrj 	case ARC_AMD64NOAGP:
16523446Smrj 	case ARC_AMD64AGP:
16533446Smrj 	{
16543446Smrj 		uint32_t value1, value2;
16553446Smrj 		/* Physaddr should not exceed 40-bit */
16563446Smrj 		if ((paddr & ~AMD64_POINTER_MASK) != 0) {
16573446Smrj 			AGPDB_PRINT2((CE_WARN,
16583446Smrj 			    "AMD64 GART hardware only supoort 40 bits"));
16593446Smrj 			return (-1);
16603446Smrj 		}
16613446Smrj 		value1 = (uint32_t)pfn >> 20;
16623446Smrj 		value1 <<= 4;
16633446Smrj 		value2 = (uint32_t)pfn << 12;
16643446Smrj 
16653446Smrj 		*itemv = value1 | value2 | AMD64_ENTRY_VALID;
16663446Smrj 		break;
16673446Smrj 	}
16683446Smrj 	case ARC_IGD810:
16693446Smrj 		if ((paddr & ~I810_POINTER_MASK) != 0) {
16703446Smrj 			AGPDB_PRINT2((CE_WARN,
16713446Smrj 			    "Intel i810 only support 30 bits"));
16723446Smrj 			return (-1);
16733446Smrj 		}
16743446Smrj 		break;
16753446Smrj 
16763446Smrj 	case ARC_IGD830:
16773446Smrj 		if ((paddr & ~GTT_POINTER_MASK) != 0) {
16783446Smrj 			AGPDB_PRINT2((CE_WARN,
16793446Smrj 			    "Intel IGD only support 32 bits"));
16803446Smrj 			return (-1);
16813446Smrj 		}
16823446Smrj 		break;
16833446Smrj 	default:
16843446Smrj 		AGPDB_PRINT2((CE_WARN,
16853446Smrj 		    "pfn2gartentry: arc type = %d, not support", arc_type));
16863446Smrj 		return (-1);
16873446Smrj 	}
16883446Smrj 	return (0);
16893446Smrj }
16903446Smrj 
16913446Smrj /*
16923446Smrj  * Check allocated physical pages validity, only called in DEBUG
16933446Smrj  * mode.
16943446Smrj  */
16953446Smrj static int
16963446Smrj agp_check_pfns(agp_arc_type_t arc_type, pfn_t *pfnarray, int items)
16973446Smrj {
16983446Smrj 	int count;
16993446Smrj 	uint32_t ret;
17003446Smrj 
17013446Smrj 	for (count = 0; count < items; count++) {
17023446Smrj 		if (pfn2gartentry(arc_type, pfnarray[count], &ret))
17033446Smrj 			break;
17043446Smrj 	}
17053446Smrj 	if (count < items)
17063446Smrj 		return (-1);
17073446Smrj 	else
17083446Smrj 		return (0);
17093446Smrj }
17103446Smrj 
17113446Smrj /*
17123446Smrj  * kmem_getpfns()
17133446Smrj  *
17143446Smrj  * Description:
17153446Smrj  * 	This function gets page frame numbers from dma handle.
17163446Smrj  *
17173446Smrj  * Arguments:
17183446Smrj  * 	dma_handle		dma hanle allocated by ddi_dma_alloc_handle
17193446Smrj  * 	dma_cookip		dma cookie pointer
17203446Smrj  * 	cookies_num		cookies number
17213446Smrj  * 	pfnarray		array to store page frames
17223446Smrj  *
17233446Smrj  * Returns:
17243446Smrj  *	0		success
17253446Smrj  */
17263446Smrj static int
17273446Smrj kmem_getpfns(
17283446Smrj     ddi_dma_handle_t dma_handle,
17293446Smrj     ddi_dma_cookie_t *dma_cookiep,
17303446Smrj     int cookies_num,
17313446Smrj     pfn_t *pfnarray)
17323446Smrj {
17333446Smrj 	int	num_cookies;
17343446Smrj 	int	index = 0;
17353446Smrj 
17363446Smrj 	num_cookies = cookies_num;
17373446Smrj 
17383446Smrj 	while (num_cookies > 0) {
17393446Smrj 		uint64_t ck_startaddr, ck_length, ck_end;
17403446Smrj 		ck_startaddr = dma_cookiep->dmac_address;
17413446Smrj 		ck_length = dma_cookiep->dmac_size;
17423446Smrj 
17433446Smrj 		ck_end = ck_startaddr + ck_length;
17443446Smrj 		while (ck_startaddr < ck_end) {
17453446Smrj 			pfnarray[index] = (pfn_t)ck_startaddr >> AGP_PAGE_SHIFT;
17463446Smrj 			ck_startaddr += AGP_PAGE_SIZE;
17473446Smrj 			index++;
17483446Smrj 		}
17493446Smrj 
17503446Smrj 		num_cookies--;
17513446Smrj 		if (num_cookies > 0) {
17523446Smrj 			ddi_dma_nextcookie(dma_handle, dma_cookiep);
17533446Smrj 		}
17543446Smrj 	}
17553446Smrj 
17563446Smrj 	return (0);
17573446Smrj }
17583446Smrj 
17593446Smrj static int
17603446Smrj copyinfo(agpgart_softstate_t *softstate, agp_info_t *info)
17613446Smrj {
17623446Smrj 	switch (softstate->asoft_devreg.agprd_arctype) {
17633446Smrj 	case ARC_IGD810:
17643446Smrj 	case ARC_IGD830:
17653446Smrj 		info->agpi_version.agpv_major = 0;
17663446Smrj 		info->agpi_version.agpv_minor = 0;
17673446Smrj 		info->agpi_devid = softstate->asoft_info.agpki_mdevid;
17683446Smrj 		info->agpi_mode = 0;
17693446Smrj 		break;
17703446Smrj 	case ARC_INTELAGP:
17713446Smrj 	case ARC_AMD64AGP:
17723446Smrj 		info->agpi_version = softstate->asoft_info.agpki_tver;
17733446Smrj 		info->agpi_devid = softstate->asoft_info.agpki_tdevid;
17743446Smrj 		info->agpi_mode = softstate->asoft_info.agpki_tstatus;
17753446Smrj 		break;
17763446Smrj 	case ARC_AMD64NOAGP:
17773446Smrj 		break;
17783446Smrj 	default:
17793446Smrj 		AGPDB_PRINT2((CE_WARN, "copyinfo: UNKNOW ARC"));
17803446Smrj 		return (-1);
17813446Smrj 	}
17823446Smrj 	/*
17833446Smrj 	 * 64bit->32bit conversion possible
17843446Smrj 	 */
17853446Smrj 	info->agpi_aperbase = softstate->asoft_info.agpki_aperbase;
17863446Smrj 	info->agpi_apersize = softstate->asoft_info.agpki_apersize;
17873446Smrj 	info->agpi_pgtotal = softstate->asoft_pgtotal;
17883446Smrj 	info->agpi_pgsystem = info->agpi_pgtotal;
17893446Smrj 	info->agpi_pgused = softstate->asoft_pgused;
17903446Smrj 
17913446Smrj 	return (0);
17923446Smrj }
17933446Smrj 
17943446Smrj static uint32_t
17953446Smrj agp_v2_setup(uint32_t tstatus, uint32_t mstatus, uint32_t mode)
17963446Smrj {
17973446Smrj 	uint32_t cmd;
17983446Smrj 	int rq, sba, over4g, fw, rate;
17993446Smrj 
18003446Smrj 	/*
18013446Smrj 	 * tstatus: target device status
18023446Smrj 	 * mstatus: master device status
18033446Smrj 	 * mode: the agp mode to be sent
18043446Smrj 	 */
18053446Smrj 
18063446Smrj 	/*
18073446Smrj 	 * RQ - Request Queue size
18083446Smrj 	 * set RQ to the min of mode and tstatus
18093446Smrj 	 * if mode set a RQ larger than hardware can support,
18103446Smrj 	 * use the max RQ which hardware can support.
18113446Smrj 	 * tstatus & AGPSTAT_RQ_MASK is the max RQ hardware can support
18123446Smrj 	 * Corelogic will enqueue agp transaction
18133446Smrj 	 */
18143446Smrj 	rq = mode & AGPSTAT_RQ_MASK;
18153446Smrj 	if ((tstatus & AGPSTAT_RQ_MASK) < rq)
18163446Smrj 		rq = tstatus & AGPSTAT_RQ_MASK;
18173446Smrj 
18183446Smrj 	/*
18193446Smrj 	 * SBA - Sideband Addressing
18203446Smrj 	 *
18213446Smrj 	 * Sideband Addressing provides an additional bus to pass requests
18223446Smrj 	 * (address and command) to the target from the master.
18233446Smrj 	 *
18243446Smrj 	 * set SBA if all three support it
18253446Smrj 	 */
18263446Smrj 	sba = (tstatus & AGPSTAT_SBA) & (mstatus & AGPSTAT_SBA)
18274478Skz151634 	    & (mode & AGPSTAT_SBA);
18283446Smrj 
18293446Smrj 	/* set OVER4G  if all three support it */
18303446Smrj 	over4g = (tstatus & AGPSTAT_OVER4G) & (mstatus & AGPSTAT_OVER4G)
18314478Skz151634 	    & (mode & AGPSTAT_OVER4G);
18323446Smrj 
18333446Smrj 	/*
18343446Smrj 	 * FW - fast write
18353446Smrj 	 *
18363446Smrj 	 * acceleration of memory write transactions from the corelogic to the
18373446Smrj 	 * A.G.P. master device acting like a PCI target.
18383446Smrj 	 *
18393446Smrj 	 * set FW if all three support it
18403446Smrj 	 */
18413446Smrj 	fw = (tstatus & AGPSTAT_FW) & (mstatus & AGPSTAT_FW)
18424478Skz151634 	    & (mode & AGPSTAT_FW);
18433446Smrj 
18443446Smrj 	/*
18453446Smrj 	 * figure out the max rate
18463446Smrj 	 * AGP v2 support: 4X, 2X, 1X speed
18473446Smrj 	 * status bit		meaning
18483446Smrj 	 * ---------------------------------------------
18493446Smrj 	 * 7:3			others
18503446Smrj 	 * 3			0 stand for V2 support
18513446Smrj 	 * 0:2			001:1X, 010:2X, 100:4X
18523446Smrj 	 * ----------------------------------------------
18533446Smrj 	 */
18543446Smrj 	rate = (tstatus & AGPSTAT_RATE_MASK) & (mstatus & AGPSTAT_RATE_MASK)
18554478Skz151634 	    & (mode & AGPSTAT_RATE_MASK);
18563446Smrj 	if (rate & AGP2_RATE_4X)
18573446Smrj 		rate = AGP2_RATE_4X;
18583446Smrj 	else if (rate & AGP2_RATE_2X)
18593446Smrj 		rate = AGP2_RATE_2X;
18603446Smrj 	else
18613446Smrj 		rate = AGP2_RATE_1X;
18623446Smrj 
18633446Smrj 	cmd = rq | sba | over4g | fw | rate;
18643446Smrj 	/* enable agp mode */
18653446Smrj 	cmd |= AGPCMD_AGPEN;
18663446Smrj 
18673446Smrj 	return (cmd);
18683446Smrj }
18693446Smrj 
18703446Smrj static uint32_t
18713446Smrj agp_v3_setup(uint32_t tstatus, uint32_t mstatus, uint32_t mode)
18723446Smrj {
18733446Smrj 	uint32_t cmd = 0;
18743446Smrj 	uint32_t rq, arqsz, cal, sba, over4g, fw, rate;
18753446Smrj 
18763446Smrj 	/*
18773446Smrj 	 * tstatus: target device status
18783446Smrj 	 * mstatus: master device status
18793446Smrj 	 * mode: the agp mode to be set
18803446Smrj 	 */
18813446Smrj 
18823446Smrj 	/*
18833446Smrj 	 * RQ - Request Queue size
18843446Smrj 	 * Set RQ to the min of mode and tstatus
18853446Smrj 	 * If mode set a RQ larger than hardware can support,
18863446Smrj 	 * use the max RQ which hardware can support.
18873446Smrj 	 * tstatus & AGPSTAT_RQ_MASK is the max RQ hardware can support
18883446Smrj 	 * Corelogic will enqueue agp transaction;
18893446Smrj 	 */
18903446Smrj 	rq = mode & AGPSTAT_RQ_MASK;
18913446Smrj 	if ((tstatus & AGPSTAT_RQ_MASK) < rq)
18923446Smrj 		rq = tstatus & AGPSTAT_RQ_MASK;
18933446Smrj 
18943446Smrj 	/*
18953446Smrj 	 * ARQSZ - Asynchronous Request Queue size
18963446Smrj 	 * Set the value equal to tstatus.
18973446Smrj 	 * Don't allow the mode register to override values
18983446Smrj 	 */
18993446Smrj 	arqsz = tstatus & AGPSTAT_ARQSZ_MASK;
19003446Smrj 
19013446Smrj 	/*
19023446Smrj 	 * CAL - Calibration cycle
19033446Smrj 	 * Set to the min of tstatus and mstatus
19043446Smrj 	 * Don't allow override by mode register
19053446Smrj 	 */
19063446Smrj 	cal = tstatus & AGPSTAT_CAL_MASK;
19073446Smrj 	if ((mstatus & AGPSTAT_CAL_MASK) < cal)
19083446Smrj 		cal = mstatus & AGPSTAT_CAL_MASK;
19093446Smrj 
19103446Smrj 	/*
19113446Smrj 	 * SBA - Sideband Addressing
19123446Smrj 	 *
19133446Smrj 	 * Sideband Addressing provides an additional bus to pass requests
19143446Smrj 	 * (address and command) to the target from the master.
19153446Smrj 	 *
19163446Smrj 	 * SBA in agp v3.0 must be set
19173446Smrj 	 */
19183446Smrj 	sba = AGPCMD_SBAEN;
19193446Smrj 
19203446Smrj 	/* GART64B is not set since no hardware supports it now */
19213446Smrj 
19223446Smrj 	/* Set OVER4G if all three support it */
19233446Smrj 	over4g = (tstatus & AGPSTAT_OVER4G) & (mstatus & AGPSTAT_OVER4G)
19244478Skz151634 	    & (mode & AGPSTAT_OVER4G);
19253446Smrj 
19263446Smrj 	/*
19273446Smrj 	 * FW - fast write
19283446Smrj 	 *
19293446Smrj 	 * Acceleration of memory write transactions from the corelogic to the
19303446Smrj 	 * A.G.P. master device acting like a PCI target.
19313446Smrj 	 *
19323446Smrj 	 * Always set FW in AGP 3.0
19333446Smrj 	 */
19343446Smrj 	fw = (tstatus & AGPSTAT_FW) & (mstatus & AGPSTAT_FW)
19354478Skz151634 	    & (mode & AGPSTAT_FW);
19363446Smrj 
19373446Smrj 	/*
19383446Smrj 	 * Figure out the max rate
19393446Smrj 	 *
19403446Smrj 	 * AGP v3 support: 8X, 4X speed
19413446Smrj 	 *
19423446Smrj 	 * status bit		meaning
19433446Smrj 	 * ---------------------------------------------
19443446Smrj 	 * 7:3			others
19453446Smrj 	 * 3			1 stand for V3 support
19463446Smrj 	 * 0:2			001:4X, 010:8X, 011:4X,8X
19473446Smrj 	 * ----------------------------------------------
19483446Smrj 	 */
19493446Smrj 	rate = (tstatus & AGPSTAT_RATE_MASK) & (mstatus & AGPSTAT_RATE_MASK)
19504478Skz151634 	    & (mode & AGPSTAT_RATE_MASK);
19513446Smrj 	if (rate & AGP3_RATE_8X)
19523446Smrj 		rate = AGP3_RATE_8X;
19533446Smrj 	else
19543446Smrj 		rate = AGP3_RATE_4X;
19553446Smrj 
19563446Smrj 	cmd = rq | arqsz | cal | sba | over4g | fw | rate;
19573446Smrj 	/* Enable AGP mode */
19583446Smrj 	cmd |= AGPCMD_AGPEN;
19593446Smrj 
19603446Smrj 	return (cmd);
19613446Smrj }
19623446Smrj 
19633446Smrj static int
19643446Smrj agp_setup(agpgart_softstate_t *softstate, uint32_t mode)
19653446Smrj {
19663446Smrj 	uint32_t tstatus, mstatus;
19673446Smrj 	uint32_t agp_mode;
19683446Smrj 
19693446Smrj 	tstatus = softstate->asoft_info.agpki_tstatus;
19703446Smrj 	mstatus = softstate->asoft_info.agpki_mstatus;
19713446Smrj 
19723446Smrj 	/*
19733446Smrj 	 * There are three kinds of AGP mode. AGP mode 1.0, 2.0, 3.0
19743446Smrj 	 * AGP mode 2.0 is fully compatible with AGP mode 1.0, so we
19753446Smrj 	 * only check 2.0 and 3.0 mode. AGP 3.0 device can work in
19763446Smrj 	 * two AGP 2.0 or AGP 3.0 mode. By checking AGP status register,
19773446Smrj 	 * we can get which mode it is working at. The working mode of
19783446Smrj 	 * AGP master and AGP target must be consistent. That is, both
19793446Smrj 	 * of them must work on AGP 3.0 mode or AGP 2.0 mode.
19803446Smrj 	 */
19813446Smrj 	if ((softstate->asoft_info.agpki_tver.agpv_major == 3) &&
19823446Smrj 	    (tstatus & AGPSTAT_MODE3)) {
19833446Smrj 		/* Master device should be 3.0 mode, too */
19843446Smrj 		if ((softstate->asoft_info.agpki_mver.agpv_major != 3) ||
19853446Smrj 		    ((mstatus & AGPSTAT_MODE3) == 0))
19863446Smrj 			return (EIO);
19873446Smrj 
19883446Smrj 		agp_mode = agp_v3_setup(tstatus, mstatus, mode);
19893446Smrj 		/* Write to the AGPCMD register of target and master devices */
19903446Smrj 		if (lyr_set_agp_cmd(agp_mode,
19913446Smrj 		    &softstate->asoft_devreg))
19923446Smrj 			return (EIO);
19933446Smrj 
19943446Smrj 		softstate->asoft_mode = agp_mode;
19953446Smrj 
19963446Smrj 		return (0);
19973446Smrj 	}
19983446Smrj 
19993446Smrj 	/*
20003446Smrj 	 * If agp taget device doesn't work in AGP 3.0 mode,
20013446Smrj 	 * it must work in AGP 2.0 mode. And make sure
20023446Smrj 	 * master device work in AGP 2.0 mode too
20033446Smrj 	 */
20043446Smrj 	if ((softstate->asoft_info.agpki_mver.agpv_major == 3) &&
20053446Smrj 	    (mstatus & AGPSTAT_MODE3))
20063446Smrj 		return (EIO);
20073446Smrj 
20083446Smrj 	agp_mode = agp_v2_setup(tstatus, mstatus, mode);
20093446Smrj 	if (lyr_set_agp_cmd(agp_mode, &softstate->asoft_devreg))
20103446Smrj 		return (EIO);
20113446Smrj 	softstate->asoft_mode = agp_mode;
20123446Smrj 
20133446Smrj 	return (0);
20143446Smrj }
20153446Smrj 
20163446Smrj /*
20173446Smrj  * agp_alloc_pmem()
20183446Smrj  *
20193446Smrj  * Description:
20203446Smrj  * 	This function allocates physical memory for direct mapping to userland
20213446Smrj  * 	applications.
20223446Smrj  *
20233446Smrj  * Arguments:
20243446Smrj  * 	softsate	driver soft state pointer
20253446Smrj  * 	length		memory size
20263446Smrj  * 	type		AGP_NORMAL: normal agp memory, AGP_PHISYCAL: specical
20273446Smrj  *			memory type for intel i810 IGD
20283446Smrj  *
20293446Smrj  * Returns:
20303446Smrj  * 	entryp		new key table entity pointer
20313446Smrj  * 	NULL		no key table slot available
20323446Smrj  */
20333446Smrj static keytable_ent_t *
20343446Smrj agp_alloc_pmem(agpgart_softstate_t *softstate, size_t length, int type)
20353446Smrj {
20363446Smrj 	keytable_ent_t	keyentry;
20373446Smrj 	keytable_ent_t	*entryp;
20383446Smrj 
20393446Smrj 	ASSERT(AGP_ALIGNED(length));
20403446Smrj 	bzero(&keyentry, sizeof (keytable_ent_t));
20413446Smrj 
20423446Smrj 	keyentry.kte_pages = AGP_BYTES2PAGES(length);
20433446Smrj 	keyentry.kte_type = type;
20443446Smrj 
20453446Smrj 	keyentry.kte_memhdl =
20463446Smrj 	    (agp_pmem_handle_t *)kmem_zalloc(sizeof (agp_pmem_handle_t),
20473446Smrj 	    KM_SLEEP);
20483446Smrj 
20493446Smrj 	if (devmap_pmem_alloc(length,
20503446Smrj 	    PMEM_SLEEP,
20513446Smrj 	    &PMEMP(keyentry.kte_memhdl)->pmem_cookie) != DDI_SUCCESS)
20523446Smrj 		goto err1;
20533446Smrj 
20543446Smrj 	keyentry.kte_pfnarray = (pfn_t *)kmem_zalloc(sizeof (pfn_t) *
20553446Smrj 	    keyentry.kte_pages, KM_SLEEP);
20563446Smrj 
20573446Smrj 	if (devmap_pmem_getpfns(
20583446Smrj 	    PMEMP(keyentry.kte_memhdl)->pmem_cookie,
20593446Smrj 	    0, keyentry.kte_pages, keyentry.kte_pfnarray) != DDI_SUCCESS) {
20603446Smrj 		AGPDB_PRINT2((CE_WARN,
20613446Smrj 		    "agp_alloc_pmem: devmap_map_getpfns failed"));
20623446Smrj 		goto err2;
20633446Smrj 	}
20643446Smrj 	ASSERT(!agp_check_pfns(softstate->asoft_devreg.agprd_arctype,
20653446Smrj 	    keyentry.kte_pfnarray, keyentry.kte_pages));
20663446Smrj 	entryp = agp_fill_empty_keyent(softstate, &keyentry);
20673446Smrj 
20683446Smrj 	if (!entryp) {
20693446Smrj 		AGPDB_PRINT2((CE_WARN,
20703446Smrj 		    "agp_alloc_pmem: agp_fill_empty_keyent error"));
20713446Smrj 		goto err2;
20723446Smrj 	}
20733446Smrj 	ASSERT((entryp->kte_key >= 0) && (entryp->kte_key < AGP_MAXKEYS));
20743446Smrj 
20753446Smrj 	return (entryp);
20763446Smrj 
20773446Smrj err2:
20783446Smrj 	kmem_free(keyentry.kte_pfnarray, sizeof (pfn_t) * keyentry.kte_pages);
20793446Smrj 	keyentry.kte_pfnarray = NULL;
20803446Smrj 	devmap_pmem_free(PMEMP(keyentry.kte_memhdl)->pmem_cookie);
20813446Smrj 	PMEMP(keyentry.kte_memhdl)->pmem_cookie = NULL;
20823446Smrj err1:
20833446Smrj 	kmem_free(keyentry.kte_memhdl, sizeof (agp_pmem_handle_t));
20843446Smrj 	keyentry.kte_memhdl = NULL;
20853446Smrj 
20863446Smrj 	return (NULL);
20873446Smrj 
20883446Smrj }
20893446Smrj 
20903446Smrj /*
20913446Smrj  * agp_alloc_kmem()
20923446Smrj  *
20933446Smrj  * Description:
20943446Smrj  * 	This function allocates physical memory for userland applications
20953446Smrj  * 	by ddi interfaces. This function can only be called to allocate
20963446Smrj  *	small phsyical contiguous pages, usually tens of kilobytes.
20973446Smrj  *
20983446Smrj  * Arguments:
20993446Smrj  * 	softsate	driver soft state pointer
21003446Smrj  * 	length		memory size
21013446Smrj  *
21023446Smrj  * Returns:
21033446Smrj  * 	entryp		new keytable entity pointer
21043446Smrj  * 	NULL		no keytable slot available or no physical
21053446Smrj  *			memory available
21063446Smrj  */
21073446Smrj static keytable_ent_t *
21083446Smrj agp_alloc_kmem(agpgart_softstate_t *softstate, size_t length)
21093446Smrj {
21103446Smrj 	keytable_ent_t	keyentry;
21113446Smrj 	keytable_ent_t	*entryp;
21123446Smrj 	int		ret;
21133446Smrj 
21143446Smrj 	ASSERT(AGP_ALIGNED(length));
21153446Smrj 
21163446Smrj 	bzero(&keyentry, sizeof (keytable_ent_t));
21173446Smrj 
21183446Smrj 	keyentry.kte_pages = AGP_BYTES2PAGES(length);
21193446Smrj 	keyentry.kte_type = AGP_PHYSICAL;
21203446Smrj 
21213446Smrj 	/*
21223446Smrj 	 * Set dma_attr_sgllen to assure contiguous physical pages
21233446Smrj 	 */
21243446Smrj 	agpgart_dma_attr.dma_attr_sgllen = 1;
21253446Smrj 
21263446Smrj 	/* 4k size pages */
21273446Smrj 	keyentry.kte_memhdl = kmem_zalloc(sizeof (agp_kmem_handle_t), KM_SLEEP);
21283446Smrj 
21293446Smrj 	if (ddi_dma_alloc_handle(softstate->asoft_dip,
21303446Smrj 	    &agpgart_dma_attr,
21313446Smrj 	    DDI_DMA_SLEEP, NULL,
21323446Smrj 	    &(KMEMP(keyentry.kte_memhdl)->kmem_handle))) {
21333446Smrj 		AGPDB_PRINT2((CE_WARN,
21343446Smrj 		    "agp_alloc_kmem: ddi_dma_allco_hanlde error"));
21353446Smrj 		goto err4;
21363446Smrj 	}
21373446Smrj 
21383446Smrj 	if ((ret = ddi_dma_mem_alloc(
21393446Smrj 	    KMEMP(keyentry.kte_memhdl)->kmem_handle,
21403446Smrj 	    length,
21413446Smrj 	    &gart_dev_acc_attr,
21423446Smrj 	    DDI_DMA_CONSISTENT,
21433446Smrj 	    DDI_DMA_SLEEP, NULL,
21443446Smrj 	    &KMEMP(keyentry.kte_memhdl)->kmem_kvaddr,
21453446Smrj 	    &KMEMP(keyentry.kte_memhdl)->kmem_reallen,
21463446Smrj 	    &KMEMP(keyentry.kte_memhdl)->kmem_acchdl)) != 0) {
21473446Smrj 		AGPDB_PRINT2((CE_WARN,
21483446Smrj 		    "agp_alloc_kmem: ddi_dma_mem_alloc error"));
21493446Smrj 
21503446Smrj 		goto err3;
21513446Smrj 	}
21523446Smrj 
21533446Smrj 	ret = ddi_dma_addr_bind_handle(
21543446Smrj 	    KMEMP(keyentry.kte_memhdl)->kmem_handle,
21553446Smrj 	    NULL,
21563446Smrj 	    KMEMP(keyentry.kte_memhdl)->kmem_kvaddr,
21573446Smrj 	    length,
21583446Smrj 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
21593446Smrj 	    DDI_DMA_SLEEP,
21603446Smrj 	    NULL,
21613446Smrj 	    &KMEMP(keyentry.kte_memhdl)->kmem_dcookie,
21623446Smrj 	    &KMEMP(keyentry.kte_memhdl)->kmem_cookies_num);
21633446Smrj 
21643446Smrj 	/*
21653446Smrj 	 * Even dma_attr_sgllen = 1, ddi_dma_addr_bind_handle may return more
21663446Smrj 	 * than one cookie, we check this in the if statement.
21673446Smrj 	 */
21683446Smrj 
21693446Smrj 	if ((ret != DDI_DMA_MAPPED) ||
21703446Smrj 	    (KMEMP(keyentry.kte_memhdl)->kmem_cookies_num != 1)) {
21713446Smrj 		AGPDB_PRINT2((CE_WARN,
21723446Smrj 		    "agp_alloc_kmem: can not alloc physical memory properly"));
21733446Smrj 		goto err2;
21743446Smrj 	}
21753446Smrj 
21763446Smrj 	keyentry.kte_pfnarray = (pfn_t *)kmem_zalloc(sizeof (pfn_t) *
21773446Smrj 	    keyentry.kte_pages, KM_SLEEP);
21783446Smrj 
21793446Smrj 	if (kmem_getpfns(
21803446Smrj 	    KMEMP(keyentry.kte_memhdl)->kmem_handle,
21813446Smrj 	    &KMEMP(keyentry.kte_memhdl)->kmem_dcookie,
21823446Smrj 	    KMEMP(keyentry.kte_memhdl)->kmem_cookies_num,
21833446Smrj 	    keyentry.kte_pfnarray)) {
21843446Smrj 		AGPDB_PRINT2((CE_WARN, "agp_alloc_kmem: get pfn array error"));
21853446Smrj 		goto err1;
21863446Smrj 	}
21873446Smrj 
21883446Smrj 	ASSERT(!agp_check_pfns(softstate->asoft_devreg.agprd_arctype,
21893446Smrj 	    keyentry.kte_pfnarray, keyentry.kte_pages));
21903446Smrj 	entryp = agp_fill_empty_keyent(softstate, &keyentry);
21913446Smrj 	if (!entryp) {
21923446Smrj 		AGPDB_PRINT2((CE_WARN,
21933446Smrj 		    "agp_alloc_kmem: agp_fill_empty_keyent error"));
21943446Smrj 
21953446Smrj 		goto err1;
21963446Smrj 	}
21973446Smrj 	ASSERT((entryp->kte_key >= 0) && (entryp->kte_key < AGP_MAXKEYS));
21983446Smrj 
21993446Smrj 	return (entryp);
22003446Smrj 
22013446Smrj err1:
22023446Smrj 	kmem_free(keyentry.kte_pfnarray, sizeof (pfn_t) * keyentry.kte_pages);
22033446Smrj 	keyentry.kte_pfnarray = NULL;
22043446Smrj 	(void) ddi_dma_unbind_handle(KMEMP(keyentry.kte_memhdl)->kmem_handle);
22053446Smrj 	KMEMP(keyentry.kte_memhdl)->kmem_cookies_num = 0;
22063446Smrj err2:
22073446Smrj 	ddi_dma_mem_free(&KMEMP(keyentry.kte_memhdl)->kmem_acchdl);
22083446Smrj 	KMEMP(keyentry.kte_memhdl)->kmem_acchdl = NULL;
22093446Smrj 	KMEMP(keyentry.kte_memhdl)->kmem_reallen = 0;
22103446Smrj 	KMEMP(keyentry.kte_memhdl)->kmem_kvaddr = NULL;
22113446Smrj err3:
22123446Smrj 	ddi_dma_free_handle(&(KMEMP(keyentry.kte_memhdl)->kmem_handle));
22133446Smrj 	KMEMP(keyentry.kte_memhdl)->kmem_handle = NULL;
22143446Smrj err4:
22153446Smrj 	kmem_free(keyentry.kte_memhdl, sizeof (agp_kmem_handle_t));
22163446Smrj 	keyentry.kte_memhdl = NULL;
22173446Smrj 	return (NULL);
22183446Smrj 
22193446Smrj }
22203446Smrj 
22213446Smrj /*
22223446Smrj  * agp_alloc_mem()
22233446Smrj  *
22243446Smrj  * Description:
22253446Smrj  * 	This function allocate physical memory for userland applications,
22263446Smrj  * 	in order to save kernel virtual space, we use the direct mapping
22273446Smrj  * 	memory interface if it is available.
22283446Smrj  *
22293446Smrj  * Arguments:
22303446Smrj  * 	st		driver soft state pointer
22313446Smrj  * 	length		memory size
22323446Smrj  * 	type		AGP_NORMAL: normal agp memory, AGP_PHISYCAL: specical
22333446Smrj  *			memory type for intel i810 IGD
22343446Smrj  *
22353446Smrj  * Returns:
22363446Smrj  * 	NULL 	Invalid memory type or can not allocate memory
22373446Smrj  * 	Keytable entry pointer returned by agp_alloc_kmem or agp_alloc_pmem
22383446Smrj  */
22393446Smrj static keytable_ent_t *
22403446Smrj agp_alloc_mem(agpgart_softstate_t *st, size_t length, int type)
22413446Smrj {
22423446Smrj 
22433446Smrj 	/*
22443446Smrj 	 * AGP_PHYSICAL type require contiguous physical pages exported
22453446Smrj 	 * to X drivers, like i810 HW cursor, ARGB cursor. the number of
22463446Smrj 	 * pages needed is usuallysmall and contiguous, 4K, 16K. So we
22473446Smrj 	 * use DDI interface to allocated such memory. And X use xsvc
22483446Smrj 	 * drivers to map this memory into its own address space.
22493446Smrj 	 */
22503446Smrj 	ASSERT(st);
22513446Smrj 
22523446Smrj 	switch (type) {
22533446Smrj 	case AGP_NORMAL:
22543446Smrj 		return (agp_alloc_pmem(st, length, type));
22553446Smrj 	case AGP_PHYSICAL:
22563446Smrj 		return (agp_alloc_kmem(st, length));
22573446Smrj 	default:
22583446Smrj 		return (NULL);
22593446Smrj 	}
22603446Smrj }
22613446Smrj 
22623446Smrj /*
22633446Smrj  * free_gart_table()
22643446Smrj  *
22653446Smrj  * Description:
22663446Smrj  * 	This function frees the gart table memory allocated by driver.
22673446Smrj  * 	Must disable gart table before calling this function.
22683446Smrj  *
22693446Smrj  * Arguments:
22703446Smrj  * 	softstate		driver soft state pointer
22713446Smrj  *
22723446Smrj  */
22733446Smrj static void
22743446Smrj free_gart_table(agpgart_softstate_t *st)
22753446Smrj {
22763446Smrj 
22773446Smrj 	if (st->gart_dma_handle == NULL)
22783446Smrj 		return;
22793446Smrj 
22803446Smrj 	(void) ddi_dma_unbind_handle(st->gart_dma_handle);
22813446Smrj 	ddi_dma_mem_free(&st->gart_dma_acc_handle);
22823446Smrj 	st->gart_dma_acc_handle = NULL;
22833446Smrj 	ddi_dma_free_handle(&st->gart_dma_handle);
22843446Smrj 	st->gart_dma_handle = NULL;
22853446Smrj 	st->gart_vbase = 0;
22863446Smrj 	st->gart_size = 0;
22873446Smrj }
22883446Smrj 
22893446Smrj /*
22903446Smrj  * alloc_gart_table()
22913446Smrj  *
22923446Smrj  * Description:
22933446Smrj  * 	This function allocates one physical continuous gart table.
22943446Smrj  * 	INTEL integrated video device except i810 have their special
22953446Smrj  * 	video bios; No need to allocate gart table for them.
22963446Smrj  *
22973446Smrj  * Arguments:
22983446Smrj  * 	st		driver soft state pointer
22993446Smrj  *
23003446Smrj  * Returns:
23013446Smrj  * 	0		success
23023446Smrj  * 	-1		can not allocate gart tabl
23033446Smrj  */
23043446Smrj static int
23053446Smrj alloc_gart_table(agpgart_softstate_t *st)
23063446Smrj {
23073446Smrj 	int			num_pages;
23083446Smrj 	size_t			table_size;
23093446Smrj 	int			ret = DDI_SUCCESS;
23103446Smrj 	ddi_dma_cookie_t	cookie;
23113446Smrj 	uint32_t		num_cookies;
23123446Smrj 
23133446Smrj 	num_pages = AGP_MB2PAGES(st->asoft_info.agpki_apersize);
23143446Smrj 
23153446Smrj 	/*
23163446Smrj 	 * Only 40-bit maximum physical memory is supported by today's
23173446Smrj 	 * AGP hardware (32-bit gart tables can hold 40-bit memory addresses).
23183446Smrj 	 * No one supports 64-bit gart entries now, so the size of gart
23193446Smrj 	 * entries defaults to 32-bit though AGP3.0 specifies the possibility
23203446Smrj 	 * of 64-bit gart entries.
23213446Smrj 	 */
23223446Smrj 
23233446Smrj 	table_size = num_pages * (sizeof (uint32_t));
23243446Smrj 
23253446Smrj 	/*
23263446Smrj 	 * Only AMD64 can put gart table above 4G, 40 bits at maximum
23273446Smrj 	 */
23283446Smrj 	if ((st->asoft_devreg.agprd_arctype == ARC_AMD64AGP) ||
23293446Smrj 	    (st->asoft_devreg.agprd_arctype == ARC_AMD64NOAGP))
23303446Smrj 		garttable_dma_attr.dma_attr_addr_hi = 0xffffffffffLL;
23313446Smrj 	else
23323446Smrj 		garttable_dma_attr.dma_attr_addr_hi = 0xffffffffU;
23333446Smrj 	/* Allocate physical continuous page frame for gart table */
23343446Smrj 	if (ret = ddi_dma_alloc_handle(st->asoft_dip,
23353446Smrj 	    &garttable_dma_attr,
23363446Smrj 	    DDI_DMA_SLEEP,
23373446Smrj 	    NULL, &st->gart_dma_handle)) {
23383446Smrj 		AGPDB_PRINT2((CE_WARN,
23393446Smrj 		    "alloc_gart_table: ddi_dma_alloc_handle failed"));
23403446Smrj 		goto err3;
23413446Smrj 	}
23423446Smrj 
23433446Smrj 	if (ret = ddi_dma_mem_alloc(st->gart_dma_handle,
23444478Skz151634 	    table_size,
23454478Skz151634 	    &gart_dev_acc_attr,
23464478Skz151634 	    DDI_DMA_CONSISTENT,
23474478Skz151634 	    DDI_DMA_SLEEP, NULL,
23484478Skz151634 	    &st->gart_vbase,
23494478Skz151634 	    &st->gart_size,
23504478Skz151634 	    &st->gart_dma_acc_handle)) {
23513446Smrj 		AGPDB_PRINT2((CE_WARN,
23523446Smrj 		    "alloc_gart_table: ddi_dma_mem_alloc failed"));
23533446Smrj 		goto err2;
23543446Smrj 
23553446Smrj 	}
23563446Smrj 
23573446Smrj 	ret = ddi_dma_addr_bind_handle(st->gart_dma_handle,
23584478Skz151634 	    NULL, st->gart_vbase,
23594478Skz151634 	    table_size,
23604478Skz151634 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
23614478Skz151634 	    DDI_DMA_SLEEP, NULL,
23624478Skz151634 	    &cookie,  &num_cookies);
23633446Smrj 
23643446Smrj 	st->gart_pbase = cookie.dmac_address;
23653446Smrj 
23663446Smrj 	if ((ret != DDI_DMA_MAPPED) || (num_cookies != 1)) {
23673446Smrj 		if (num_cookies > 1)
23683446Smrj 			(void) ddi_dma_unbind_handle(st->gart_dma_handle);
23693446Smrj 		AGPDB_PRINT2((CE_WARN,
23703446Smrj 		    "alloc_gart_table: alloc contiguous phys memory failed"));
23713446Smrj 		goto err1;
23723446Smrj 	}
23733446Smrj 
23743446Smrj 	return (0);
23753446Smrj err1:
23763446Smrj 	ddi_dma_mem_free(&st->gart_dma_acc_handle);
23773446Smrj 	st->gart_dma_acc_handle = NULL;
23783446Smrj err2:
23793446Smrj 	ddi_dma_free_handle(&st->gart_dma_handle);
23803446Smrj 	st->gart_dma_handle = NULL;
23813446Smrj err3:
23823446Smrj 	st->gart_pbase = 0;
23833446Smrj 	st->gart_size = 0;
23843446Smrj 	st->gart_vbase = 0;
23853446Smrj 
23863446Smrj 	return (-1);
23873446Smrj }
23883446Smrj 
23893446Smrj /*
23903446Smrj  * agp_add_to_gart()
23913446Smrj  *
23923446Smrj  * Description:
23933446Smrj  * 	This function fills the gart table entries by a given page frame number
23943446Smrj  * 	array and set up the agp aperture page to physical memory page
23953446Smrj  * 	translation.
23963446Smrj  * Arguments:
23973446Smrj  * 	type		valid sytem arc types ARC_AMD64AGP, ARC_INTELAGP,
23983446Smrj  * 			ARC_AMD64AGP
23993446Smrj  * 	pfnarray	allocated physical page frame number array
24003446Smrj  * 	pg_offset	agp aperture start page to be bound
24013446Smrj  * 	entries		the number of pages to be bound
24023446Smrj  * 	dma_hdl		gart table dma memory handle
24033446Smrj  * 	tablep		gart table kernel virtual address
24043446Smrj  * Returns:
24053446Smrj  * 	-1		failed
24063446Smrj  * 	0		success
24073446Smrj  */
24083446Smrj static int
24093446Smrj agp_add_to_gart(
24103446Smrj     agp_arc_type_t type,
24113446Smrj     pfn_t *pfnarray,
24123446Smrj     uint32_t pg_offset,
24133446Smrj     uint32_t entries,
24143446Smrj     ddi_dma_handle_t dma_hdl,
24153446Smrj     uint32_t *tablep)
24163446Smrj {
24173446Smrj 	int items = 0;
24183446Smrj 	uint32_t *entryp;
24193446Smrj 	uint32_t itemv;
24203446Smrj 
24213446Smrj 	entryp = tablep + pg_offset;
24223446Smrj 	while (items < entries) {
24233446Smrj 		if (pfn2gartentry(type, pfnarray[items], &itemv))
24243446Smrj 			break;
24253446Smrj 		*(entryp + items) = itemv;
24263446Smrj 		items++;
24273446Smrj 	}
24283446Smrj 	if (items < entries)
24293446Smrj 		return (-1);
24303446Smrj 
24313446Smrj 	(void) ddi_dma_sync(dma_hdl, pg_offset * sizeof (uint32_t),
24323446Smrj 	    entries * sizeof (uint32_t), DDI_DMA_SYNC_FORDEV);
24333446Smrj 
24343446Smrj 	return (0);
24353446Smrj }
24363446Smrj 
24373446Smrj /*
24383446Smrj  * agp_bind_key()
24393446Smrj  *
24403446Smrj  * Description:
24413446Smrj  * 	This function will call low level gart table access functions to
24423446Smrj  * 	set up gart table translation. Also it will do some sanity
24433446Smrj  * 	checking on key table entry.
24443446Smrj  *
24453446Smrj  * Arguments:
24463446Smrj  * 	softstate		driver soft state pointer
24473446Smrj  * 	keyent			key table entity pointer to be bound
24483446Smrj  * 	pg_offset		aperture start page to be bound
24493446Smrj  * Returns:
24503446Smrj  * 	EINVAL			not a valid operation
24513446Smrj  */
24523446Smrj static int
24533446Smrj agp_bind_key(agpgart_softstate_t *softstate,
24543446Smrj     keytable_ent_t  *keyent, uint32_t  pg_offset)
24553446Smrj {
24563446Smrj 	uint64_t pg_end;
24573446Smrj 	int ret = 0;
24583446Smrj 
24593446Smrj 	ASSERT(keyent);
24603446Smrj 	ASSERT((keyent->kte_key >= 0) && (keyent->kte_key < AGP_MAXKEYS));
24613446Smrj 	ASSERT(mutex_owned(&softstate->asoft_instmutex));
24623446Smrj 
24633446Smrj 	pg_end = pg_offset + keyent->kte_pages;
24643446Smrj 
24653446Smrj 	if (pg_end > AGP_MB2PAGES(softstate->asoft_info.agpki_apersize)) {
24663446Smrj 		AGPDB_PRINT2((CE_WARN,
24673446Smrj 		    "agp_bind_key: key=0x%x,exceed aper range",
24683446Smrj 		    keyent->kte_key));
24693446Smrj 
24703446Smrj 		return (EINVAL);
24713446Smrj 	}
24723446Smrj 
24733446Smrj 	if (agp_check_off(softstate->asoft_table,
24743446Smrj 	    pg_offset, keyent->kte_pages)) {
24753446Smrj 		AGPDB_PRINT2((CE_WARN,
24763446Smrj 		    "agp_bind_key: pg_offset=0x%x, pages=0x%lx overlaped",
24773446Smrj 		    pg_offset, keyent->kte_pages));
24783446Smrj 		return (EINVAL);
24793446Smrj 	}
24803446Smrj 
24813446Smrj 	ASSERT(keyent->kte_pfnarray != NULL);
24823446Smrj 
24833446Smrj 	switch (softstate->asoft_devreg.agprd_arctype) {
24843446Smrj 	case ARC_IGD810:
24853446Smrj 	case ARC_IGD830:
24863446Smrj 		ret = lyr_i8xx_add_to_gtt(pg_offset, keyent,
24873446Smrj 		    &softstate->asoft_devreg);
24883446Smrj 		if (ret)
24893446Smrj 			return (EIO);
24903446Smrj 		break;
24913446Smrj 	case ARC_INTELAGP:
24923446Smrj 	case ARC_AMD64NOAGP:
24933446Smrj 	case ARC_AMD64AGP:
24943446Smrj 		ret =  agp_add_to_gart(
24953446Smrj 		    softstate->asoft_devreg.agprd_arctype,
24963446Smrj 		    keyent->kte_pfnarray,
24973446Smrj 		    pg_offset,
24983446Smrj 		    keyent->kte_pages,
24993446Smrj 		    softstate->gart_dma_handle,
25003446Smrj 		    (uint32_t *)softstate->gart_vbase);
25013446Smrj 		if (ret)
25023446Smrj 			return (EINVAL);
25033446Smrj 		/* Flush GTLB table */
25043446Smrj 		lyr_flush_gart_cache(&softstate->asoft_devreg);
25053446Smrj 		break;
25063446Smrj 	default:
25073446Smrj 		AGPDB_PRINT2((CE_WARN,
25083446Smrj 		    "agp_bind_key: arc type = 0x%x unsupported",
25093446Smrj 		    softstate->asoft_devreg.agprd_arctype));
25103446Smrj 		return (EINVAL);
25113446Smrj 	}
25123446Smrj 	return (0);
25133446Smrj }
25143446Smrj 
25153446Smrj static int
25163446Smrj agpgart_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
25173446Smrj {
25183446Smrj 	int instance;
25193446Smrj 	agpgart_softstate_t *softstate;
25203446Smrj 
25213446Smrj 	if (cmd != DDI_ATTACH) {
25223446Smrj 		AGPDB_PRINT2((CE_WARN,
25233446Smrj 		    "agpgart_attach: only attach op supported"));
25243446Smrj 		return (DDI_FAILURE);
25253446Smrj 	}
25263446Smrj 	instance = ddi_get_instance(dip);
25273446Smrj 
25283446Smrj 	if (ddi_soft_state_zalloc(agpgart_glob_soft_handle, instance)
25294478Skz151634 	    != DDI_SUCCESS) {
25303446Smrj 		AGPDB_PRINT2((CE_WARN,
25313446Smrj 		    "agpgart_attach: soft state zalloc failed"));
25323446Smrj 		goto err1;
25333446Smrj 
25343446Smrj 	}
25353446Smrj 	softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
25363446Smrj 	mutex_init(&softstate->asoft_instmutex, NULL, MUTEX_DRIVER, NULL);
25373446Smrj 	softstate->asoft_dip = dip;
25383446Smrj 	/*
25393446Smrj 	 * Allocate LDI identifier for agpgart driver
25403446Smrj 	 * Agpgart driver is the kernel consumer
25413446Smrj 	 */
25423446Smrj 	if (ldi_ident_from_dip(dip, &softstate->asoft_li)) {
25433446Smrj 		AGPDB_PRINT2((CE_WARN,
25443446Smrj 		    "agpgart_attach: LDI indentifier allcation failed"));
25453446Smrj 		goto err2;
25463446Smrj 	}
25473446Smrj 
25483446Smrj 	softstate->asoft_devreg.agprd_arctype = ARC_UNKNOWN;
25493446Smrj 	/* Install agp kstat */
25503446Smrj 	if (agp_init_kstats(softstate)) {
25513446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_attach: init kstats error"));
25523446Smrj 		goto err3;
25533446Smrj 	}
25543446Smrj 	/*
25553446Smrj 	 * devfs will create /dev/agpgart
25563446Smrj 	 * and  /devices/agpgart:agpgart
25573446Smrj 	 */
25583446Smrj 
25593446Smrj 	if (ddi_create_minor_node(dip, AGPGART_DEVNODE, S_IFCHR,
25603446Smrj 	    AGP_INST2MINOR(instance),
25613446Smrj 	    DDI_NT_AGP_PSEUDO, 0)) {
25623446Smrj 		AGPDB_PRINT2((CE_WARN,
25633446Smrj 		    "agpgart_attach: Can not create minor node"));
25643446Smrj 		goto err4;
25653446Smrj 	}
25663446Smrj 
25673446Smrj 	softstate->asoft_table = kmem_zalloc(
25684478Skz151634 	    AGP_MAXKEYS * (sizeof (keytable_ent_t)),
25694478Skz151634 	    KM_SLEEP);
25703446Smrj 
25713446Smrj 	return (DDI_SUCCESS);
25723446Smrj err4:
25733446Smrj 	agp_fini_kstats(softstate);
25743446Smrj err3:
25753446Smrj 	ldi_ident_release(softstate->asoft_li);
25763446Smrj err2:
25773446Smrj 	ddi_soft_state_free(agpgart_glob_soft_handle, instance);
25783446Smrj err1:
25793446Smrj 	return (DDI_FAILURE);
25803446Smrj }
25813446Smrj 
25823446Smrj static int
25833446Smrj agpgart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
25843446Smrj {
25853446Smrj 	int instance;
25863446Smrj 	agpgart_softstate_t *st;
25873446Smrj 
25883446Smrj 	instance = ddi_get_instance(dip);
25893446Smrj 
25903446Smrj 	st = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
25913446Smrj 
25923446Smrj 	if (cmd != DDI_DETACH)
25933446Smrj 		return (DDI_FAILURE);
25943446Smrj 
25953446Smrj 	/*
25963446Smrj 	 * Caller should free all the memory allocated explicitly.
25973446Smrj 	 * We release the memory allocated by caller which is not
25983446Smrj 	 * properly freed. mutex_enter here make sure assertion on
25993446Smrj 	 * softstate mutex success in agp_dealloc_mem.
26003446Smrj 	 */
26013446Smrj 	mutex_enter(&st->asoft_instmutex);
26023446Smrj 	if (agp_del_allkeys(st)) {
26033446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_detach: agp_del_allkeys err"));
26043446Smrj 		AGPDB_PRINT2((CE_WARN,
26053446Smrj 		    "you might free agp memory exported to your applications"));
26063446Smrj 
26073446Smrj 		mutex_exit(&st->asoft_instmutex);
26083446Smrj 		return (DDI_FAILURE);
26093446Smrj 	}
26103446Smrj 	mutex_exit(&st->asoft_instmutex);
26113446Smrj 	if (st->asoft_table) {
26123446Smrj 		kmem_free(st->asoft_table,
26133446Smrj 		    AGP_MAXKEYS * (sizeof (keytable_ent_t)));
26143446Smrj 		st->asoft_table = 0;
26153446Smrj 	}
26163446Smrj 
26173446Smrj 	ddi_remove_minor_node(dip, AGPGART_DEVNODE);
26183446Smrj 	agp_fini_kstats(st);
26193446Smrj 	ldi_ident_release(st->asoft_li);
26203446Smrj 	mutex_destroy(&st->asoft_instmutex);
26213446Smrj 	ddi_soft_state_free(agpgart_glob_soft_handle, instance);
26223446Smrj 
26233446Smrj 	return (DDI_SUCCESS);
26243446Smrj }
26253446Smrj 
26263446Smrj /*ARGSUSED*/
26273446Smrj static int
26283446Smrj agpgart_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
26293446Smrj     void **resultp)
26303446Smrj {
26313446Smrj 	agpgart_softstate_t *st;
26323446Smrj 	int instance, rval = DDI_FAILURE;
26333446Smrj 	dev_t dev;
26343446Smrj 
26353446Smrj 	switch (cmd) {
26363446Smrj 	case DDI_INFO_DEVT2DEVINFO:
26373446Smrj 		dev = (dev_t)arg;
26383446Smrj 		instance = AGP_DEV2INST(dev);
26393446Smrj 		st = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
26403446Smrj 		if (st != NULL) {
26413446Smrj 			mutex_enter(&st->asoft_instmutex);
26423446Smrj 			*resultp = st->asoft_dip;
26433446Smrj 			mutex_exit(&st->asoft_instmutex);
26443446Smrj 			rval = DDI_SUCCESS;
26453446Smrj 		} else
26463446Smrj 			*resultp = NULL;
26473446Smrj 
26483446Smrj 		break;
26493446Smrj 	case DDI_INFO_DEVT2INSTANCE:
26503446Smrj 		dev = (dev_t)arg;
26513446Smrj 		instance = AGP_DEV2INST(dev);
26523446Smrj 		*resultp = (void *)(uintptr_t)instance;
26533446Smrj 		rval = DDI_SUCCESS;
26543446Smrj 
26553446Smrj 		break;
26563446Smrj 	default:
26573446Smrj 		break;
26583446Smrj 	}
26593446Smrj 
26603446Smrj 	return (rval);
26613446Smrj }
26623446Smrj 
26633446Smrj /*
26643446Smrj  * agpgart_open()
26653446Smrj  *
26663446Smrj  * Description:
26673446Smrj  * 	This function is the driver open entry point. If it is the
26683446Smrj  * 	first time the agpgart driver is opened, the driver will
26693446Smrj  * 	open other agp related layered drivers and set up the agpgart
26703446Smrj  * 	table properly.
26713446Smrj  *
26723446Smrj  * Arguments:
26733446Smrj  * 	dev			device number pointer
26743446Smrj  * 	openflags		open flags
26753446Smrj  *	otyp			OTYP_BLK, OTYP_CHR
26763446Smrj  * 	credp			user's credential's struct pointer
26773446Smrj  *
26783446Smrj  * Returns:
26793446Smrj  * 	ENXIO			operation error
26803446Smrj  * 	EAGAIN			resoure temporarily unvailable
26813446Smrj  * 	0			success
26823446Smrj  */
26833446Smrj /*ARGSUSED*/
26843446Smrj static int
26853446Smrj agpgart_open(dev_t *dev, int openflags, int otyp, cred_t *credp)
26863446Smrj {
26873446Smrj 	int instance = AGP_DEV2INST(*dev);
26883446Smrj 	agpgart_softstate_t *softstate;
26893446Smrj 	int rc = 0;
26903446Smrj 
26913446Smrj 	softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
26923446Smrj 	if (softstate == NULL) {
26933446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_open: get soft state err"));
26943446Smrj 		return (ENXIO);
26953446Smrj 	}
26963446Smrj 	mutex_enter(&softstate->asoft_instmutex);
26973446Smrj 
26983446Smrj 	if (softstate->asoft_opened) {
26993446Smrj 		softstate->asoft_opened++;
27003446Smrj 		mutex_exit(&softstate->asoft_instmutex);
27013446Smrj 		return (0);
27023446Smrj 	}
27033446Smrj 
27043446Smrj 	/*
27053446Smrj 	 * The driver is opened first time, so we initialize layered
27063446Smrj 	 * driver interface and softstate member here.
27073446Smrj 	 */
27083446Smrj 	softstate->asoft_pgused = 0;
27093446Smrj 	if (lyr_init(&softstate->asoft_devreg, softstate->asoft_li)) {
27103446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_open: lyr_init failed"));
27113446Smrj 		mutex_exit(&softstate->asoft_instmutex);
27123446Smrj 		return (EAGAIN);
27133446Smrj 	}
27143446Smrj 
27153446Smrj 	/* Call into layered driver */
27163446Smrj 	if (lyr_get_info(&softstate->asoft_info, &softstate->asoft_devreg)) {
27173446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_open: lyr_get_info error"));
27183446Smrj 		lyr_end(&softstate->asoft_devreg);
27193446Smrj 		mutex_exit(&softstate->asoft_instmutex);
27203446Smrj 		return (EIO);
27213446Smrj 	}
27223446Smrj 
27233446Smrj 	/*
27243446Smrj 	 * BIOS already set up gtt table for ARC_IGD830
27253446Smrj 	 */
27263446Smrj 	if (IS_INTEL_830(softstate->asoft_devreg.agprd_arctype)) {
27273446Smrj 		softstate->asoft_opened++;
27283446Smrj 
27293446Smrj 		softstate->asoft_pgtotal =
27303446Smrj 		    get_max_pages(softstate->asoft_info.agpki_apersize);
27313446Smrj 
27323446Smrj 		if (lyr_config_devices(&softstate->asoft_devreg)) {
27333446Smrj 			AGPDB_PRINT2((CE_WARN,
27343446Smrj 			    "agpgart_open: lyr_config_devices error"));
27353446Smrj 			lyr_end(&softstate->asoft_devreg);
27363446Smrj 			mutex_exit(&softstate->asoft_instmutex);
27373446Smrj 
27383446Smrj 			return (EIO);
27393446Smrj 		}
27403446Smrj 		mutex_exit(&softstate->asoft_instmutex);
27413446Smrj 		return (0);
27423446Smrj 	}
27433446Smrj 
27443446Smrj 	rc = alloc_gart_table(softstate);
27453446Smrj 
27463446Smrj 	/*
27473446Smrj 	 * Allocate physically contiguous pages for AGP arc or
27483446Smrj 	 * i810 arc. If failed, divide aper_size by 2 to
27493446Smrj 	 * reduce gart table size until 4 megabytes. This
27503446Smrj 	 * is just a workaround for systems with very few
27513446Smrj 	 * physically contiguous memory.
27523446Smrj 	 */
27533446Smrj 	if (rc) {
27543446Smrj 		while ((softstate->asoft_info.agpki_apersize >= 4) &&
27553446Smrj 		    (alloc_gart_table(softstate))) {
27563446Smrj 			softstate->asoft_info.agpki_apersize >>= 1;
27573446Smrj 		}
27583446Smrj 		if (softstate->asoft_info.agpki_apersize >= 4)
27593446Smrj 			rc = 0;
27603446Smrj 	}
27613446Smrj 
27623446Smrj 	if (rc != 0) {
27633446Smrj 		AGPDB_PRINT2((CE_WARN,
27643446Smrj 		    "agpgart_open: alloc gart table failed"));
27653446Smrj 		lyr_end(&softstate->asoft_devreg);
27663446Smrj 		mutex_exit(&softstate->asoft_instmutex);
27673446Smrj 		return (EAGAIN);
27683446Smrj 	}
27693446Smrj 
27703446Smrj 	softstate->asoft_pgtotal =
27713446Smrj 	    get_max_pages(softstate->asoft_info.agpki_apersize);
27723446Smrj 	/*
27733446Smrj 	 * BIOS doesn't initialize GTT for i810,
27743446Smrj 	 * So i810 GTT must be created by driver.
27753446Smrj 	 *
27763446Smrj 	 * Set up gart table and enable it.
27773446Smrj 	 */
27783446Smrj 	if (lyr_set_gart_addr(softstate->gart_pbase,
27793446Smrj 	    &softstate->asoft_devreg)) {
27803446Smrj 		AGPDB_PRINT2((CE_WARN,
27813446Smrj 		    "agpgart_open: set gart table addr failed"));
27823446Smrj 		free_gart_table(softstate);
27833446Smrj 		lyr_end(&softstate->asoft_devreg);
27843446Smrj 		mutex_exit(&softstate->asoft_instmutex);
27853446Smrj 		return (EIO);
27863446Smrj 	}
27873446Smrj 	if (lyr_config_devices(&softstate->asoft_devreg)) {
27883446Smrj 		AGPDB_PRINT2((CE_WARN,
27893446Smrj 		    "agpgart_open: lyr_config_devices failed"));
27903446Smrj 		free_gart_table(softstate);
27913446Smrj 		lyr_end(&softstate->asoft_devreg);
27923446Smrj 		mutex_exit(&softstate->asoft_instmutex);
27933446Smrj 		return (EIO);
27943446Smrj 	}
27953446Smrj 
27963446Smrj 	softstate->asoft_opened++;
27973446Smrj 	mutex_exit(&softstate->asoft_instmutex);
27983446Smrj 
27993446Smrj 	return (0);
28003446Smrj }
28013446Smrj 
28023446Smrj /*
28033446Smrj  * agpgart_close()
28043446Smrj  *
28053446Smrj  * Description:
28063446Smrj  * 	agpgart_close will release resources allocated in the first open
28073446Smrj  * 	and close other open layered drivers. Also it frees the memory
28083446Smrj  *	allocated by ioctls.
28093446Smrj  *
28103446Smrj  * Arguments:
28113446Smrj  * 	dev			device number
28123446Smrj  * 	flag			file status flag
28133446Smrj  *	otyp			OTYP_BLK, OTYP_CHR
28143446Smrj  * 	credp			user's credential's struct pointer
28153446Smrj  *
28163446Smrj  * Returns:
28173446Smrj  * 	ENXIO			not an error, to support "deferred attach"
28183446Smrj  * 	0			success
28193446Smrj  */
28203446Smrj /*ARGSUSED*/
28213446Smrj static int
28223446Smrj agpgart_close(dev_t dev, int flag, int otyp, cred_t *credp)
28233446Smrj {
28243446Smrj 	int instance = AGP_DEV2INST(dev);
28253446Smrj 	agpgart_softstate_t *softstate;
28263446Smrj 
28273446Smrj 	softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
28283446Smrj 	if (softstate == NULL) {
28293446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_close: get soft state err"));
28303446Smrj 		return (ENXIO);
28313446Smrj 	}
28323446Smrj 
28333446Smrj 	mutex_enter(&softstate->asoft_instmutex);
28343446Smrj 	ASSERT(softstate->asoft_opened);
28353446Smrj 
28363446Smrj 
28373446Smrj 	/*
28383446Smrj 	 * If the last process close this device is not the controlling
28393446Smrj 	 * process, also release the control over agpgart driver here if the
28403446Smrj 	 * the controlling process fails to release the control before it
28413446Smrj 	 * close the driver.
28423446Smrj 	 */
28433446Smrj 	if (softstate->asoft_acquired == 1) {
28443446Smrj 		AGPDB_PRINT2((CE_WARN,
28453446Smrj 		    "agpgart_close: auto release control over driver"));
28463446Smrj 		release_control(softstate);
28473446Smrj 	}
28483446Smrj 
28493446Smrj 	if (lyr_unconfig_devices(&softstate->asoft_devreg)) {
28503446Smrj 		AGPDB_PRINT2((CE_WARN,
28513446Smrj 		    "agpgart_close: lyr_unconfig_device error"));
28523446Smrj 		mutex_exit(&softstate->asoft_instmutex);
28533446Smrj 		return (EIO);
28543446Smrj 	}
28553446Smrj 	softstate->asoft_agpen = 0;
28563446Smrj 
28573446Smrj 	if (!IS_INTEL_830(softstate->asoft_devreg.agprd_arctype)) {
28583446Smrj 		free_gart_table(softstate);
28593446Smrj 	}
28603446Smrj 
28613446Smrj 	lyr_end(&softstate->asoft_devreg);
28623446Smrj 
28633446Smrj 	/*
28643446Smrj 	 * This statement must be positioned before agp_del_allkeys
28653446Smrj 	 * agp_dealloc_mem indirectly called by agp_del_allkeys
28663446Smrj 	 * will test this variable.
28673446Smrj 	 */
28683446Smrj 	softstate->asoft_opened = 0;
28693446Smrj 
28703446Smrj 	/*
28713446Smrj 	 * Free the memory allocated by user applications which
28723446Smrj 	 * was never deallocated.
28733446Smrj 	 */
28743446Smrj 	(void) agp_del_allkeys(softstate);
28753446Smrj 
28763446Smrj 	mutex_exit(&softstate->asoft_instmutex);
28773446Smrj 
28783446Smrj 	return (0);
28793446Smrj }
28803446Smrj 
28813446Smrj static int
28823446Smrj ioctl_agpgart_info(agpgart_softstate_t  *softstate, void  *arg, int flags)
28833446Smrj {
28843446Smrj 	agp_info_t infostruct;
28853446Smrj #ifdef _MULTI_DATAMODEL
28863446Smrj 	agp_info32_t infostruct32;
28873446Smrj #endif
28883446Smrj 
28893446Smrj 	bzero(&infostruct, sizeof (agp_info_t));
28903446Smrj 
28913446Smrj #ifdef _MULTI_DATAMODEL
28923446Smrj 	bzero(&infostruct32, sizeof (agp_info32_t));
28933446Smrj 	if (ddi_model_convert_from(flags & FMODELS) == DDI_MODEL_ILP32) {
28943446Smrj 		if (copyinfo(softstate, &infostruct))
28953446Smrj 			return (EINVAL);
28963446Smrj 
28973446Smrj 		agpinfo_default_to_32(infostruct, infostruct32);
28983446Smrj 		if (ddi_copyout(&infostruct32, arg,
28993446Smrj 		    sizeof (agp_info32_t), flags) != 0)
29003446Smrj 			return (EFAULT);
29013446Smrj 
29023446Smrj 		return (0);
29033446Smrj 	}
29043446Smrj #endif /* _MULTI_DATAMODEL */
29053446Smrj 	if (copyinfo(softstate, &infostruct))
29063446Smrj 		return (EINVAL);
29073446Smrj 
29083446Smrj 	if (ddi_copyout(&infostruct, arg, sizeof (agp_info_t), flags) != 0) {
29093446Smrj 		return (EFAULT);
29103446Smrj 	}
29113446Smrj 
29123446Smrj 	return (0);
29133446Smrj }
29143446Smrj 
29153446Smrj static int
29163446Smrj ioctl_agpgart_acquire(agpgart_softstate_t  *st)
29173446Smrj {
29183446Smrj 	if (st->asoft_acquired) {
29193446Smrj 		AGPDB_PRINT2((CE_WARN, "ioctl_acquire: already acquired"));
29203446Smrj 		return (EBUSY);
29213446Smrj 	}
29223446Smrj 	acquire_control(st);
29233446Smrj 	return (0);
29243446Smrj }
29253446Smrj 
29263446Smrj static int
29273446Smrj ioctl_agpgart_release(agpgart_softstate_t  *st)
29283446Smrj {
29293446Smrj 	if (is_controlling_proc(st) < 0) {
29303446Smrj 		AGPDB_PRINT2((CE_WARN,
29313446Smrj 		    "ioctl_agpgart_release: not a controlling process"));
29323446Smrj 		return (EPERM);
29333446Smrj 	}
29343446Smrj 	release_control(st);
29353446Smrj 	return (0);
29363446Smrj }
29373446Smrj 
29383446Smrj static int
29393446Smrj ioctl_agpgart_setup(agpgart_softstate_t  *st, void  *arg, int flags)
29403446Smrj {
29413446Smrj 	agp_setup_t data;
29423446Smrj 	int rc = 0;
29433446Smrj 
29443446Smrj 	if (is_controlling_proc(st) < 0) {
29453446Smrj 		AGPDB_PRINT2((CE_WARN,
29463446Smrj 		    "ioctl_agpgart_setup: not a controlling process"));
29473446Smrj 		return (EPERM);
29483446Smrj 	}
29493446Smrj 
29503446Smrj 	if (!IS_TRUE_AGP(st->asoft_devreg.agprd_arctype)) {
29513446Smrj 		AGPDB_PRINT2((CE_WARN,
29523446Smrj 		    "ioctl_agpgart_setup: no true agp bridge"));
29533446Smrj 		return (EINVAL);
29543446Smrj 	}
29553446Smrj 
29563446Smrj 	if (ddi_copyin(arg, &data, sizeof (agp_setup_t), flags) != 0)
29573446Smrj 		return (EFAULT);
29583446Smrj 
29593446Smrj 	if (rc = agp_setup(st, data.agps_mode))
29603446Smrj 		return (rc);
29613446Smrj 	/* Store agp mode status for kstat */
29623446Smrj 	st->asoft_agpen = 1;
29633446Smrj 	return (0);
29643446Smrj }
29653446Smrj 
29663446Smrj static int
29673446Smrj ioctl_agpgart_alloc(agpgart_softstate_t  *st, void  *arg, int flags)
29683446Smrj {
29693446Smrj 	agp_allocate_t	alloc_info;
29703446Smrj 	keytable_ent_t	*entryp;
29713446Smrj 	size_t		length;
29723446Smrj 	uint64_t	pg_num;
29733446Smrj 
29743446Smrj 	if (is_controlling_proc(st) < 0) {
29753446Smrj 		AGPDB_PRINT2((CE_WARN,
29763446Smrj 		    "ioctl_agpgart_alloc: not a controlling process"));
29773446Smrj 		return (EPERM);
29783446Smrj 	}
29793446Smrj 
29803446Smrj 	if (ddi_copyin(arg, &alloc_info,
29813446Smrj 	    sizeof (agp_allocate_t), flags) != 0) {
29823446Smrj 		return (EFAULT);
29833446Smrj 	}
29843446Smrj 	pg_num = st->asoft_pgused + alloc_info.agpa_pgcount;
29853446Smrj 	if (pg_num > st->asoft_pgtotal) {
29863446Smrj 		AGPDB_PRINT2((CE_WARN,
29873446Smrj 		    "ioctl_agpgart_alloc: exceeding the memory pages limit"));
29883446Smrj 		AGPDB_PRINT2((CE_WARN,
29893446Smrj 		    "ioctl_agpgart_alloc: request %x pages failed",
29903446Smrj 		    alloc_info.agpa_pgcount));
29913446Smrj 		AGPDB_PRINT2((CE_WARN,
29923446Smrj 		    "ioctl_agpgart_alloc: pages used %x total is %x",
29933446Smrj 		    st->asoft_pgused, st->asoft_pgtotal));
29943446Smrj 
29953446Smrj 		return (EINVAL);
29963446Smrj 	}
29973446Smrj 
29983446Smrj 	length = AGP_PAGES2BYTES(alloc_info.agpa_pgcount);
29993446Smrj 	entryp = agp_alloc_mem(st, length, alloc_info.agpa_type);
30003446Smrj 	if (!entryp) {
30013446Smrj 		AGPDB_PRINT2((CE_WARN,
30023446Smrj 		    "ioctl_agpgart_alloc: allocate 0x%lx bytes failed",
30033446Smrj 		    length));
30043446Smrj 		return (ENOMEM);
30053446Smrj 	}
30063446Smrj 	ASSERT((entryp->kte_key >= 0) && (entryp->kte_key < AGP_MAXKEYS));
30073446Smrj 	alloc_info.agpa_key = entryp->kte_key;
30083446Smrj 	if (alloc_info.agpa_type == AGP_PHYSICAL) {
30093446Smrj 		alloc_info.agpa_physical =
30103446Smrj 		    (uint32_t)(entryp->kte_pfnarray[0] << AGP_PAGE_SHIFT);
30113446Smrj 	}
30123446Smrj 	/* Update the memory pagse used */
30133446Smrj 	st->asoft_pgused += alloc_info.agpa_pgcount;
30143446Smrj 
30153446Smrj 	if (ddi_copyout(&alloc_info, arg,
30163446Smrj 	    sizeof (agp_allocate_t), flags) != 0) {
30173446Smrj 
30183446Smrj 		return (EFAULT);
30193446Smrj 	}
30203446Smrj 
30213446Smrj 	return (0);
30223446Smrj }
30233446Smrj 
30243446Smrj static int
30253446Smrj ioctl_agpgart_dealloc(agpgart_softstate_t  *st, intptr_t arg)
30263446Smrj {
30273446Smrj 	int key;
30283446Smrj 	keytable_ent_t  *keyent;
30293446Smrj 
30303446Smrj 	if (is_controlling_proc(st) < 0) {
30313446Smrj 		AGPDB_PRINT2((CE_WARN,
30323446Smrj 		    "ioctl_agpgart_dealloc: not a controlling process"));
30333446Smrj 		return (EPERM);
30343446Smrj 	}
30353446Smrj 	key = (int)arg;
30363446Smrj 	if ((key >= AGP_MAXKEYS) || key < 0) {
30373446Smrj 		return (EINVAL);
30383446Smrj 	}
30393446Smrj 	keyent = &st->asoft_table[key];
30403446Smrj 	if (!keyent->kte_memhdl) {
30413446Smrj 		return (EINVAL);
30423446Smrj 	}
30433446Smrj 
30443446Smrj 	if (agp_dealloc_mem(st, keyent))
30453446Smrj 		return (EINVAL);
30463446Smrj 
30473446Smrj 	/* Update the memory pages used */
30483446Smrj 	st->asoft_pgused -= keyent->kte_pages;
30493446Smrj 	bzero(keyent, sizeof (keytable_ent_t));
30503446Smrj 
30513446Smrj 	return (0);
30523446Smrj }
30533446Smrj 
30543446Smrj static int
30553446Smrj ioctl_agpgart_bind(agpgart_softstate_t  *st, void  *arg, int flags)
30563446Smrj {
30573446Smrj 	agp_bind_t 	bind_info;
30583446Smrj 	keytable_ent_t	*keyent;
30593446Smrj 	int		key;
30603446Smrj 	uint32_t	pg_offset;
30613446Smrj 	int		retval = 0;
30623446Smrj 
30633446Smrj 	if (is_controlling_proc(st) < 0) {
30643446Smrj 		AGPDB_PRINT2((CE_WARN,
30653446Smrj 		    "ioctl_agpgart_bind: not a controlling process"));
30663446Smrj 		return (EPERM);
30673446Smrj 	}
30683446Smrj 
30693446Smrj 	if (ddi_copyin(arg, &bind_info, sizeof (agp_bind_t), flags) != 0) {
30703446Smrj 		return (EFAULT);
30713446Smrj 	}
30723446Smrj 
30733446Smrj 	key = bind_info.agpb_key;
30743446Smrj 	if ((key >= AGP_MAXKEYS) || key < 0) {
30753446Smrj 		AGPDB_PRINT2((CE_WARN, "ioctl_agpgart_bind: invalid key"));
30763446Smrj 		return (EINVAL);
30773446Smrj 	}
30783446Smrj 
30793446Smrj 	if (IS_INTEL_830(st->asoft_devreg.agprd_arctype)) {
30803446Smrj 		if (AGP_PAGES2KB(bind_info.agpb_pgstart) <
30813446Smrj 		    st->asoft_info.agpki_presize) {
30823446Smrj 			AGPDB_PRINT2((CE_WARN,
30834478Skz151634 			    "ioctl_agpgart_bind: bind to prealloc area "
30844478Skz151634 			    "pgstart = %dKB < presize = %ldKB",
30854478Skz151634 			    AGP_PAGES2KB(bind_info.agpb_pgstart),
30864478Skz151634 			    st->asoft_info.agpki_presize));
30873446Smrj 			return (EINVAL);
30883446Smrj 		}
30893446Smrj 	}
30903446Smrj 
30913446Smrj 	pg_offset = bind_info.agpb_pgstart;
30923446Smrj 	keyent = &st->asoft_table[key];
30933446Smrj 	if (!keyent->kte_memhdl) {
30943446Smrj 		AGPDB_PRINT2((CE_WARN,
30953446Smrj 		    "ioctl_agpgart_bind: Key = 0x%x can't get keyenty",
30963446Smrj 		    key));
30973446Smrj 		return (EINVAL);
30983446Smrj 	}
30993446Smrj 
31003446Smrj 	if (keyent->kte_bound != 0) {
31013446Smrj 		AGPDB_PRINT2((CE_WARN,
31023446Smrj 		    "ioctl_agpgart_bind: Key = 0x%x already bound",
31033446Smrj 		    key));
31043446Smrj 		return (EINVAL);
31053446Smrj 	}
31063446Smrj 	retval = agp_bind_key(st, keyent, pg_offset);
31073446Smrj 
31083446Smrj 	if (retval == 0) {
31093446Smrj 		keyent->kte_pgoff = pg_offset;
31103446Smrj 		keyent->kte_bound = 1;
31113446Smrj 	}
31123446Smrj 
31133446Smrj 	return (retval);
31143446Smrj }
31153446Smrj 
31163446Smrj static int
31173446Smrj ioctl_agpgart_unbind(agpgart_softstate_t  *st, void  *arg, int flags)
31183446Smrj {
31193446Smrj 	int key, retval = 0;
31203446Smrj 	agp_unbind_t unbindinfo;
31213446Smrj 	keytable_ent_t *keyent;
31223446Smrj 
31233446Smrj 	if (is_controlling_proc(st) < 0) {
31243446Smrj 		AGPDB_PRINT2((CE_WARN,
31253446Smrj 		    "ioctl_agpgart_bind: not a controlling process"));
31263446Smrj 		return (EPERM);
31273446Smrj 	}
31283446Smrj 
31293446Smrj 	if (ddi_copyin(arg, &unbindinfo, sizeof (unbindinfo), flags) != 0) {
31303446Smrj 		return (EFAULT);
31313446Smrj 	}
31323446Smrj 	key = unbindinfo.agpu_key;
31333446Smrj 	if ((key >= AGP_MAXKEYS) || key < 0) {
31343446Smrj 		AGPDB_PRINT2((CE_WARN, "ioctl_agpgart_unbind: invalid key"));
31353446Smrj 		return (EINVAL);
31363446Smrj 	}
31373446Smrj 	keyent = &st->asoft_table[key];
31383446Smrj 	if (!keyent->kte_bound) {
31393446Smrj 		return (EINVAL);
31403446Smrj 	}
31413446Smrj 
31423446Smrj 	if ((retval = agp_unbind_key(st, keyent)) != 0)
31433446Smrj 		return (retval);
31443446Smrj 
31453446Smrj 	return (0);
31463446Smrj }
31473446Smrj 
31483446Smrj /*ARGSUSED*/
31493446Smrj static int
31503446Smrj agpgart_ioctl(dev_t dev, int cmd, intptr_t intarg, int flags,
31513446Smrj     cred_t *credp, int *rvalp)
31523446Smrj {
31533446Smrj 	int instance;
31543446Smrj 	int retval = 0;
31553446Smrj 	void *arg = (void*)intarg;
31563446Smrj 
31573446Smrj 	agpgart_softstate_t *softstate;
31583446Smrj 
31593446Smrj 	instance = AGP_DEV2INST(dev);
31603446Smrj 	softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
31613446Smrj 	if (softstate == NULL) {
31623446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_ioctl: get soft state err"));
31633446Smrj 		return (ENXIO);
31643446Smrj 	}
31653446Smrj 
31663446Smrj 	if ((cmd != AGPIOC_INFO) && secpolicy_gart_access(credp)) {
31673446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_ioctl: permission denied"));
31683446Smrj 		return (EPERM);
31693446Smrj 	}
31703446Smrj 
31713446Smrj 	mutex_enter(&softstate->asoft_instmutex);
31723446Smrj 
31733446Smrj 	switch (cmd) {
31743446Smrj 	case AGPIOC_INFO:
31753446Smrj 		retval = ioctl_agpgart_info(softstate, arg, flags);
31763446Smrj 		break;
31773446Smrj 	case AGPIOC_ACQUIRE:
31783446Smrj 		retval = ioctl_agpgart_acquire(softstate);
31793446Smrj 		break;
31803446Smrj 	case AGPIOC_RELEASE:
31813446Smrj 		retval = ioctl_agpgart_release(softstate);
31823446Smrj 		break;
31833446Smrj 	case AGPIOC_SETUP:
31843446Smrj 		retval = ioctl_agpgart_setup(softstate, arg, flags);
31853446Smrj 		break;
31863446Smrj 	case AGPIOC_ALLOCATE:
31873446Smrj 		retval = ioctl_agpgart_alloc(softstate, arg, flags);
31883446Smrj 		break;
31893446Smrj 	case AGPIOC_DEALLOCATE:
31903446Smrj 		retval = ioctl_agpgart_dealloc(softstate, intarg);
31913446Smrj 		break;
31923446Smrj 	case AGPIOC_BIND:
31933446Smrj 		retval = ioctl_agpgart_bind(softstate, arg, flags);
31943446Smrj 		break;
31953446Smrj 	case AGPIOC_UNBIND:
31963446Smrj 		retval = ioctl_agpgart_unbind(softstate, arg, flags);
31973446Smrj 		break;
31983446Smrj 	default:
31993446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_ioctl: wrong argument"));
32003446Smrj 		retval = ENXIO;
32013446Smrj 		break;
32023446Smrj 	}
32033446Smrj 
32043446Smrj 	mutex_exit(&softstate->asoft_instmutex);
32053446Smrj 	return (retval);
32063446Smrj }
32073446Smrj 
32083446Smrj static int
32093446Smrj agpgart_segmap(dev_t dev, off_t off, struct as *asp,
32103446Smrj     caddr_t *addrp, off_t len, unsigned int prot,
32113446Smrj     unsigned int maxprot, unsigned int flags, cred_t *credp)
32123446Smrj {
32133446Smrj 
32143446Smrj 	struct agpgart_softstate *softstate;
32153446Smrj 	int instance;
32163446Smrj 	int rc = 0;
32173446Smrj 
32183446Smrj 	instance = AGP_DEV2INST(dev);
32193446Smrj 	softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
32203446Smrj 	if (softstate == NULL) {
32213446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_segmap: get soft state err"));
32223446Smrj 		return (ENXIO);
32233446Smrj 	}
32243446Smrj 	if (!AGP_ALIGNED(len))
32253446Smrj 		return (EINVAL);
32263446Smrj 
32273446Smrj 	mutex_enter(&softstate->asoft_instmutex);
32283446Smrj 
32293446Smrj 	/*
32303446Smrj 	 * Process must have gart map privilege or gart access privilege
32313446Smrj 	 * to map agp memory.
32323446Smrj 	 */
32333446Smrj 	if (secpolicy_gart_map(credp)) {
32343446Smrj 		mutex_exit(&softstate->asoft_instmutex);
32353446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_segmap: permission denied"));
32363446Smrj 		return (EPERM);
32373446Smrj 	}
32383446Smrj 
32393446Smrj 	rc = devmap_setup(dev, (offset_t)off, asp, addrp,
32403446Smrj 	    (size_t)len, prot, maxprot, flags, credp);
32413446Smrj 
32423446Smrj 	mutex_exit(&softstate->asoft_instmutex);
32433446Smrj 	return (rc);
32443446Smrj }
32453446Smrj 
32463446Smrj /*ARGSUSED*/
32473446Smrj static int
32483446Smrj agpgart_devmap(dev_t dev, devmap_cookie_t cookie, offset_t offset, size_t len,
32493446Smrj     size_t *mappedlen, uint_t model)
32503446Smrj {
32513446Smrj 	struct agpgart_softstate *softstate;
32523446Smrj 	int instance, status;
32533446Smrj 	struct keytable_ent *mementry;
32543446Smrj 	offset_t local_offset;
32553446Smrj 
32563446Smrj 	instance = AGP_DEV2INST(dev);
32573446Smrj 	softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance);
32583446Smrj 	if (softstate == NULL) {
32593446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_devmap: get soft state err"));
32603446Smrj 		return (ENXIO);
32613446Smrj 	}
32623446Smrj 
32633446Smrj 
32643446Smrj 	if (offset > MB2BYTES(softstate->asoft_info.agpki_apersize)) {
32653446Smrj 		AGPDB_PRINT2((CE_WARN, "agpgart_devmap: offset is too large"));
32663446Smrj 		return (EINVAL);
32673446Smrj 	}
32683446Smrj 
32693446Smrj 	/*
32703446Smrj 	 * Can not find any memory now, so fail.
32713446Smrj 	 */
32723446Smrj 
32733446Smrj 	mementry = agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(offset));
32743446Smrj 
32753446Smrj 	if (mementry == NULL) {
32763446Smrj 		AGPDB_PRINT2((CE_WARN,
32773446Smrj 		    "agpgart_devmap: can not find the proper keyent"));
32783446Smrj 		return (EINVAL);
32793446Smrj 	}
32803446Smrj 
32813446Smrj 	local_offset = offset - AGP_PAGES2BYTES(mementry->kte_pgoff);
32823446Smrj 
32833446Smrj 	if (len > (AGP_PAGES2BYTES(mementry->kte_pages) - local_offset)) {
32843446Smrj 		len = AGP_PAGES2BYTES(mementry->kte_pages) - local_offset;
32853446Smrj 	}
32863446Smrj 
32873446Smrj 	switch (mementry->kte_type) {
32883446Smrj 	case AGP_NORMAL:
32893446Smrj 		status = devmap_pmem_setup(cookie, softstate->asoft_dip,
32903446Smrj 		    &agp_devmap_cb,
32913446Smrj 		    PMEMP(mementry->kte_memhdl)->pmem_cookie, local_offset,
32923446Smrj 		    len, PROT_ALL, (DEVMAP_DEFAULTS|IOMEM_DATA_UC_WR_COMBINE),
32933446Smrj 		    &mem_dev_acc_attr);
32943446Smrj 		break;
32953446Smrj 	default:
32963446Smrj 		AGPDB_PRINT2((CE_WARN,
32973446Smrj 		    "agpgart_devmap: not a valid memory type"));
32983446Smrj 		return (EINVAL);
32993446Smrj 	}
33003446Smrj 
33013446Smrj 
33023446Smrj 	if (status == 0) {
33033446Smrj 		*mappedlen = len;
33043446Smrj 	} else {
33053446Smrj 		*mappedlen = 0;
33063446Smrj 		AGPDB_PRINT2((CE_WARN,
33073446Smrj 		    "agpgart_devmap: devmap interface failed"));
33083446Smrj 		return (EINVAL);
33093446Smrj 	}
33103446Smrj 
33113446Smrj 	return (0);
33123446Smrj }
33133446Smrj 
33143446Smrj static struct cb_ops	agpgart_cb_ops = {
33153446Smrj 	agpgart_open,		/* open() */
33163446Smrj 	agpgart_close,		/* close() */
33173446Smrj 	nodev,			/* strategy() */
33183446Smrj 	nodev,			/* print routine */
33193446Smrj 	nodev,			/* no dump routine */
33203446Smrj 	nodev,			/* read() */
33213446Smrj 	nodev,			/* write() */
33223446Smrj 	agpgart_ioctl,		/* agpgart_ioctl */
33233446Smrj 	agpgart_devmap,		/* devmap routine */
33243446Smrj 	nodev,			/* no longer use mmap routine */
33253446Smrj 	agpgart_segmap,		/* system segmap routine */
33263446Smrj 	nochpoll,		/* no chpoll routine */
33273446Smrj 	ddi_prop_op,		/* system prop operations */
33283446Smrj 	0,			/* not a STREAMS driver */
33293446Smrj 	D_DEVMAP | D_MP,	/* safe for multi-thread/multi-processor */
33303446Smrj 	CB_REV,			/* cb_ops version? */
33313446Smrj 	nodev,			/* cb_aread() */
33323446Smrj 	nodev,			/* cb_awrite() */
33333446Smrj };
33343446Smrj 
33353446Smrj static struct dev_ops agpgart_ops = {
33363446Smrj 	DEVO_REV,		/* devo_rev */
33373446Smrj 	0,			/* devo_refcnt */
33383446Smrj 	agpgart_getinfo,	/* devo_getinfo */
33393446Smrj 	nulldev,		/* devo_identify */
33403446Smrj 	nulldev,		/* devo_probe */
33413446Smrj 	agpgart_attach,		/* devo_attach */
33423446Smrj 	agpgart_detach,		/* devo_detach */
33433446Smrj 	nodev,			/* devo_reset */
33443446Smrj 	&agpgart_cb_ops,	/* devo_cb_ops */
33453446Smrj 	(struct bus_ops *)0,	/* devo_bus_ops */
33463446Smrj 	NULL,			/* devo_power */
33473446Smrj };
33483446Smrj 
33493446Smrj static	struct modldrv modldrv = {
33503446Smrj 	&mod_driverops,
33513446Smrj 	"AGP driver v%I%",
33523446Smrj 	&agpgart_ops,
33533446Smrj };
33543446Smrj 
33553446Smrj static struct modlinkage modlinkage = {
33563446Smrj 	MODREV_1,		/* MODREV_1 is indicated by manual */
33573446Smrj 	{&modldrv, NULL, NULL, NULL}
33583446Smrj };
33593446Smrj 
33603446Smrj static void *agpgart_glob_soft_handle;
33613446Smrj 
33623446Smrj int
33633446Smrj _init(void)
33643446Smrj {
33653446Smrj 	int ret = DDI_SUCCESS;
33663446Smrj 
33673446Smrj 	ret = ddi_soft_state_init(&agpgart_glob_soft_handle,
33684478Skz151634 	    sizeof (agpgart_softstate_t),
33694478Skz151634 	    AGPGART_MAX_INSTANCES);
33703446Smrj 
33713446Smrj 	if (ret != 0) {
33723446Smrj 		AGPDB_PRINT2((CE_WARN,
33733446Smrj 		    "_init: soft state init error code=0x%x", ret));
33743446Smrj 		return (ret);
33753446Smrj 	}
33763446Smrj 
33773446Smrj 	if ((ret = mod_install(&modlinkage)) != 0) {
33783446Smrj 		AGPDB_PRINT2((CE_WARN,
33793446Smrj 		    "_init: mod install error code=0x%x", ret));
33803446Smrj 		ddi_soft_state_fini(&agpgart_glob_soft_handle);
33813446Smrj 		return (ret);
33823446Smrj 	}
33833446Smrj 
33843446Smrj 	return (DDI_SUCCESS);
33853446Smrj }
33863446Smrj 
33873446Smrj int
33883446Smrj _info(struct modinfo *modinfop)
33893446Smrj {
33903446Smrj 	return (mod_info(&modlinkage, modinfop));
33913446Smrj }
33923446Smrj 
33933446Smrj int
33943446Smrj _fini(void)
33953446Smrj {
33963446Smrj 	int ret;
33973446Smrj 
33983446Smrj 	if ((ret = mod_remove(&modlinkage)) == 0) {
33993446Smrj 		ddi_soft_state_fini(&agpgart_glob_soft_handle);
34003446Smrj 	}
34013446Smrj 
34023446Smrj 	return (ret);
34033446Smrj }
3404