13446Smrj /*
23527Sms148562  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
33446Smrj  * Use is subject to license terms.
43446Smrj  */
53446Smrj 
63446Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
73446Smrj 
83446Smrj #include <sys/systm.h>
93446Smrj #include <sys/conf.h>
103446Smrj #include <sys/modctl.h>
113446Smrj #include <sys/file.h>
123446Smrj #include <sys/stat.h>
133446Smrj #include <sys/ddi.h>
143446Smrj #include <sys/sunddi.h>
153446Smrj #include <sys/modctl.h>
163446Smrj #include <sys/sunldi.h>
173446Smrj #include <sys/pci.h>
183446Smrj #include <sys/agpgart.h>
193446Smrj #include <sys/agp/agpdefs.h>
203446Smrj #include <sys/agp/agptarget_io.h>
213446Smrj 
223446Smrj int agptarget_debug_var = 0;
233446Smrj #define	TARGETDB_PRINT2(fmt)	if (agptarget_debug_var >= 1) cmn_err fmt
243446Smrj #define	INST2NODENUM(inst)	(inst)
253446Smrj #define	DEV2INST(dev)		(getminor(dev))
263446Smrj 
273446Smrj typedef struct agp_target_softstate {
283446Smrj 	dev_info_t		*tsoft_dip;
293446Smrj 	ddi_acc_handle_t	tsoft_pcihdl;
303446Smrj 	uint32_t		tsoft_devid;
313446Smrj 	/* The offset of the ACAPID register */
323446Smrj 	off_t			tsoft_acaptr;
333446Smrj 	kmutex_t		tsoft_lock;
343446Smrj }agp_target_softstate_t;
353446Smrj 
363446Smrj static void *agptarget_glob_soft_handle;
373446Smrj 
383446Smrj #define	GETSOFTC(instance)	((agp_target_softstate_t *)	\
393446Smrj     ddi_get_soft_state(agptarget_glob_soft_handle, instance));
403446Smrj 
413446Smrj /*
423446Smrj  * The AMD8151 bridge is the only supported 64 bit hardware
433446Smrj  */
443446Smrj static int
453446Smrj is_64bit_aper(agp_target_softstate_t *softstate)
463446Smrj {
473446Smrj 	return (softstate->tsoft_devid == AMD_BR_8151);
483446Smrj }
493446Smrj 
503446Smrj /*
513446Smrj  * agp_target_cap_find()
523446Smrj  *
533446Smrj  * Description:
543446Smrj  * 	This function searches the linked capability list to find the offset
553446Smrj  * 	of the AGP capability register. When it was not found, return 0.
563446Smrj  * 	This works for standard AGP chipsets, but not for some Intel chipsets,
573446Smrj  * 	like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for
583446Smrj  * 	these chipsets even if AGP is supported. So the offset of acapid
593446Smrj  * 	should be set manually in thoses cases.
603446Smrj  *
613446Smrj  * Arguments:
623446Smrj  * 	pci_handle		ddi acc handle of pci config
633446Smrj  *
643446Smrj  * Returns:
653446Smrj  * 	0			No capability pointer register found
663446Smrj  * 	nexcap			The AGP capability pointer register offset
673446Smrj  */
683446Smrj static off_t
693446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle)
703446Smrj {
713446Smrj 	off_t		nextcap = 0;
723446Smrj 	uint32_t	ncapid = 0;
733446Smrj 	uint8_t		value = 0;
743446Smrj 
753446Smrj 	/* Check if this device supports the capability pointer */
763446Smrj 	value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT)
773446Smrj 	    & PCI_CONF_CAP_MASK);
783446Smrj 
793446Smrj 	if (!value)
803446Smrj 		return (0);
813446Smrj 	/* Get the offset of the first capability pointer from CAPPTR */
823446Smrj 	nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR));
833446Smrj 
843446Smrj 	/* Check the AGP capability from the first capability pointer */
853446Smrj 	while (nextcap) {
863446Smrj 		ncapid = pci_config_get32(pci_handle, nextcap);
873446Smrj 		/*
883446Smrj 		 * AGP3.0 rev1.0 127  the capid was assigned by the PCI SIG,
893446Smrj 		 * 845 data sheet page 69
903446Smrj 		 */
913446Smrj 		if ((ncapid & PCI_CONF_CAPID_MASK) ==
923446Smrj 		    AGP_CAP_ID) /* The AGP cap was found */
933446Smrj 			break;
943446Smrj 
953446Smrj 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
963446Smrj 	}
973446Smrj 
983446Smrj 	return (nextcap);
993446Smrj 
1003446Smrj }
1013446Smrj 
1023446Smrj /*
1033446Smrj  * agp_target_get_aperbase()
1043446Smrj  *
1053446Smrj  * Description:
1063446Smrj  * 	This function gets the AGP aperture base address from the AGP target
1073446Smrj  *	register, the AGP aperture base register was programmed by the BIOS.
1083446Smrj  *
1093446Smrj  * Arguments:
1103446Smrj  * 	softstate		driver soft state pointer
1113446Smrj  *
1123446Smrj  * Returns:
1133446Smrj  * 	aper_base 		AGP aperture base address
1143446Smrj  *
1153446Smrj  * Notes:
1163446Smrj  * 	If a 64bit bridge device is available, the AGP aperture base address
1173446Smrj  * 	can be 64 bit.
1183446Smrj  */
1193446Smrj static uint64_t
1203446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate)
1213446Smrj {
1223446Smrj 	uint64_t aper_base;
1233446Smrj 
1243446Smrj 	if (!is_64bit_aper(softstate)) {
1253446Smrj 		aper_base = pci_config_get32(softstate->tsoft_pcihdl,
1263446Smrj 		    AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK;
1273446Smrj 	} else {
1283446Smrj 		aper_base = pci_config_get64(softstate->tsoft_pcihdl,
1293446Smrj 		    AGP_CONF_APERBASE);
1303446Smrj 		/* 32-bit or 64-bit aperbase base pointer */
1313446Smrj 		if ((aper_base & AGP_APER_TYPE_MASK) == 0)
1323446Smrj 			aper_base &= AGP_32_APERBASE_MASK;
1333446Smrj 		else
1343446Smrj 			aper_base &= AGP_64_APERBASE_MASK;
1353446Smrj 	}
1363446Smrj 	return (aper_base);
1373446Smrj }
1383446Smrj 
1393446Smrj /*
1403446Smrj  * agp_target_get_apsize()
1413446Smrj  *
1423446Smrj  * Description:
1433446Smrj  * 	This function gets the AGP aperture size by reading the AGP aperture
1443446Smrj  * 	size register.
1453446Smrj  * Arguments:
1463446Smrj  * 	softstate		driver soft state pointer
1473446Smrj  *
1483446Smrj  * Return:
1493446Smrj  * 	size		The AGP aperture size in megabytes
1503446Smrj  * 	0		an unexpected error
1513446Smrj  */
1523446Smrj static size_t
1533446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate)
1543446Smrj {
1553446Smrj 	off_t cap;
1563446Smrj 	uint16_t value;
1573446Smrj 	size_t size, regsize;
1583446Smrj 
1593446Smrj 	ASSERT(softstate->tsoft_acaptr);
1603446Smrj 	cap = softstate->tsoft_acaptr;
1613446Smrj 
1623446Smrj 	if ((softstate->tsoft_devid & VENDOR_ID_MASK) == INTEL_VENDOR_ID) {
1633446Smrj 		/* extend this value to 16 bit for later tests */
1643446Smrj 		value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl,
1653446Smrj 		    cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK;
1663446Smrj 	} else {
1673446Smrj 		value = pci_config_get16(softstate->tsoft_pcihdl,
1683446Smrj 		    cap + AGP_CONF_APERSIZE);
1693446Smrj 	}
1703446Smrj 
1713446Smrj 	if (value & AGP_APER_128M_MASK) {
1723446Smrj 		switch (value & AGP_APER_128M_MASK) {
1733446Smrj 			case AGP_APER_4M:
1743446Smrj 				size = 4; /* 4M */
1753446Smrj 				break;
1763446Smrj 			case AGP_APER_8M:
1773446Smrj 				size = 8; /* 8M */
1783446Smrj 				break;
1793446Smrj 			case AGP_APER_16M:
1803446Smrj 				size = 16; /* 16M */
1813446Smrj 				break;
1823446Smrj 			case AGP_APER_32M:
1833446Smrj 				size = 32; /* 32M */
1843446Smrj 				break;
1853446Smrj 			case AGP_APER_64M:
1863446Smrj 				size = 64; /* 64M */
1873446Smrj 				break;
1883446Smrj 			case AGP_APER_128M:
1893446Smrj 				size = 128; /* 128M */
1903446Smrj 				break;
1913446Smrj 			default:
1923446Smrj 				size = 0; /* not true */
1933446Smrj 		}
1943446Smrj 	} else {
1953446Smrj 		switch (value & AGP_APER_4G_MASK) {
1963446Smrj 			case AGP_APER_256M:
1973446Smrj 				size = 256; /* 256 M */
1983446Smrj 				break;
1993446Smrj 			case AGP_APER_512M:
2003446Smrj 				size = 512; /* 512 M */
2013446Smrj 				break;
2023446Smrj 			case AGP_APER_1024M:
2033446Smrj 				size = 1024; /* 1024 M */
2043446Smrj 				break;
2053446Smrj 			case AGP_APER_2048M:
2063446Smrj 				size = 2048; /* 2048 M */
2073446Smrj 				break;
2083446Smrj 			case AGP_APER_4G:
2093446Smrj 				size = 4096; /* 4096 M */
2103446Smrj 				break;
2113446Smrj 			default:
2123446Smrj 				size = 0; /* not true */
2133446Smrj 		}
2143446Smrj 	}
2153446Smrj 	/*
2163446Smrj 	 * In some cases, there is no APSIZE register, so the size value
2173446Smrj 	 * of 256M could be wrong. Check the value by reading the size of
2183446Smrj 	 * the first register which was set in the PCI configuration space.
2193446Smrj 	 */
2203446Smrj 	if (size == 256) {
2213446Smrj 		if (ddi_dev_regsize(softstate->tsoft_dip,
2223446Smrj 		    AGP_TARGET_BAR1, (off_t *)&regsize) == DDI_FAILURE)
2233446Smrj 			return (0);
2243446Smrj 
2253446Smrj 		if (MB2BYTES(size) != regsize) {
2263446Smrj 			TARGETDB_PRINT2((CE_WARN,
2273446Smrj 			    "APSIZE 256M doesn't match regsize %lx",
2283446Smrj 			    regsize));
2293446Smrj 			TARGETDB_PRINT2((CE_WARN, "Use regsize instead"));
2303446Smrj 			size = BYTES2MB(regsize);
2313446Smrj 		}
2323446Smrj 	}
2333446Smrj 
2343446Smrj 	return (size);
2353446Smrj }
2363446Smrj 
2373446Smrj static void
2383446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr)
2393446Smrj {
2403446Smrj 	ASSERT(softstate->tsoft_acaptr);
2413446Smrj 
2423446Smrj 	/* Disable the GTLB for Intel chipsets */
2433446Smrj 	pci_config_put16(softstate->tsoft_pcihdl,
2443446Smrj 	    softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000);
2453446Smrj 
2463446Smrj 	pci_config_put32(softstate->tsoft_pcihdl,
2473446Smrj 	    softstate->tsoft_acaptr + AGP_CONF_ATTBASE,
2483446Smrj 	    gartaddr & AGP_ATTBASE_MASK);
2493446Smrj }
2503446Smrj 
2513446Smrj static size_t
2523446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate)
2533446Smrj {
2543446Smrj 	uint8_t memval;
2553446Smrj 	size_t kbytes;
2563446Smrj 
2573446Smrj 	switch (softstate->tsoft_devid) {
2583446Smrj 	case INTEL_BR_810:
2593446Smrj 	case INTEL_BR_810DC:
2603446Smrj 	case INTEL_BR_810E:
2613446Smrj 		memval = pci_config_get8(softstate->tsoft_pcihdl,
2623446Smrj 		    I810_CONF_SMRAM);
2633446Smrj 		switch (memval & I810_GMS_MASK) {
2643446Smrj 		case 0x80:
2653446Smrj 			kbytes = 512; /* 512K preallocated memory */
2663446Smrj 			break;
2673446Smrj 		case 0xc0:
2683446Smrj 			kbytes = 1024; /* 1024K preallocated memory */
2693446Smrj 			break;
2703446Smrj 		default:
2713446Smrj 			kbytes = 0; /* an unexpected case */
2723446Smrj 		}
2733446Smrj 		break;
2743446Smrj 	case INTEL_BR_830M:
2753446Smrj 	case INTEL_BR_845:
2763446Smrj 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
2773446Smrj 		switch (memval & I8XX_GC_MODE_MASK) {
2783446Smrj 		case I8XX_GC_MODE2:
2793446Smrj 			kbytes = 512; /* 512K preallocated memory */
2803446Smrj 			break;
2813446Smrj 		case I8XX_GC_MODE3:
2823446Smrj 			kbytes = 1024; /* 1M preallocated memory */
2833446Smrj 			break;
2843446Smrj 		case I8XX_GC_MODE4:
2853446Smrj 			kbytes = 8 * 1024; /* 8M preallocated memory */
2863446Smrj 			break;
2873446Smrj 		default:
2883446Smrj 			kbytes = 0; /* an unexpected case */
2893446Smrj 		}
2903446Smrj 		break;
2913446Smrj 	case INTEL_BR_855GM:
2923446Smrj 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
2933446Smrj 		switch (memval & I8XX_GC_MODE_MASK) {
2943446Smrj 		case I8XX_GC_MODE1:
2953446Smrj 			kbytes = 1024; /* 1M preallocated memory */
2963446Smrj 			break;
2973446Smrj 		case I8XX_GC_MODE2:
2983446Smrj 			kbytes = 4 * 1024; /* 4M preallocated memory */
2993446Smrj 			break;
3003446Smrj 		case I8XX_GC_MODE3:
3013446Smrj 			kbytes = 8 * 1024; /* 8M preallocated memory */
3023446Smrj 			break;
3033446Smrj 		case I8XX_GC_MODE4:
3043446Smrj 			kbytes = 16 * 1024; /* 16M preallocated memory */
3053446Smrj 			break;
3063446Smrj 		case I8XX_GC_MODE5:
3073446Smrj 			kbytes = 32 * 1024; /* 32M preallocated memory */
3083446Smrj 			break;
3093446Smrj 		default:
3103446Smrj 			kbytes = 0; /* an unexpected case */
3113446Smrj 		}
3123446Smrj 		break;
3133446Smrj 	case INTEL_BR_865:
3143527Sms148562 	case INTEL_BR_910M:
3153446Smrj 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
3163446Smrj 		switch (memval & I8XX_GC_MODE_MASK) {
3173446Smrj 		case I8XX_GC_MODE1:
3183446Smrj 			kbytes = 1024; /* 1M preallocated memory */
3193446Smrj 			break;
3203446Smrj 		case I8XX_GC_MODE3:
3213446Smrj 			kbytes = 8 * 1024; /* 8M preallocated memory */
3223446Smrj 			break;
3233527Sms148562 		/*
3243527Sms148562 		 * There is no option for 16M in 910GM datasheet,
3253527Sms148562 		 * but some BIOS add this option for 16M support.
3263527Sms148562 		 */
3273446Smrj 		case I8XX_GC_MODE4:
3283446Smrj 			kbytes = 16 * 1024; /* 16M preallocated memory */
3293446Smrj 			break;
3303446Smrj 		default:
3313446Smrj 			kbytes = 0; /* an unexpected case */
3323446Smrj 		}
3333446Smrj 		break;
3343446Smrj 	case INTEL_BR_910:
3353446Smrj 	case INTEL_BR_945:
336*4303Skz151634 	case INTEL_BR_945GM:
3373446Smrj 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
3383446Smrj 		switch (memval & I8XX_GC_MODE_MASK) {
3393446Smrj 		case I8XX_GC_MODE1:
3403446Smrj 			kbytes = 1024; /* 1M preallocated memory */
3413446Smrj 			break;
3423446Smrj 		case I8XX_GC_MODE3:
3433446Smrj 			kbytes = 8 * 1024; /* 8M preallocated memory */
3443446Smrj 			break;
3453446Smrj 		default:
3463446Smrj 			kbytes = 0; /* an unexpected case */
3473446Smrj 		}
3483446Smrj 		break;
3493446Smrj 	default:
3503446Smrj 		kbytes = 0;
3513446Smrj 	}
3523446Smrj 
3533446Smrj 	return (kbytes);
3543446Smrj }
3553446Smrj 
3563446Smrj /*ARGSUSED*/
3573446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
3583446Smrj     void *arg, void **resultp)
3593446Smrj {
3603446Smrj 	agp_target_softstate_t *st;
3613446Smrj 	int instance, rval = DDI_FAILURE;
3623446Smrj 	dev_t dev;
3633446Smrj 
3643446Smrj 	switch (cmd) {
3653446Smrj 	case DDI_INFO_DEVT2DEVINFO:
3663446Smrj 		dev = (dev_t)arg;
3673446Smrj 		instance = DEV2INST(dev);
3683446Smrj 		st = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
3693446Smrj 		if (st != NULL) {
3703446Smrj 			mutex_enter(&st->tsoft_lock);
3713446Smrj 			*resultp = st->tsoft_dip;
3723446Smrj 			mutex_exit(&st->tsoft_lock);
3733446Smrj 			rval = DDI_SUCCESS;
3743446Smrj 		} else
3753446Smrj 			*resultp = NULL;
3763446Smrj 
3773446Smrj 		break;
3783446Smrj 	case DDI_INFO_DEVT2INSTANCE:
3793446Smrj 		dev = (dev_t)arg;
3803446Smrj 		instance = DEV2INST(dev);
3813446Smrj 		*resultp = (void *)(uintptr_t)instance;
3823446Smrj 		rval = DDI_SUCCESS;
3833446Smrj 	default:
3843446Smrj 		break;
3853446Smrj 	}
3863446Smrj 
3873446Smrj 	return (rval);
3883446Smrj }
3893446Smrj 
3903446Smrj static int
3913446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3923446Smrj {
3933446Smrj 	agp_target_softstate_t *softstate;
3943446Smrj 	int instance;
3953446Smrj 	int status;
3963446Smrj 
3973446Smrj 	if (cmd != DDI_ATTACH)
3983446Smrj 		return (DDI_FAILURE);
3993446Smrj 
4003446Smrj 	instance = ddi_get_instance(dip);
4013446Smrj 
4023446Smrj 	if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) !=
4033446Smrj 	    DDI_SUCCESS)
4043446Smrj 		return (DDI_FAILURE);
4053446Smrj 
4063446Smrj 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
4073446Smrj 	mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL);
4083446Smrj 	softstate->tsoft_dip = dip;
4093446Smrj 	status = pci_config_setup(dip, &softstate->tsoft_pcihdl);
4103446Smrj 	if (status != DDI_SUCCESS) {
4113446Smrj 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
4123446Smrj 		return (DDI_FAILURE);
4133446Smrj 	}
4143446Smrj 
4153446Smrj 	softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl,
4163446Smrj 	    PCI_CONF_VENID);
4173446Smrj 	softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl);
4183446Smrj 	if (softstate->tsoft_acaptr == 0) {
4193446Smrj 		/* Make a correction for some Intel chipsets */
4203446Smrj 		if ((softstate->tsoft_devid & VENDOR_ID_MASK) ==
4213446Smrj 		    INTEL_VENDOR_ID)
4223446Smrj 			softstate->tsoft_acaptr = AGP_CAP_OFF_DEF;
4233446Smrj 		else
4243446Smrj 			return (DDI_FAILURE);
4253446Smrj 	}
4263446Smrj 
4273446Smrj 	status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR,
4283446Smrj 	    INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0);
4293446Smrj 
4303446Smrj 	if (status != DDI_SUCCESS) {
4313446Smrj 		pci_config_teardown(&softstate->tsoft_pcihdl);
4323446Smrj 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
4333446Smrj 		return (DDI_FAILURE);
4343446Smrj 	}
4353446Smrj 
4363446Smrj 	return (DDI_SUCCESS);
4373446Smrj }
4383446Smrj 
4393446Smrj /*ARGSUSED*/
4403446Smrj static int
4413446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4423446Smrj {
4433446Smrj 	int instance;
4443446Smrj 	agp_target_softstate_t *softstate;
4453446Smrj 
4463446Smrj 	if (cmd != DDI_DETACH)
4473446Smrj 		return (DDI_FAILURE);
4483446Smrj 
4493446Smrj 	instance = ddi_get_instance(dip);
4503446Smrj 
4513446Smrj 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
4523446Smrj 
4533446Smrj 	ddi_remove_minor_node(dip, AGPTARGET_NAME);
4543446Smrj 	pci_config_teardown(&softstate->tsoft_pcihdl);
4553446Smrj 	mutex_destroy(&softstate->tsoft_lock);
4563446Smrj 	ddi_soft_state_free(agptarget_glob_soft_handle, instance);
4573446Smrj 	return (DDI_SUCCESS);
4583446Smrj }
4593446Smrj 
4603446Smrj /*ARGSUSED*/
4613446Smrj static int
4623446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
4633446Smrj     cred_t *cred, int *rval)
4643446Smrj {
4653446Smrj 	int instance = DEV2INST(dev);
4663446Smrj 	agp_target_softstate_t *st;
4673446Smrj 	static char kernel_only[] =
4683446Smrj 	    "amd64_gart_ioctl: is a kernel only ioctl";
4693446Smrj 
4703446Smrj 	if (!(mode & FKIOCTL)) {
4713446Smrj 		TARGETDB_PRINT2((CE_CONT, kernel_only));
4723446Smrj 		return (ENXIO);
4733446Smrj 	}
4743446Smrj 	st = GETSOFTC(instance);
4753446Smrj 
4763446Smrj 	if (st == NULL)
4773446Smrj 		return (ENXIO);
4783446Smrj 
4793446Smrj 	mutex_enter(&st->tsoft_lock);
4803446Smrj 
4813446Smrj 	switch (cmd) {
4823446Smrj 	case CHIP_DETECT:
4833446Smrj 	{
4843446Smrj 		int type;
4853446Smrj 		switch (st->tsoft_devid & VENDOR_ID_MASK) {
4863446Smrj 		case INTEL_VENDOR_ID:
4873446Smrj 			type = CHIP_IS_INTEL;
4883446Smrj 			break;
4893446Smrj 		case AMD_VENDOR_ID:
4903446Smrj 			type = CHIP_IS_AMD;
4913446Smrj 			break;
4923446Smrj 		default:
4933446Smrj 			type = 0;
4943446Smrj 		}
4953446Smrj 		if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) {
4963446Smrj 			mutex_exit(&st->tsoft_lock);
4973446Smrj 			return (EFAULT);
4983446Smrj 		}
4993446Smrj 
5003446Smrj 		break;
5013446Smrj 	}
5023446Smrj 	case I8XX_GET_PREALLOC_SIZE:
5033446Smrj 	{
5043446Smrj 		size_t prealloc_size;
5053446Smrj 
5063446Smrj 		if ((st->tsoft_devid & VENDOR_ID_MASK) !=
5073446Smrj 		    INTEL_VENDOR_ID) {
5083446Smrj 			mutex_exit(&st->tsoft_lock);
5093446Smrj 			return (EINVAL);
5103446Smrj 		}
5113446Smrj 
5123446Smrj 		prealloc_size = i8xx_biosmem_detect(st);
5133446Smrj 		if (ddi_copyout(&prealloc_size, (void *)data,
5143446Smrj 		    sizeof (size_t), mode)) {
5153446Smrj 			mutex_exit(&st->tsoft_lock);
5163446Smrj 			return (EFAULT);
5173446Smrj 		}
5183446Smrj 
5193446Smrj 		break;
5203446Smrj 	}
5213446Smrj 	case AGP_TARGET_GETINFO:
5223446Smrj 	{
5233446Smrj 		i_agp_info_t info;
5243446Smrj 		uint32_t value;
5253446Smrj 		off_t cap;
5263446Smrj 
5273446Smrj 		ASSERT(st->tsoft_acaptr);
5283446Smrj 
5293446Smrj 		cap = st->tsoft_acaptr;
5303446Smrj 		value = pci_config_get32(st->tsoft_pcihdl, cap);
5313446Smrj 		info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf);
5323446Smrj 		info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf);
5333446Smrj 		info.iagp_devid = st->tsoft_devid;
5343446Smrj 		info.iagp_mode = pci_config_get32(st->tsoft_pcihdl,
535*4303Skz151634 		    cap + AGP_CONF_STATUS);
5363446Smrj 		info.iagp_aperbase = agp_target_get_apbase(st);
5373446Smrj 		info.iagp_apersize = agp_target_get_apsize(st);
5383446Smrj 
5393446Smrj 		if (ddi_copyout(&info, (void *)data,
5403446Smrj 		    sizeof (i_agp_info_t), mode)) {
5413446Smrj 			mutex_exit(&st->tsoft_lock);
5423446Smrj 			return (EFAULT);
5433446Smrj 		}
5443446Smrj 		break;
5453446Smrj 
5463446Smrj 	}
5473446Smrj 	/*
5483446Smrj 	 * This ioctl is only for Intel AGP chipsets.
5493446Smrj 	 * It is not necessary for the AMD8151 AGP bridge, because
5503446Smrj 	 * this register in the AMD8151 does not control any hardware.
5513446Smrj 	 * It is only provided for compatibility with an Intel AGP bridge.
5523446Smrj 	 * Please refer to the <<AMD8151 data sheet>> page 24,
5533446Smrj 	 * AGP device GART pointer.
5543446Smrj 	 */
5553446Smrj 	case AGP_TARGET_SET_GATTADDR:
5563446Smrj 	{
5573446Smrj 		uint32_t gartaddr;
5583446Smrj 
5593446Smrj 		if (ddi_copyin((void *)data, &gartaddr,
5603446Smrj 		    sizeof (uint32_t), mode)) {
5613446Smrj 			mutex_exit(&st->tsoft_lock);
5623446Smrj 			return (EFAULT);
5633446Smrj 		}
5643446Smrj 
5653446Smrj 		agp_target_set_gartaddr(st, gartaddr);
5663446Smrj 		break;
5673446Smrj 	}
5683446Smrj 	case AGP_TARGET_SETCMD:
5693446Smrj 	{
5703446Smrj 		uint32_t command;
5713446Smrj 
5723446Smrj 		if (ddi_copyin((void *)data, &command,
5733446Smrj 		    sizeof (uint32_t), mode)) {
5743446Smrj 			mutex_exit(&st->tsoft_lock);
5753446Smrj 			return (EFAULT);
5763446Smrj 		}
5773446Smrj 
5783446Smrj 		ASSERT(st->tsoft_acaptr);
5793446Smrj 
5803446Smrj 		pci_config_put32(st->tsoft_pcihdl,
5813446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
5823446Smrj 		    command);
5833446Smrj 		break;
5843446Smrj 
5853446Smrj 	}
5863446Smrj 	case AGP_TARGET_FLUSH_GTLB:
5873446Smrj 	{
5883446Smrj 		uint16_t value;
5893446Smrj 
5903446Smrj 		ASSERT(st->tsoft_acaptr);
5913446Smrj 
5923446Smrj 		value = pci_config_get16(st->tsoft_pcihdl,
5933446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL);
5943446Smrj 		value &= ~AGPCTRL_GTLBEN;
5953446Smrj 		pci_config_put16(st->tsoft_pcihdl,
5963446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
5973446Smrj 		value |= AGPCTRL_GTLBEN;
5983446Smrj 		pci_config_put16(st->tsoft_pcihdl,
5993446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
6003446Smrj 
6013446Smrj 		break;
6023446Smrj 	}
6033446Smrj 	case AGP_TARGET_CONFIGURE:
6043446Smrj 	{
6053446Smrj 		uint8_t value;
6063446Smrj 
6073446Smrj 		ASSERT(st->tsoft_acaptr);
6083446Smrj 
6093446Smrj 		value = pci_config_get8(st->tsoft_pcihdl,
6103446Smrj 		    st->tsoft_acaptr + AGP_CONF_MISC);
6113446Smrj 		value |= AGP_MISC_APEN;
6123446Smrj 		pci_config_put8(st->tsoft_pcihdl,
6133446Smrj 		    st->tsoft_acaptr + AGP_CONF_MISC, value);
6143446Smrj 		break;
6153446Smrj 
6163446Smrj 	}
6173446Smrj 	case AGP_TARGET_UNCONFIG:
6183446Smrj 	{
6193446Smrj 		uint32_t value1;
6203446Smrj 		uint8_t value2;
6213446Smrj 
6223446Smrj 		ASSERT(st->tsoft_acaptr);
6233446Smrj 
6243446Smrj 		pci_config_put16(st->tsoft_pcihdl,
6253446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0);
6263446Smrj 
6273446Smrj 		value2 = pci_config_get8(st->tsoft_pcihdl,
6283446Smrj 		    st->tsoft_acaptr + AGP_CONF_MISC);
6293446Smrj 		value2 &= ~AGP_MISC_APEN;
6303446Smrj 		pci_config_put8(st->tsoft_pcihdl,
6313446Smrj 		    st->tsoft_acaptr + AGP_CONF_MISC, value2);
6323446Smrj 
6333446Smrj 		value1 = pci_config_get32(st->tsoft_pcihdl,
6343446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND);
6353446Smrj 		value1 &= ~AGPCMD_AGPEN;
6363446Smrj 		pci_config_put32(st->tsoft_pcihdl,
6373446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
6383446Smrj 		    value1);
6393446Smrj 
6403446Smrj 		pci_config_put32(st->tsoft_pcihdl,
6413446Smrj 		    st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0);
6423446Smrj 
6433446Smrj 		break;
6443446Smrj 	}
6453446Smrj 
6463446Smrj 	default:
6473446Smrj 		mutex_exit(&st->tsoft_lock);
6483446Smrj 		return (ENXIO);
6493446Smrj 	} /* end switch */
6503446Smrj 
6513446Smrj 	mutex_exit(&st->tsoft_lock);
6523446Smrj 
6533446Smrj 	return (0);
6543446Smrj }
6553446Smrj 
6563446Smrj /*ARGSUSED*/
6573446Smrj static int
6583446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred)
6593446Smrj {
6603446Smrj 	int instance = DEV2INST(*devp);
6613446Smrj 	agp_target_softstate_t *st;
6623446Smrj 
6633446Smrj 	if (!(flag & FKLYR))
6643446Smrj 		return (ENXIO);
6653446Smrj 
6663446Smrj 	st = GETSOFTC(instance);
6673446Smrj 
6683446Smrj 	if (st == NULL)
6693446Smrj 		return (ENXIO);
6703446Smrj 
6713446Smrj 	return (0);
6723446Smrj }
6733446Smrj 
6743446Smrj /*ARGSUSED*/
6753446Smrj static int
6763446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred)
6773446Smrj {
6783446Smrj 	int instance = DEV2INST(dev);
6793446Smrj 	agp_target_softstate_t *st;
6803446Smrj 
6813446Smrj 	st = GETSOFTC(instance);
6823446Smrj 
6833446Smrj 	if (st == NULL)
6843446Smrj 		return (ENXIO);
6853446Smrj 
6863446Smrj 	return (0);
6873446Smrj }
6883446Smrj 
6893446Smrj static  struct  cb_ops  agp_target_cb_ops = {
6903446Smrj 	agp_target_open,		/* cb_open */
6913446Smrj 	agp_target_close,		/* cb_close */
6923446Smrj 	nodev,				/* cb_strategy */
6933446Smrj 	nodev,				/* cb_print */
6943446Smrj 	nodev,				/* cb_dump */
6953446Smrj 	nodev,				/* cb_read() */
6963446Smrj 	nodev,				/* cb_write() */
6973446Smrj 	agp_target_ioctl,		/* cb_ioctl */
6983446Smrj 	nodev,				/* cb_devmap */
6993446Smrj 	nodev,				/* cb_mmap */
7003446Smrj 	nodev,				/* cb_segmap */
7013446Smrj 	nochpoll,			/* cb_chpoll */
7023446Smrj 	ddi_prop_op,			/* cb_prop_op */
7033446Smrj 	0,				/* cb_stream */
7043446Smrj 	D_NEW | D_MP, 			/* cb_flag */
7053446Smrj 	CB_REV,				/* cb_ops version? */
7063446Smrj 	nodev,				/* cb_aread() */
7073446Smrj 	nodev,				/* cb_awrite() */
7083446Smrj };
7093446Smrj 
7103446Smrj /* device operations */
7113446Smrj static struct dev_ops agp_target_ops = {
7123446Smrj 	DEVO_REV,		/* devo_rev */
7133446Smrj 	0,			/* devo_refcnt */
7143446Smrj 	agptarget_getinfo, 	/* devo_getinfo */
7153446Smrj 	nulldev,		/* devo_identify */
7163446Smrj 	nulldev,		/* devo_probe */
7173446Smrj 	agp_target_attach,	/* devo_attach */
7183446Smrj 	agp_target_detach,	/* devo_detach */
7193446Smrj 	nodev,			/* devo_reset */
7203446Smrj 	&agp_target_cb_ops,	/* devo_cb_ops */
7213446Smrj 	0,			/* devo_bus_ops */
7223446Smrj 	0,			/* devo_power */
7233446Smrj };
7243446Smrj 
7253446Smrj static  struct modldrv modldrv = {
7263446Smrj 	&mod_driverops,
7273446Smrj 	"AGP target driver v%I%",
7283446Smrj 	&agp_target_ops,
7293446Smrj };
7303446Smrj 
7313446Smrj static  struct modlinkage modlinkage = {
7323446Smrj 	MODREV_1,		/* MODREV_1 is indicated by manual */
7333446Smrj 	{&modldrv, NULL, NULL, NULL}
7343446Smrj };
7353446Smrj 
7363446Smrj int
7373446Smrj _init(void)
7383446Smrj {
7393446Smrj 	int ret;
7403446Smrj 
7413446Smrj 	ret = ddi_soft_state_init(&agptarget_glob_soft_handle,
7423446Smrj 	    sizeof (agp_target_softstate_t), 1);
7433446Smrj 
7443446Smrj 	if (ret)
7453446Smrj 		goto err1;
7463446Smrj 
7473446Smrj 	if ((ret = mod_install(&modlinkage)) != 0) {
7483446Smrj 		goto err2;
7493446Smrj 	}
7503446Smrj 
7513446Smrj 	return (DDI_SUCCESS);
7523446Smrj err2:
7533446Smrj 	ddi_soft_state_fini(&agptarget_glob_soft_handle);
7543446Smrj err1:
7553446Smrj 	return (ret);
7563446Smrj }
7573446Smrj 
7583446Smrj int
7593446Smrj _info(struct  modinfo *modinfop)
7603446Smrj {
7613446Smrj 	return (mod_info(&modlinkage, modinfop));
7623446Smrj }
7633446Smrj 
7643446Smrj int
7653446Smrj _fini(void)
7663446Smrj {
7673446Smrj 	int	ret;
7683446Smrj 
7693446Smrj 	if ((ret = mod_remove(&modlinkage)) == 0) {
7703446Smrj 		ddi_soft_state_fini(&agptarget_glob_soft_handle);
7713446Smrj 	}
7723446Smrj 	return (ret);
7733446Smrj }
774