xref: /onnv-gate/usr/src/uts/intel/io/agpgart/agptarget.c (revision 11359:522bdb2b850d)
14478Skz151634 /*
24478Skz151634  * CDDL HEADER START
34478Skz151634  *
44478Skz151634  * The contents of this file are subject to the terms of the
54478Skz151634  * Common Development and Distribution License (the "License").
64478Skz151634  * You may not use this file except in compliance with the License.
74478Skz151634  *
84478Skz151634  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94478Skz151634  * or http://www.opensolaris.org/os/licensing.
104478Skz151634  * See the License for the specific language governing permissions
114478Skz151634  * and limitations under the License.
124478Skz151634  *
134478Skz151634  * When distributing Covered Code, include this CDDL HEADER in each
144478Skz151634  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154478Skz151634  * If applicable, add the following below this CDDL HEADER, with the
164478Skz151634  * fields enclosed by brackets "[]" replaced with your own identifying
174478Skz151634  * information: Portions Copyright [yyyy] [name of copyright owner]
184478Skz151634  *
194478Skz151634  * CDDL HEADER END
204478Skz151634  */
214478Skz151634 
223446Smrj /*
2311260SMiao.Chen@Sun.COM  * Copyright (c) 2009, Intel Corporation.
2411260SMiao.Chen@Sun.COM  * All Rights Reserved.
2511260SMiao.Chen@Sun.COM  */
2611260SMiao.Chen@Sun.COM 
2711260SMiao.Chen@Sun.COM /*
288832SMiao.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
293446Smrj  * Use is subject to license terms.
303446Smrj  */
313446Smrj 
323446Smrj 
333446Smrj #include <sys/systm.h>
343446Smrj #include <sys/conf.h>
353446Smrj #include <sys/modctl.h>
363446Smrj #include <sys/file.h>
373446Smrj #include <sys/stat.h>
383446Smrj #include <sys/ddi.h>
393446Smrj #include <sys/sunddi.h>
4011260SMiao.Chen@Sun.COM #include <sys/sunndi.h>
413446Smrj #include <sys/modctl.h>
423446Smrj #include <sys/sunldi.h>
433446Smrj #include <sys/pci.h>
443446Smrj #include <sys/agpgart.h>
453446Smrj #include <sys/agp/agpdefs.h>
463446Smrj #include <sys/agp/agptarget_io.h>
473446Smrj 
483446Smrj int agptarget_debug_var = 0;
493446Smrj #define	TARGETDB_PRINT2(fmt)	if (agptarget_debug_var >= 1) cmn_err fmt
503446Smrj #define	INST2NODENUM(inst)	(inst)
513446Smrj #define	DEV2INST(dev)		(getminor(dev))
523446Smrj 
5311260SMiao.Chen@Sun.COM static ddi_device_acc_attr_t dev_attr = {
5411260SMiao.Chen@Sun.COM 	DDI_DEVICE_ATTR_V0,
5511260SMiao.Chen@Sun.COM 	DDI_NEVERSWAP_ACC,
5611260SMiao.Chen@Sun.COM 	DDI_STRICTORDER_ACC,
5711260SMiao.Chen@Sun.COM };
5811260SMiao.Chen@Sun.COM 
5911260SMiao.Chen@Sun.COM static struct _i9xx_private_compat {
6011260SMiao.Chen@Sun.COM 	uint64_t	physical;	/* physical address */
6111260SMiao.Chen@Sun.COM 	uint_t	size;	/* size of mapping */
6211260SMiao.Chen@Sun.COM 	uint_t	regnum;	/* register number */
6311260SMiao.Chen@Sun.COM 	caddr_t	flush_page;	/* kernel virtual address */
6411260SMiao.Chen@Sun.COM 	ddi_acc_handle_t	handle; /* data access handle */
65*11359SMiao.Chen@Sun.COM 	uint_t	ra_alloced;
66*11359SMiao.Chen@Sun.COM } i9xx_private = {0, 0, 0, 0, 0, 0};
6711260SMiao.Chen@Sun.COM 
6811260SMiao.Chen@Sun.COM #define	I915_IFPADDR	0x60
6911260SMiao.Chen@Sun.COM #define	I965_IFPADDR	0x70
7011260SMiao.Chen@Sun.COM 
7111260SMiao.Chen@Sun.COM #define	HIADDR(n)	((uint32_t)(((uint64_t)(n) & \
7211260SMiao.Chen@Sun.COM 			0xFFFFFFFF00000000ULL) >> 32))
7311260SMiao.Chen@Sun.COM #define	LOADDR(n)	((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
7411260SMiao.Chen@Sun.COM 
7511260SMiao.Chen@Sun.COM /*
7611260SMiao.Chen@Sun.COM  * Using for GEM to flush the chipset global
7711260SMiao.Chen@Sun.COM  * write buffers on certain intel chipset
7811260SMiao.Chen@Sun.COM  */
7911260SMiao.Chen@Sun.COM 
8011260SMiao.Chen@Sun.COM static void
8111260SMiao.Chen@Sun.COM intel_chipset_flush_setup(dev_info_t *dip,
8211260SMiao.Chen@Sun.COM 		    ddi_acc_handle_t pci_acc_hdl,
8311260SMiao.Chen@Sun.COM 		    int gms_off);
8411260SMiao.Chen@Sun.COM 
853446Smrj typedef struct agp_target_softstate {
863446Smrj 	dev_info_t		*tsoft_dip;
873446Smrj 	ddi_acc_handle_t	tsoft_pcihdl;
883446Smrj 	uint32_t		tsoft_devid;
893446Smrj 	/* The offset of the ACAPID register */
903446Smrj 	off_t			tsoft_acaptr;
913446Smrj 	kmutex_t		tsoft_lock;
927130Sms148562 	int			tsoft_gms_off; /* GMS offset in config */
937130Sms148562 	uint32_t		tsoft_gms;
943446Smrj }agp_target_softstate_t;
953446Smrj 
965036Skz151634 /*
975036Skz151634  * To get the pre-allocated graphics mem size using Graphics Mode Select
985036Skz151634  * (GMS) value.
995036Skz151634  */
1005036Skz151634 typedef struct gms_mode {
1015036Skz151634 	uint32_t	gm_devid;	/* bridge vendor + device id */
1025036Skz151634 	off_t		gm_regoff;	/* mode selection register offset */
1035036Skz151634 	uint32_t	gm_mask;	/* GMS mask */
1045036Skz151634 	uint32_t	gm_num;		/* number of modes in gm_vec */
1055036Skz151634 	int 		*gm_vec;	/* modes array */
1065036Skz151634 } gms_mode_t;
1075036Skz151634 
1083446Smrj static void *agptarget_glob_soft_handle;
1093446Smrj 
1103446Smrj #define	GETSOFTC(instance)	((agp_target_softstate_t *)	\
1113446Smrj     ddi_get_soft_state(agptarget_glob_soft_handle, instance));
1123446Smrj 
1133446Smrj /*
1143446Smrj  * The AMD8151 bridge is the only supported 64 bit hardware
1153446Smrj  */
1163446Smrj static int
1173446Smrj is_64bit_aper(agp_target_softstate_t *softstate)
1183446Smrj {
1193446Smrj 	return (softstate->tsoft_devid == AMD_BR_8151);
1203446Smrj }
1217130Sms148562 
1225131Sms148562 /*
1235131Sms148562  * Check if it is an intel bridge
1245131Sms148562  */
1255131Sms148562 static int
1265131Sms148562 is_intel_br(agp_target_softstate_t *softstate)
1275131Sms148562 {
1285131Sms148562 	return ((softstate->tsoft_devid & VENDOR_ID_MASK) ==
1295131Sms148562 	    INTEL_VENDOR_ID);
1305131Sms148562 }
1313446Smrj 
1323446Smrj /*
1333446Smrj  * agp_target_cap_find()
1343446Smrj  *
1353446Smrj  * Description:
1363446Smrj  * 	This function searches the linked capability list to find the offset
1373446Smrj  * 	of the AGP capability register. When it was not found, return 0.
1383446Smrj  * 	This works for standard AGP chipsets, but not for some Intel chipsets,
1393446Smrj  * 	like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for
1403446Smrj  * 	these chipsets even if AGP is supported. So the offset of acapid
1413446Smrj  * 	should be set manually in thoses cases.
1423446Smrj  *
1433446Smrj  * Arguments:
1443446Smrj  * 	pci_handle		ddi acc handle of pci config
1453446Smrj  *
1463446Smrj  * Returns:
1473446Smrj  * 	0			No capability pointer register found
1483446Smrj  * 	nexcap			The AGP capability pointer register offset
1493446Smrj  */
1503446Smrj static off_t
1513446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle)
1523446Smrj {
1533446Smrj 	off_t		nextcap = 0;
1543446Smrj 	uint32_t	ncapid = 0;
1553446Smrj 	uint8_t		value = 0;
1563446Smrj 
1573446Smrj 	/* Check if this device supports the capability pointer */
1583446Smrj 	value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT)
1593446Smrj 	    & PCI_CONF_CAP_MASK);
1603446Smrj 
1613446Smrj 	if (!value)
1623446Smrj 		return (0);
1633446Smrj 	/* Get the offset of the first capability pointer from CAPPTR */
1643446Smrj 	nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR));
1653446Smrj 
1663446Smrj 	/* Check the AGP capability from the first capability pointer */
1673446Smrj 	while (nextcap) {
1683446Smrj 		ncapid = pci_config_get32(pci_handle, nextcap);
1693446Smrj 		/*
1703446Smrj 		 * AGP3.0 rev1.0 127  the capid was assigned by the PCI SIG,
1713446Smrj 		 * 845 data sheet page 69
1723446Smrj 		 */
1733446Smrj 		if ((ncapid & PCI_CONF_CAPID_MASK) ==
1743446Smrj 		    AGP_CAP_ID) /* The AGP cap was found */
1753446Smrj 			break;
1763446Smrj 
1773446Smrj 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
1783446Smrj 	}
1793446Smrj 
1803446Smrj 	return (nextcap);
1813446Smrj 
1823446Smrj }
1833446Smrj 
1843446Smrj /*
1853446Smrj  * agp_target_get_aperbase()
1863446Smrj  *
1873446Smrj  * Description:
1883446Smrj  * 	This function gets the AGP aperture base address from the AGP target
1893446Smrj  *	register, the AGP aperture base register was programmed by the BIOS.
1903446Smrj  *
1913446Smrj  * Arguments:
1923446Smrj  * 	softstate		driver soft state pointer
1933446Smrj  *
1943446Smrj  * Returns:
1953446Smrj  * 	aper_base 		AGP aperture base address
1963446Smrj  *
1973446Smrj  * Notes:
1983446Smrj  * 	If a 64bit bridge device is available, the AGP aperture base address
1993446Smrj  * 	can be 64 bit.
2003446Smrj  */
2013446Smrj static uint64_t
2023446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate)
2033446Smrj {
2043446Smrj 	uint64_t aper_base;
2053446Smrj 
2065131Sms148562 	if (is_intel_br(softstate)) {
2073446Smrj 		aper_base = pci_config_get32(softstate->tsoft_pcihdl,
2083446Smrj 		    AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK;
2095131Sms148562 	} else if (is_64bit_aper(softstate)) {
2103446Smrj 		aper_base = pci_config_get64(softstate->tsoft_pcihdl,
2113446Smrj 		    AGP_CONF_APERBASE);
2123446Smrj 		/* 32-bit or 64-bit aperbase base pointer */
2133446Smrj 		if ((aper_base & AGP_APER_TYPE_MASK) == 0)
2143446Smrj 			aper_base &= AGP_32_APERBASE_MASK;
2153446Smrj 		else
2163446Smrj 			aper_base &= AGP_64_APERBASE_MASK;
2173446Smrj 	}
2185131Sms148562 
2193446Smrj 	return (aper_base);
2203446Smrj }
2213446Smrj 
2223446Smrj /*
2233446Smrj  * agp_target_get_apsize()
2243446Smrj  *
2253446Smrj  * Description:
2263446Smrj  * 	This function gets the AGP aperture size by reading the AGP aperture
2273446Smrj  * 	size register.
2283446Smrj  * Arguments:
2293446Smrj  * 	softstate		driver soft state pointer
2303446Smrj  *
2313446Smrj  * Return:
2323446Smrj  * 	size		The AGP aperture size in megabytes
2333446Smrj  * 	0		an unexpected error
2343446Smrj  */
2353446Smrj static size_t
2363446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate)
2373446Smrj {
2383446Smrj 	off_t cap;
2393446Smrj 	uint16_t value;
2403446Smrj 	size_t size, regsize;
2413446Smrj 
2423446Smrj 	ASSERT(softstate->tsoft_acaptr);
2433446Smrj 	cap = softstate->tsoft_acaptr;
2443446Smrj 
2455131Sms148562 	if (is_intel_br(softstate)) {
2463446Smrj 		/* extend this value to 16 bit for later tests */
2473446Smrj 		value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl,
2483446Smrj 		    cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK;
2495131Sms148562 	} else if (is_64bit_aper(softstate)) {
2503446Smrj 		value = pci_config_get16(softstate->tsoft_pcihdl,
2513446Smrj 		    cap + AGP_CONF_APERSIZE);
2523446Smrj 	}
2533446Smrj 
2543446Smrj 	if (value & AGP_APER_128M_MASK) {
2553446Smrj 		switch (value & AGP_APER_128M_MASK) {
2563446Smrj 			case AGP_APER_4M:
2573446Smrj 				size = 4; /* 4M */
2583446Smrj 				break;
2593446Smrj 			case AGP_APER_8M:
2603446Smrj 				size = 8; /* 8M */
2613446Smrj 				break;
2623446Smrj 			case AGP_APER_16M:
2633446Smrj 				size = 16; /* 16M */
2643446Smrj 				break;
2653446Smrj 			case AGP_APER_32M:
2663446Smrj 				size = 32; /* 32M */
2673446Smrj 				break;
2683446Smrj 			case AGP_APER_64M:
2693446Smrj 				size = 64; /* 64M */
2703446Smrj 				break;
2713446Smrj 			case AGP_APER_128M:
2723446Smrj 				size = 128; /* 128M */
2733446Smrj 				break;
2743446Smrj 			default:
2753446Smrj 				size = 0; /* not true */
2763446Smrj 		}
2773446Smrj 	} else {
2783446Smrj 		switch (value & AGP_APER_4G_MASK) {
2793446Smrj 			case AGP_APER_256M:
2803446Smrj 				size = 256; /* 256 M */
2813446Smrj 				break;
2823446Smrj 			case AGP_APER_512M:
2833446Smrj 				size = 512; /* 512 M */
2843446Smrj 				break;
2853446Smrj 			case AGP_APER_1024M:
2863446Smrj 				size = 1024; /* 1024 M */
2873446Smrj 				break;
2883446Smrj 			case AGP_APER_2048M:
2893446Smrj 				size = 2048; /* 2048 M */
2903446Smrj 				break;
2913446Smrj 			case AGP_APER_4G:
2923446Smrj 				size = 4096; /* 4096 M */
2933446Smrj 				break;
2943446Smrj 			default:
2953446Smrj 				size = 0; /* not true */
2963446Smrj 		}
2973446Smrj 	}
2983446Smrj 	/*
2993446Smrj 	 * In some cases, there is no APSIZE register, so the size value
3003446Smrj 	 * of 256M could be wrong. Check the value by reading the size of
3013446Smrj 	 * the first register which was set in the PCI configuration space.
3023446Smrj 	 */
3033446Smrj 	if (size == 256) {
3043446Smrj 		if (ddi_dev_regsize(softstate->tsoft_dip,
3053446Smrj 		    AGP_TARGET_BAR1, (off_t *)&regsize) == DDI_FAILURE)
3063446Smrj 			return (0);
3073446Smrj 
3083446Smrj 		if (MB2BYTES(size) != regsize) {
3093446Smrj 			TARGETDB_PRINT2((CE_WARN,
3103446Smrj 			    "APSIZE 256M doesn't match regsize %lx",
3113446Smrj 			    regsize));
3123446Smrj 			TARGETDB_PRINT2((CE_WARN, "Use regsize instead"));
3133446Smrj 			size = BYTES2MB(regsize);
3143446Smrj 		}
3153446Smrj 	}
3163446Smrj 
3173446Smrj 	return (size);
3183446Smrj }
3193446Smrj 
3203446Smrj static void
3213446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr)
3223446Smrj {
3233446Smrj 	ASSERT(softstate->tsoft_acaptr);
3243446Smrj 
3253446Smrj 	/* Disable the GTLB for Intel chipsets */
3263446Smrj 	pci_config_put16(softstate->tsoft_pcihdl,
3273446Smrj 	    softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000);
3283446Smrj 
3293446Smrj 	pci_config_put32(softstate->tsoft_pcihdl,
3303446Smrj 	    softstate->tsoft_acaptr + AGP_CONF_ATTBASE,
3313446Smrj 	    gartaddr & AGP_ATTBASE_MASK);
3323446Smrj }
3333446Smrj 
3345036Skz151634 /*
3355036Skz151634  * Pre-allocated graphics memory for every type of Intel north bridge, mem size
3365036Skz151634  * are specified in kbytes.
3375036Skz151634  */
3385036Skz151634 #define	GMS_MB(n) 	((n) * 1024)
3395036Skz151634 #define	GMS_SHIFT 	4
3405036Skz151634 #define	GMS_SIZE(a)	(sizeof (a) / sizeof (int))
3415036Skz151634 
3425036Skz151634 /*
3435036Skz151634  * Since value zero always means "No memory pre-allocated", value of (GMS - 1)
3445036Skz151634  * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb)
3455036Skz151634  * that GMS value 0x1 corresponding to.
3465036Skz151634  *
3475036Skz151634  * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics
3485036Skz151634  * memory, unless some special BIOS settings exist.
3495036Skz151634  */
3505036Skz151634 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)};
3515036Skz151634 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)};
3525036Skz151634 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
3535036Skz151634 	GMS_MB(32)};
3545036Skz151634 /* There is no modes for 16M in datasheet, but some BIOS add it. */
3555036Skz151634 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)};
3565036Skz151634 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)};
3575036Skz151634 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
3585036Skz151634 	GMS_MB(32), GMS_MB(48), GMS_MB(64)};
3595036Skz151634 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
3605036Skz151634 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)};
3617662SMiao.Chen@Sun.COM static int gms_G4X[13] = {0, 0, 0, 0,
3627662SMiao.Chen@Sun.COM 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256),
3637662SMiao.Chen@Sun.COM 	GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)};
3645036Skz151634 
3655036Skz151634 static gms_mode_t gms_modes[] = {
3665036Skz151634 	{INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK,
3675036Skz151634 		GMS_SIZE(gms_810), gms_810},
3685036Skz151634 	{INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK,
3695036Skz151634 		GMS_SIZE(gms_810), gms_810},
3705036Skz151634 	{INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK,
3715036Skz151634 		GMS_SIZE(gms_810), gms_810},
3725036Skz151634 	{INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3735036Skz151634 		GMS_SIZE(gms_830_845), gms_830_845},
3745036Skz151634 	{INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3755036Skz151634 		GMS_SIZE(gms_830_845), gms_830_845},
3765036Skz151634 	{INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3775036Skz151634 		GMS_SIZE(gms_855GM), gms_855GM},
3785036Skz151634 	{INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3795036Skz151634 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
3805036Skz151634 	{INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3815036Skz151634 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
3825036Skz151634 	{INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3835036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3845036Skz151634 	{INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3855036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3865036Skz151634 	{INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3875036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3888020SMiao.Chen@Sun.COM 	{INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3898020SMiao.Chen@Sun.COM 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3905036Skz151634 	{INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3915036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3925036Skz151634 	{INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3935036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3945036Skz151634 	{INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3955036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3965036Skz151634 	{INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3975036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3985036Skz151634 	{INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3995036Skz151634 		GMS_SIZE(gms_965GM), gms_965GM},
4005036Skz151634 	{INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
4015036Skz151634 		GMS_SIZE(gms_965GM), gms_965GM},
4025036Skz151634 	{INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK,
4035036Skz151634 		GMS_SIZE(gms_X33), gms_X33},
4045036Skz151634 	{INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
4055036Skz151634 		GMS_SIZE(gms_X33), gms_X33},
4065036Skz151634 	{INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
4076778Smc196098 		GMS_SIZE(gms_X33), gms_X33},
4086778Smc196098 	{INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
4097662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_965GM), gms_965GM},
4107662SMiao.Chen@Sun.COM 	{INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
4117662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
4127662SMiao.Chen@Sun.COM 	{INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
4137662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
4147662SMiao.Chen@Sun.COM 	{INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
4158832SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
4168832SMiao.Chen@Sun.COM 	{INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
41711260SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
418*11359SMiao.Chen@Sun.COM 	{INTEL_BR_IGDNG_D, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
419*11359SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
420*11359SMiao.Chen@Sun.COM 	{INTEL_BR_IGDNG_M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
421*11359SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
422*11359SMiao.Chen@Sun.COM 	{INTEL_BR_IGDNG_MA, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
423*11359SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
424*11359SMiao.Chen@Sun.COM 	{INTEL_BR_IGDNG_MC2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
425*11359SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
42611260SMiao.Chen@Sun.COM 	{INTEL_BR_B43, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
4277662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X}
4285036Skz151634 };
4297130Sms148562 static int
4307130Sms148562 get_chip_gms(uint32_t devid)
4317130Sms148562 {
4327130Sms148562 	int num_modes;
4337130Sms148562 	int i;
4347130Sms148562 
4357130Sms148562 	num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t));
4367130Sms148562 
4377130Sms148562 	for (i = 0; i < num_modes; i++) {
4387130Sms148562 		if (gms_modes[i].gm_devid == devid)
4397130Sms148562 			break;
4407130Sms148562 	}
4417130Sms148562 
4427130Sms148562 	return ((i == num_modes) ? -1 : i);
4437130Sms148562 }
4445036Skz151634 
4455036Skz151634 /* Returns the size (kbytes) of pre-allocated graphics memory */
4463446Smrj static size_t
4473446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate)
4483446Smrj {
4493446Smrj 	uint8_t memval;
4503446Smrj 	size_t kbytes;
4517130Sms148562 	int	gms_off;
4523446Smrj 
4535036Skz151634 	kbytes = 0;
4547130Sms148562 	gms_off = softstate->tsoft_gms_off;
4557130Sms148562 
4565036Skz151634 	/* fetch the GMS value from DRAM controller */
4575036Skz151634 	memval = pci_config_get8(softstate->tsoft_pcihdl,
4587130Sms148562 	    gms_modes[gms_off].gm_regoff);
4595036Skz151634 	TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval));
4607130Sms148562 	memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT;
4615036Skz151634 	/* assuming zero byte for 0 or "reserved" GMS values */
4627130Sms148562 	if (memval == 0 || memval > gms_modes[gms_off].gm_num) {
4635036Skz151634 		TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: "
4645036Skz151634 		    "devid = %x, GMS = %x. assuming zero byte of "
4657130Sms148562 		    "pre-allocated memory",
4667130Sms148562 		    gms_modes[gms_off].gm_devid, memval));
4675036Skz151634 		goto done;
4685036Skz151634 	}
4695036Skz151634 	memval--;	/* use (GMS_value - 1) as index */
4707130Sms148562 	kbytes = (gms_modes[gms_off].gm_vec)[memval];
4713446Smrj 
4725036Skz151634 done:
4734478Skz151634 	TARGETDB_PRINT2((CE_NOTE,
4744478Skz151634 	    "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected",
4754478Skz151634 	    kbytes));
4763446Smrj 	return (kbytes);
4773446Smrj }
4783446Smrj 
4793446Smrj /*ARGSUSED*/
4803446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
4813446Smrj     void *arg, void **resultp)
4823446Smrj {
4833446Smrj 	agp_target_softstate_t *st;
4843446Smrj 	int instance, rval = DDI_FAILURE;
4853446Smrj 	dev_t dev;
4863446Smrj 
4873446Smrj 	switch (cmd) {
4883446Smrj 	case DDI_INFO_DEVT2DEVINFO:
4893446Smrj 		dev = (dev_t)arg;
4903446Smrj 		instance = DEV2INST(dev);
4913446Smrj 		st = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
4923446Smrj 		if (st != NULL) {
4933446Smrj 			mutex_enter(&st->tsoft_lock);
4943446Smrj 			*resultp = st->tsoft_dip;
4953446Smrj 			mutex_exit(&st->tsoft_lock);
4963446Smrj 			rval = DDI_SUCCESS;
4973446Smrj 		} else
4983446Smrj 			*resultp = NULL;
4993446Smrj 
5003446Smrj 		break;
5013446Smrj 	case DDI_INFO_DEVT2INSTANCE:
5023446Smrj 		dev = (dev_t)arg;
5033446Smrj 		instance = DEV2INST(dev);
5043446Smrj 		*resultp = (void *)(uintptr_t)instance;
5053446Smrj 		rval = DDI_SUCCESS;
5063446Smrj 	default:
5073446Smrj 		break;
5083446Smrj 	}
5093446Smrj 
5103446Smrj 	return (rval);
5113446Smrj }
5123446Smrj 
5133446Smrj static int
5147130Sms148562 intel_br_resume(agp_target_softstate_t *softstate)
5157130Sms148562 {
5167130Sms148562 	int gms_off;
5177130Sms148562 
5187130Sms148562 	gms_off = softstate->tsoft_gms_off;
5197130Sms148562 
5207130Sms148562 	/*
5217130Sms148562 	 * We recover the gmch graphics control register here
5227130Sms148562 	 */
5237130Sms148562 	pci_config_put16(softstate->tsoft_pcihdl,
5247130Sms148562 	    gms_modes[gms_off].gm_regoff, softstate->tsoft_gms);
5257130Sms148562 
5267130Sms148562 	return (DDI_SUCCESS);
5277130Sms148562 }
5287130Sms148562 static int
5297130Sms148562 intel_br_suspend(agp_target_softstate_t *softstate)
5307130Sms148562 {
5317130Sms148562 	int gms_off;
5327130Sms148562 
5337130Sms148562 	gms_off = softstate->tsoft_gms_off;
5347130Sms148562 	softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl,
5357130Sms148562 	    gms_modes[gms_off].gm_regoff);
5367130Sms148562 
5377130Sms148562 	return (DDI_SUCCESS);
5387130Sms148562 }
5397130Sms148562 
54011260SMiao.Chen@Sun.COM static void
54111260SMiao.Chen@Sun.COM intel_chipset_flush_setup(dev_info_t *dip,
542*11359SMiao.Chen@Sun.COM     ddi_acc_handle_t pci_acc_hdl, int gms_off)
54311260SMiao.Chen@Sun.COM {
54411260SMiao.Chen@Sun.COM 	uint32_t temp_hi, temp_lo;
545*11359SMiao.Chen@Sun.COM 	uint64_t phys_base, phys_len;
54611260SMiao.Chen@Sun.COM 	uint32_t phys_hi_mask = 0;
547*11359SMiao.Chen@Sun.COM 	pci_regspec_t *old_regs = NULL, *new_regs = NULL;
548*11359SMiao.Chen@Sun.COM 	int old_len = 0, new_len = 0;
549*11359SMiao.Chen@Sun.COM 	uint32_t old_regnum, new_regnum;
550*11359SMiao.Chen@Sun.COM 	int circular = 0, prop_updated = 0;
551*11359SMiao.Chen@Sun.COM 	int ret;
55211260SMiao.Chen@Sun.COM 
553*11359SMiao.Chen@Sun.COM 	if (i9xx_private.handle)
554*11359SMiao.Chen@Sun.COM 		return;
55511260SMiao.Chen@Sun.COM 
55611260SMiao.Chen@Sun.COM 	/* IS_I965 || IS_G33 || IS_G4X */
55711260SMiao.Chen@Sun.COM 	if (gms_off > 11) {
558*11359SMiao.Chen@Sun.COM 		temp_hi = pci_config_get32(pci_acc_hdl, I965_IFPADDR + 4);
559*11359SMiao.Chen@Sun.COM 		temp_lo = pci_config_get32(pci_acc_hdl, I965_IFPADDR);
56011260SMiao.Chen@Sun.COM 		phys_hi_mask |= PCI_ADDR_MEM64 | I965_IFPADDR;
56111260SMiao.Chen@Sun.COM 	} else {
562*11359SMiao.Chen@Sun.COM 		temp_lo = pci_config_get32(pci_acc_hdl, I915_IFPADDR);
56311260SMiao.Chen@Sun.COM 		phys_hi_mask |= PCI_ADDR_MEM32 | I915_IFPADDR;
56411260SMiao.Chen@Sun.COM 	}
56511260SMiao.Chen@Sun.COM 
56611260SMiao.Chen@Sun.COM 	if (!(temp_lo & 0x1)) {
567*11359SMiao.Chen@Sun.COM 		ndi_ra_request_t request;
568*11359SMiao.Chen@Sun.COM 
569*11359SMiao.Chen@Sun.COM 		bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
570*11359SMiao.Chen@Sun.COM 		request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED;
571*11359SMiao.Chen@Sun.COM 		request.ra_boundbase = 0;
572*11359SMiao.Chen@Sun.COM 		request.ra_boundlen = 0xffffffff;
573*11359SMiao.Chen@Sun.COM 		request.ra_len = AGP_PAGE_SIZE;
574*11359SMiao.Chen@Sun.COM 
57511260SMiao.Chen@Sun.COM 		/* allocate space from the allocator */
576*11359SMiao.Chen@Sun.COM 		ndi_devi_enter(ddi_get_parent(dip), &circular);
577*11359SMiao.Chen@Sun.COM 		if (ndi_ra_alloc(ddi_get_parent(dip), &request, &phys_base,
578*11359SMiao.Chen@Sun.COM 		    &phys_len, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
579*11359SMiao.Chen@Sun.COM 			TARGETDB_PRINT2((CE_WARN,
580*11359SMiao.Chen@Sun.COM 			    "intel_chipset_flush_setup: "
581*11359SMiao.Chen@Sun.COM 			    "ndi_ra_alloc failed!"));
582*11359SMiao.Chen@Sun.COM 			ndi_devi_exit(ddi_get_parent(dip), circular);
583*11359SMiao.Chen@Sun.COM 			goto error;
58411260SMiao.Chen@Sun.COM 		}
585*11359SMiao.Chen@Sun.COM 		ndi_devi_exit(ddi_get_parent(dip), circular);
586*11359SMiao.Chen@Sun.COM 		i9xx_private.ra_alloced = 1;
587*11359SMiao.Chen@Sun.COM 
588*11359SMiao.Chen@Sun.COM 		TARGETDB_PRINT2((CE_WARN,
589*11359SMiao.Chen@Sun.COM 		    "intel_chipset_flush_setup: "
590*11359SMiao.Chen@Sun.COM 		    "addr = 0x%x.0x%x len [0x%x]\n",
591*11359SMiao.Chen@Sun.COM 		    HIADDR(phys_base), LOADDR(phys_base),
592*11359SMiao.Chen@Sun.COM 		    (uint32_t)phys_len));
59311260SMiao.Chen@Sun.COM 
59411260SMiao.Chen@Sun.COM 		if (gms_off > 11) {
595*11359SMiao.Chen@Sun.COM 			pci_config_put32(pci_acc_hdl, I965_IFPADDR + 4,
596*11359SMiao.Chen@Sun.COM 			    HIADDR(phys_base));
597*11359SMiao.Chen@Sun.COM 			pci_config_put32(pci_acc_hdl, I965_IFPADDR,
598*11359SMiao.Chen@Sun.COM 			    LOADDR(phys_base) | 0x1);
59911260SMiao.Chen@Sun.COM 		} else {
600*11359SMiao.Chen@Sun.COM 			pci_config_put32(pci_acc_hdl, I915_IFPADDR,
601*11359SMiao.Chen@Sun.COM 			    LOADDR(phys_base) | 0x1);
60211260SMiao.Chen@Sun.COM 		}
603*11359SMiao.Chen@Sun.COM 	} else {
60411260SMiao.Chen@Sun.COM 		temp_lo &= ~0x1;
605*11359SMiao.Chen@Sun.COM 		phys_base = ((uint64_t)temp_hi << 32) | temp_lo;
60611260SMiao.Chen@Sun.COM 	}
60711260SMiao.Chen@Sun.COM 
608*11359SMiao.Chen@Sun.COM 	temp_hi = pci_config_get32(pci_acc_hdl, I965_IFPADDR + 4);
609*11359SMiao.Chen@Sun.COM 	temp_lo = pci_config_get32(pci_acc_hdl, I965_IFPADDR);
61011260SMiao.Chen@Sun.COM 
61111260SMiao.Chen@Sun.COM 	/* set pci props */
612*11359SMiao.Chen@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
613*11359SMiao.Chen@Sun.COM 	    "reg", (caddr_t)&old_regs, &old_len) != DDI_PROP_SUCCESS) {
614*11359SMiao.Chen@Sun.COM 		TARGETDB_PRINT2((CE_WARN,
615*11359SMiao.Chen@Sun.COM 		    "intel_chipset_flush_setup: "
616*11359SMiao.Chen@Sun.COM 		    "ddi_getlongprop(1) failed!"));
617*11359SMiao.Chen@Sun.COM 		goto error;
61811260SMiao.Chen@Sun.COM 	}
61911260SMiao.Chen@Sun.COM 
620*11359SMiao.Chen@Sun.COM 	old_regnum = old_len / sizeof (pci_regspec_t);
621*11359SMiao.Chen@Sun.COM 	TARGETDB_PRINT2((CE_WARN,
622*11359SMiao.Chen@Sun.COM 	    "intel_chipset_flush_setup: old_regnum = %d", old_regnum));
62311260SMiao.Chen@Sun.COM 
624*11359SMiao.Chen@Sun.COM 	new_regnum = old_regnum + 1;
625*11359SMiao.Chen@Sun.COM 	new_len = new_regnum * sizeof (pci_regspec_t);
626*11359SMiao.Chen@Sun.COM 	new_regs = kmem_zalloc(new_len, KM_SLEEP);
627*11359SMiao.Chen@Sun.COM 	if (memcpy(new_regs, old_regs, (size_t)old_len) == NULL) {
628*11359SMiao.Chen@Sun.COM 		TARGETDB_PRINT2((CE_WARN,
629*11359SMiao.Chen@Sun.COM 		    "intel_chipset_flush_setup: memcpy failed"));
63011260SMiao.Chen@Sun.COM 		goto error;
63111260SMiao.Chen@Sun.COM 	}
63211260SMiao.Chen@Sun.COM 
63311260SMiao.Chen@Sun.COM 	/* Bus=0, Dev=0, Func=0 0x82001000 */
634*11359SMiao.Chen@Sun.COM 	new_regs[old_regnum].pci_phys_hi = PCI_REG_REL_M | phys_hi_mask;
635*11359SMiao.Chen@Sun.COM 	new_regs[old_regnum].pci_phys_mid = HIADDR(phys_base);
636*11359SMiao.Chen@Sun.COM 	new_regs[old_regnum].pci_phys_low = LOADDR(phys_base);
637*11359SMiao.Chen@Sun.COM 	new_regs[old_regnum].pci_size_hi = 0x00000000;
638*11359SMiao.Chen@Sun.COM 	new_regs[old_regnum].pci_size_low = AGP_PAGE_SIZE;
63911260SMiao.Chen@Sun.COM 
640*11359SMiao.Chen@Sun.COM 	ret = ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
641*11359SMiao.Chen@Sun.COM 	    "reg", (int *)new_regs, (uint_t)5 * new_regnum);
642*11359SMiao.Chen@Sun.COM 	if (ret != DDI_PROP_SUCCESS) {
643*11359SMiao.Chen@Sun.COM 		TARGETDB_PRINT2((CE_WARN,
644*11359SMiao.Chen@Sun.COM 		    "intel_chipset_flush_setup: "
645*11359SMiao.Chen@Sun.COM 		    "ndi_prop_update_int_array failed %d", ret));
646*11359SMiao.Chen@Sun.COM 		goto error;
64711260SMiao.Chen@Sun.COM 	}
648*11359SMiao.Chen@Sun.COM 	kmem_free(new_regs, (size_t)new_len);
649*11359SMiao.Chen@Sun.COM 	new_regs = NULL;
650*11359SMiao.Chen@Sun.COM 
651*11359SMiao.Chen@Sun.COM 	prop_updated = 1;
65211260SMiao.Chen@Sun.COM 
65311260SMiao.Chen@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
654*11359SMiao.Chen@Sun.COM 	    "reg", (caddr_t)&new_regs, &new_len) != DDI_PROP_SUCCESS) {
655*11359SMiao.Chen@Sun.COM 		TARGETDB_PRINT2((CE_WARN,
656*11359SMiao.Chen@Sun.COM 		    "intel_chipset_flush_setup: "
657*11359SMiao.Chen@Sun.COM 		    "ddi_getlongprop(2) failed"));
65811260SMiao.Chen@Sun.COM 		goto error;
65911260SMiao.Chen@Sun.COM 	}
660*11359SMiao.Chen@Sun.COM 	kmem_free(new_regs, (size_t)new_len);
661*11359SMiao.Chen@Sun.COM 	new_regs = NULL;
662*11359SMiao.Chen@Sun.COM 
663*11359SMiao.Chen@Sun.COM 	new_regnum = new_len / sizeof (pci_regspec_t);
66411260SMiao.Chen@Sun.COM 
665*11359SMiao.Chen@Sun.COM 	i9xx_private.physical = phys_base;
66611260SMiao.Chen@Sun.COM 	i9xx_private.size = AGP_PAGE_SIZE;
667*11359SMiao.Chen@Sun.COM 	i9xx_private.regnum = new_regnum - 1;
668*11359SMiao.Chen@Sun.COM 
66911260SMiao.Chen@Sun.COM 	ret = ddi_regs_map_setup(dip, i9xx_private.regnum,
67011260SMiao.Chen@Sun.COM 	    (caddr_t *)&(i9xx_private.flush_page), 0,
671*11359SMiao.Chen@Sun.COM 	    i9xx_private.size, &dev_attr, &i9xx_private.handle);
67211260SMiao.Chen@Sun.COM 	if (ret != DDI_SUCCESS) {
673*11359SMiao.Chen@Sun.COM 		TARGETDB_PRINT2((CE_WARN,
674*11359SMiao.Chen@Sun.COM 		    "intel_chipset_flush_setup: ddi_regs_map_setup failed"));
67511260SMiao.Chen@Sun.COM 		i9xx_private.handle = NULL;
676*11359SMiao.Chen@Sun.COM 		goto error;
67711260SMiao.Chen@Sun.COM 	}
678*11359SMiao.Chen@Sun.COM 
679*11359SMiao.Chen@Sun.COM 	kmem_free(old_regs, (size_t)old_len);
68011260SMiao.Chen@Sun.COM 	return;
68111260SMiao.Chen@Sun.COM error:
682*11359SMiao.Chen@Sun.COM 	if (prop_updated)
683*11359SMiao.Chen@Sun.COM 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
684*11359SMiao.Chen@Sun.COM 		    "reg", (int *)old_regs, (uint_t)5 * old_regnum);
685*11359SMiao.Chen@Sun.COM 	if (new_regs)
686*11359SMiao.Chen@Sun.COM 		kmem_free(new_regs, (size_t)new_len);
687*11359SMiao.Chen@Sun.COM 	if (old_regs)
688*11359SMiao.Chen@Sun.COM 		kmem_free(old_regs, (size_t)old_len);
689*11359SMiao.Chen@Sun.COM 	if (i9xx_private.ra_alloced) {
690*11359SMiao.Chen@Sun.COM 		ndi_devi_enter(ddi_get_parent(dip), &circular);
691*11359SMiao.Chen@Sun.COM 		(void) ndi_ra_free(ddi_get_parent(dip),
692*11359SMiao.Chen@Sun.COM 		    phys_base, phys_len, NDI_RA_TYPE_MEM, NDI_RA_PASS);
693*11359SMiao.Chen@Sun.COM 		ndi_devi_exit(ddi_get_parent(dip), circular);
694*11359SMiao.Chen@Sun.COM 		i9xx_private.ra_alloced = 0;
695*11359SMiao.Chen@Sun.COM 	}
696*11359SMiao.Chen@Sun.COM }
697*11359SMiao.Chen@Sun.COM 
698*11359SMiao.Chen@Sun.COM static void
699*11359SMiao.Chen@Sun.COM intel_chipset_flush_free(dev_info_t *dip)
700*11359SMiao.Chen@Sun.COM {
701*11359SMiao.Chen@Sun.COM 	pci_regspec_t *regs = NULL;
702*11359SMiao.Chen@Sun.COM 	int len = 0, regnum;
703*11359SMiao.Chen@Sun.COM 	int circular = 0;
704*11359SMiao.Chen@Sun.COM 
705*11359SMiao.Chen@Sun.COM 	if (i9xx_private.handle == NULL)
706*11359SMiao.Chen@Sun.COM 		return;
707*11359SMiao.Chen@Sun.COM 
708*11359SMiao.Chen@Sun.COM 	ddi_regs_map_free(&i9xx_private.handle);
709*11359SMiao.Chen@Sun.COM 	i9xx_private.handle = NULL;
710*11359SMiao.Chen@Sun.COM 
711*11359SMiao.Chen@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
712*11359SMiao.Chen@Sun.COM 	    "reg", (caddr_t)&regs, &len) == DDI_PROP_SUCCESS) {
713*11359SMiao.Chen@Sun.COM 		regnum = len / sizeof (pci_regspec_t) - 1;
714*11359SMiao.Chen@Sun.COM 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
715*11359SMiao.Chen@Sun.COM 		    "reg", (int *)regs, (uint_t)5 * regnum);
716*11359SMiao.Chen@Sun.COM 	}
71711260SMiao.Chen@Sun.COM 	if (regs)
718*11359SMiao.Chen@Sun.COM 		kmem_free(regs, (size_t)len);
719*11359SMiao.Chen@Sun.COM 
720*11359SMiao.Chen@Sun.COM 	if (i9xx_private.ra_alloced) {
721*11359SMiao.Chen@Sun.COM 		ndi_devi_enter(ddi_get_parent(dip), &circular);
722*11359SMiao.Chen@Sun.COM 		(void) ndi_ra_free(ddi_get_parent(dip),
723*11359SMiao.Chen@Sun.COM 		    i9xx_private.physical, i9xx_private.size,
724*11359SMiao.Chen@Sun.COM 		    NDI_RA_TYPE_MEM, NDI_RA_PASS);
725*11359SMiao.Chen@Sun.COM 		ndi_devi_exit(ddi_get_parent(dip), circular);
726*11359SMiao.Chen@Sun.COM 		i9xx_private.ra_alloced = 0;
727*11359SMiao.Chen@Sun.COM 	}
72811260SMiao.Chen@Sun.COM }
72911260SMiao.Chen@Sun.COM 
7307130Sms148562 static int
7313446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7323446Smrj {
7333446Smrj 	agp_target_softstate_t *softstate;
7343446Smrj 	int instance;
7353446Smrj 	int status;
7363446Smrj 
7373446Smrj 	instance = ddi_get_instance(dip);
7383446Smrj 
7397130Sms148562 	switch (cmd) {
7407130Sms148562 	case DDI_ATTACH:
7417130Sms148562 		break;
7427130Sms148562 	case DDI_RESUME:
7437130Sms148562 		softstate =
7447130Sms148562 		    ddi_get_soft_state(agptarget_glob_soft_handle, instance);
7457130Sms148562 		return (intel_br_resume(softstate));
7467130Sms148562 	default:
7477130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
7487130Sms148562 		    "only attach and resume ops are supported"));
7493446Smrj 		return (DDI_FAILURE);
7507130Sms148562 	}
7517130Sms148562 
7527130Sms148562 	if (ddi_soft_state_zalloc(agptarget_glob_soft_handle,
7537130Sms148562 	    instance) != DDI_SUCCESS) {
7547130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
7557130Sms148562 		    "soft state zalloc failed"));
7567130Sms148562 		return (DDI_FAILURE);
7577130Sms148562 	}
7583446Smrj 
7593446Smrj 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
7603446Smrj 	mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL);
7613446Smrj 	softstate->tsoft_dip = dip;
7623446Smrj 	status = pci_config_setup(dip, &softstate->tsoft_pcihdl);
7633446Smrj 	if (status != DDI_SUCCESS) {
7647130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
7657130Sms148562 		    "pci config setup failed"));
7667130Sms148562 		ddi_soft_state_free(agptarget_glob_soft_handle,
7677130Sms148562 		    instance);
7683446Smrj 		return (DDI_FAILURE);
7693446Smrj 	}
7703446Smrj 
7713446Smrj 	softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl,
7723446Smrj 	    PCI_CONF_VENID);
7737130Sms148562 	softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid);
7747130Sms148562 	if (softstate->tsoft_gms_off < 0) {
7757130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
7767130Sms148562 		    "read gms offset failed"));
7777130Sms148562 		pci_config_teardown(&softstate->tsoft_pcihdl);
7787130Sms148562 		ddi_soft_state_free(agptarget_glob_soft_handle,
7797130Sms148562 		    instance);
7807130Sms148562 		return (DDI_FAILURE);
7817130Sms148562 	}
7823446Smrj 	softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl);
7833446Smrj 	if (softstate->tsoft_acaptr == 0) {
7843446Smrj 		/* Make a correction for some Intel chipsets */
7855131Sms148562 		if (is_intel_br(softstate))
7863446Smrj 			softstate->tsoft_acaptr = AGP_CAP_OFF_DEF;
7877130Sms148562 		else {
7887130Sms148562 			TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
7897130Sms148562 			    "Not a supposed corretion"));
7907130Sms148562 			pci_config_teardown(&softstate->tsoft_pcihdl);
7917130Sms148562 			ddi_soft_state_free(agptarget_glob_soft_handle,
7927130Sms148562 			    instance);
7933446Smrj 			return (DDI_FAILURE);
7947130Sms148562 		}
7953446Smrj 	}
7963446Smrj 
7973446Smrj 	status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR,
7983446Smrj 	    INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0);
7993446Smrj 
8003446Smrj 	if (status != DDI_SUCCESS) {
8017130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
8027130Sms148562 		    "Create minor node failed"));
8033446Smrj 		pci_config_teardown(&softstate->tsoft_pcihdl);
8043446Smrj 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
8053446Smrj 		return (DDI_FAILURE);
8063446Smrj 	}
8073446Smrj 
8083446Smrj 	return (DDI_SUCCESS);
8093446Smrj }
8103446Smrj 
8113446Smrj /*ARGSUSED*/
8123446Smrj static int
8133446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8143446Smrj {
8153446Smrj 	int instance;
8163446Smrj 	agp_target_softstate_t *softstate;
8173446Smrj 
8187130Sms148562 	instance = ddi_get_instance(dip);
8197130Sms148562 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
8203446Smrj 
8217130Sms148562 	if (cmd == DDI_SUSPEND) {
8227130Sms148562 		/* get GMS modes list entry */
8237130Sms148562 		return (intel_br_suspend(softstate));
8247130Sms148562 	}
8253446Smrj 
8267130Sms148562 	if (cmd != DDI_DETACH) {
8277130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_detach:"
8287130Sms148562 		    "only detach and suspend ops are supported"));
8297130Sms148562 		return (DDI_FAILURE);
8307130Sms148562 	}
8313446Smrj 
8323446Smrj 	ddi_remove_minor_node(dip, AGPTARGET_NAME);
8333446Smrj 	pci_config_teardown(&softstate->tsoft_pcihdl);
8343446Smrj 	mutex_destroy(&softstate->tsoft_lock);
8353446Smrj 	ddi_soft_state_free(agptarget_glob_soft_handle, instance);
8363446Smrj 	return (DDI_SUCCESS);
8373446Smrj }
8383446Smrj 
8393446Smrj /*ARGSUSED*/
8403446Smrj static int
8413446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
8423446Smrj     cred_t *cred, int *rval)
8433446Smrj {
8443446Smrj 	int instance = DEV2INST(dev);
8453446Smrj 	agp_target_softstate_t *st;
8463446Smrj 	static char kernel_only[] =
8473446Smrj 	    "amd64_gart_ioctl: is a kernel only ioctl";
8483446Smrj 
8493446Smrj 	if (!(mode & FKIOCTL)) {
8503446Smrj 		TARGETDB_PRINT2((CE_CONT, kernel_only));
8513446Smrj 		return (ENXIO);
8523446Smrj 	}
8533446Smrj 	st = GETSOFTC(instance);
8543446Smrj 
8553446Smrj 	if (st == NULL)
8563446Smrj 		return (ENXIO);
8573446Smrj 
8583446Smrj 	mutex_enter(&st->tsoft_lock);
8593446Smrj 
8603446Smrj 	switch (cmd) {
8613446Smrj 	case CHIP_DETECT:
8623446Smrj 	{
8635131Sms148562 		int type = 0;
8645131Sms148562 
8655131Sms148562 		if (is_intel_br(st))
8663446Smrj 			type = CHIP_IS_INTEL;
8675131Sms148562 		else if (is_64bit_aper(st))
8683446Smrj 			type = CHIP_IS_AMD;
8695131Sms148562 		else {
8703446Smrj 			type = 0;
8715131Sms148562 			TARGETDB_PRINT2((CE_WARN, "Unknown bridge!"));
8723446Smrj 		}
8735131Sms148562 
8743446Smrj 		if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) {
8753446Smrj 			mutex_exit(&st->tsoft_lock);
8763446Smrj 			return (EFAULT);
8773446Smrj 		}
8783446Smrj 
8793446Smrj 		break;
8803446Smrj 	}
8813446Smrj 	case I8XX_GET_PREALLOC_SIZE:
8823446Smrj 	{
8833446Smrj 		size_t prealloc_size;
8843446Smrj 
8855131Sms148562 		if (!is_intel_br(st)) {
8863446Smrj 			mutex_exit(&st->tsoft_lock);
8873446Smrj 			return (EINVAL);
8883446Smrj 		}
8893446Smrj 
8903446Smrj 		prealloc_size = i8xx_biosmem_detect(st);
8913446Smrj 		if (ddi_copyout(&prealloc_size, (void *)data,
8923446Smrj 		    sizeof (size_t), mode)) {
8933446Smrj 			mutex_exit(&st->tsoft_lock);
8943446Smrj 			return (EFAULT);
8953446Smrj 		}
8963446Smrj 
8973446Smrj 		break;
8983446Smrj 	}
8993446Smrj 	case AGP_TARGET_GETINFO:
9003446Smrj 	{
9013446Smrj 		i_agp_info_t info;
9023446Smrj 		uint32_t value;
9033446Smrj 		off_t cap;
9043446Smrj 
9053446Smrj 		ASSERT(st->tsoft_acaptr);
9063446Smrj 
9073446Smrj 		cap = st->tsoft_acaptr;
9083446Smrj 		value = pci_config_get32(st->tsoft_pcihdl, cap);
9093446Smrj 		info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf);
9103446Smrj 		info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf);
9113446Smrj 		info.iagp_devid = st->tsoft_devid;
9123446Smrj 		info.iagp_mode = pci_config_get32(st->tsoft_pcihdl,
9134303Skz151634 		    cap + AGP_CONF_STATUS);
9143446Smrj 		info.iagp_aperbase = agp_target_get_apbase(st);
9153446Smrj 		info.iagp_apersize = agp_target_get_apsize(st);
9163446Smrj 
9173446Smrj 		if (ddi_copyout(&info, (void *)data,
9183446Smrj 		    sizeof (i_agp_info_t), mode)) {
9193446Smrj 			mutex_exit(&st->tsoft_lock);
9203446Smrj 			return (EFAULT);
9213446Smrj 		}
9223446Smrj 		break;
9233446Smrj 
9243446Smrj 	}
9253446Smrj 	/*
9263446Smrj 	 * This ioctl is only for Intel AGP chipsets.
9273446Smrj 	 * It is not necessary for the AMD8151 AGP bridge, because
9283446Smrj 	 * this register in the AMD8151 does not control any hardware.
9293446Smrj 	 * It is only provided for compatibility with an Intel AGP bridge.
9303446Smrj 	 * Please refer to the <<AMD8151 data sheet>> page 24,
9313446Smrj 	 * AGP device GART pointer.
9323446Smrj 	 */
9333446Smrj 	case AGP_TARGET_SET_GATTADDR:
9343446Smrj 	{
9353446Smrj 		uint32_t gartaddr;
9363446Smrj 
9373446Smrj 		if (ddi_copyin((void *)data, &gartaddr,
9383446Smrj 		    sizeof (uint32_t), mode)) {
9393446Smrj 			mutex_exit(&st->tsoft_lock);
9403446Smrj 			return (EFAULT);
9413446Smrj 		}
9423446Smrj 
9433446Smrj 		agp_target_set_gartaddr(st, gartaddr);
9443446Smrj 		break;
9453446Smrj 	}
9463446Smrj 	case AGP_TARGET_SETCMD:
9473446Smrj 	{
9483446Smrj 		uint32_t command;
9493446Smrj 
9503446Smrj 		if (ddi_copyin((void *)data, &command,
9513446Smrj 		    sizeof (uint32_t), mode)) {
9523446Smrj 			mutex_exit(&st->tsoft_lock);
9533446Smrj 			return (EFAULT);
9543446Smrj 		}
9553446Smrj 
9563446Smrj 		ASSERT(st->tsoft_acaptr);
9573446Smrj 
9583446Smrj 		pci_config_put32(st->tsoft_pcihdl,
9593446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
9603446Smrj 		    command);
9613446Smrj 		break;
9623446Smrj 
9633446Smrj 	}
9643446Smrj 	case AGP_TARGET_FLUSH_GTLB:
9653446Smrj 	{
9663446Smrj 		uint16_t value;
9673446Smrj 
9683446Smrj 		ASSERT(st->tsoft_acaptr);
9693446Smrj 
9703446Smrj 		value = pci_config_get16(st->tsoft_pcihdl,
9713446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL);
9723446Smrj 		value &= ~AGPCTRL_GTLBEN;
9733446Smrj 		pci_config_put16(st->tsoft_pcihdl,
9743446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
9753446Smrj 		value |= AGPCTRL_GTLBEN;
9763446Smrj 		pci_config_put16(st->tsoft_pcihdl,
9773446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
9783446Smrj 
9793446Smrj 		break;
9803446Smrj 	}
9813446Smrj 	case AGP_TARGET_CONFIGURE:
9823446Smrj 	{
9833446Smrj 		uint8_t value;
9843446Smrj 
9853446Smrj 		ASSERT(st->tsoft_acaptr);
9863446Smrj 
9875131Sms148562 		/*
9885131Sms148562 		 * In Intel agp bridges, agp misc register offset
9895131Sms148562 		 * is indexed from 0 instead of capability register.
9905131Sms148562 		 * AMD agp bridges have no such misc register
9915131Sms148562 		 * to control the aperture access, and they have
9925131Sms148562 		 * similar regsiters in CPU gart devices instead.
9935131Sms148562 		 */
9945131Sms148562 
9955131Sms148562 		if (is_intel_br(st)) {
9965131Sms148562 			value = pci_config_get8(st->tsoft_pcihdl,
9975131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC);
9985131Sms148562 			value |= AGP_MISC_APEN;
9995131Sms148562 			pci_config_put8(st->tsoft_pcihdl,
10005131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC, value);
10015131Sms148562 		}
10023446Smrj 		break;
10033446Smrj 
10043446Smrj 	}
10053446Smrj 	case AGP_TARGET_UNCONFIG:
10063446Smrj 	{
10073446Smrj 		uint32_t value1;
10083446Smrj 		uint8_t value2;
10093446Smrj 
10103446Smrj 		ASSERT(st->tsoft_acaptr);
10113446Smrj 
10123446Smrj 		pci_config_put16(st->tsoft_pcihdl,
10133446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0);
10143446Smrj 
10155131Sms148562 		if (is_intel_br(st)) {
10165131Sms148562 			value2 = pci_config_get8(st->tsoft_pcihdl,
10175131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC);
10185131Sms148562 			value2 &= ~AGP_MISC_APEN;
10195131Sms148562 			pci_config_put8(st->tsoft_pcihdl,
10205131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC, value2);
10215131Sms148562 		}
10223446Smrj 
10233446Smrj 		value1 = pci_config_get32(st->tsoft_pcihdl,
10243446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND);
10253446Smrj 		value1 &= ~AGPCMD_AGPEN;
10263446Smrj 		pci_config_put32(st->tsoft_pcihdl,
10273446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
10283446Smrj 		    value1);
10293446Smrj 
10303446Smrj 		pci_config_put32(st->tsoft_pcihdl,
10313446Smrj 		    st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0);
10323446Smrj 
10333446Smrj 		break;
10343446Smrj 	}
10353446Smrj 
103611260SMiao.Chen@Sun.COM 	case INTEL_CHIPSET_FLUSH_SETUP:
103711260SMiao.Chen@Sun.COM 	{
103811260SMiao.Chen@Sun.COM 		intel_chipset_flush_setup(st->tsoft_dip,
103911260SMiao.Chen@Sun.COM 		    st->tsoft_pcihdl, st->tsoft_gms_off);
104011260SMiao.Chen@Sun.COM 		break;
104111260SMiao.Chen@Sun.COM 	}
104211260SMiao.Chen@Sun.COM 	case INTEL_CHIPSET_FLUSH:
104311260SMiao.Chen@Sun.COM 	{
104411260SMiao.Chen@Sun.COM 		if (i9xx_private.handle != NULL)
104511260SMiao.Chen@Sun.COM 			ddi_put32(i9xx_private.handle,
104611260SMiao.Chen@Sun.COM 			    (uint32_t *)(uintptr_t)i9xx_private.flush_page, 1);
104711260SMiao.Chen@Sun.COM 
104811260SMiao.Chen@Sun.COM 		break;
104911260SMiao.Chen@Sun.COM 	}
105011260SMiao.Chen@Sun.COM 	case INTEL_CHIPSET_FLUSH_FREE:
105111260SMiao.Chen@Sun.COM 	{
1052*11359SMiao.Chen@Sun.COM 		intel_chipset_flush_free(st->tsoft_dip);
105311260SMiao.Chen@Sun.COM 		break;
105411260SMiao.Chen@Sun.COM 	}
10553446Smrj 	default:
10563446Smrj 		mutex_exit(&st->tsoft_lock);
10573446Smrj 		return (ENXIO);
10583446Smrj 	} /* end switch */
10593446Smrj 
10603446Smrj 	mutex_exit(&st->tsoft_lock);
10613446Smrj 
10623446Smrj 	return (0);
10633446Smrj }
10643446Smrj 
10653446Smrj /*ARGSUSED*/
10663446Smrj static int
10673446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred)
10683446Smrj {
10693446Smrj 	int instance = DEV2INST(*devp);
10703446Smrj 	agp_target_softstate_t *st;
10713446Smrj 
10723446Smrj 	if (!(flag & FKLYR))
10733446Smrj 		return (ENXIO);
10743446Smrj 
10753446Smrj 	st = GETSOFTC(instance);
10763446Smrj 
10773446Smrj 	if (st == NULL)
10783446Smrj 		return (ENXIO);
10793446Smrj 
10803446Smrj 	return (0);
10813446Smrj }
10823446Smrj 
10833446Smrj /*ARGSUSED*/
10843446Smrj static int
10853446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred)
10863446Smrj {
10873446Smrj 	int instance = DEV2INST(dev);
10883446Smrj 	agp_target_softstate_t *st;
10893446Smrj 
10903446Smrj 	st = GETSOFTC(instance);
10913446Smrj 
10923446Smrj 	if (st == NULL)
10933446Smrj 		return (ENXIO);
10943446Smrj 
10953446Smrj 	return (0);
10963446Smrj }
10973446Smrj 
10983446Smrj static  struct  cb_ops  agp_target_cb_ops = {
10993446Smrj 	agp_target_open,		/* cb_open */
11003446Smrj 	agp_target_close,		/* cb_close */
11013446Smrj 	nodev,				/* cb_strategy */
11023446Smrj 	nodev,				/* cb_print */
11033446Smrj 	nodev,				/* cb_dump */
11043446Smrj 	nodev,				/* cb_read() */
11053446Smrj 	nodev,				/* cb_write() */
11063446Smrj 	agp_target_ioctl,		/* cb_ioctl */
11073446Smrj 	nodev,				/* cb_devmap */
11083446Smrj 	nodev,				/* cb_mmap */
11093446Smrj 	nodev,				/* cb_segmap */
11103446Smrj 	nochpoll,			/* cb_chpoll */
11113446Smrj 	ddi_prop_op,			/* cb_prop_op */
11123446Smrj 	0,				/* cb_stream */
11133446Smrj 	D_NEW | D_MP, 			/* cb_flag */
11143446Smrj 	CB_REV,				/* cb_ops version? */
11153446Smrj 	nodev,				/* cb_aread() */
11163446Smrj 	nodev,				/* cb_awrite() */
11173446Smrj };
11183446Smrj 
11193446Smrj /* device operations */
11203446Smrj static struct dev_ops agp_target_ops = {
11213446Smrj 	DEVO_REV,		/* devo_rev */
11223446Smrj 	0,			/* devo_refcnt */
11233446Smrj 	agptarget_getinfo, 	/* devo_getinfo */
11243446Smrj 	nulldev,		/* devo_identify */
11253446Smrj 	nulldev,		/* devo_probe */
11263446Smrj 	agp_target_attach,	/* devo_attach */
11273446Smrj 	agp_target_detach,	/* devo_detach */
11283446Smrj 	nodev,			/* devo_reset */
11293446Smrj 	&agp_target_cb_ops,	/* devo_cb_ops */
11303446Smrj 	0,			/* devo_bus_ops */
11313446Smrj 	0,			/* devo_power */
11328328SMiao.Chen@Sun.COM 	ddi_quiesce_not_needed,	/* devo_quiesce */
11333446Smrj };
11343446Smrj 
11353446Smrj static  struct modldrv modldrv = {
11363446Smrj 	&mod_driverops,
11377130Sms148562 	"AGP target driver",
11383446Smrj 	&agp_target_ops,
11393446Smrj };
11403446Smrj 
11413446Smrj static  struct modlinkage modlinkage = {
11423446Smrj 	MODREV_1,		/* MODREV_1 is indicated by manual */
11433446Smrj 	{&modldrv, NULL, NULL, NULL}
11443446Smrj };
11453446Smrj 
11463446Smrj int
11473446Smrj _init(void)
11483446Smrj {
11493446Smrj 	int ret;
11503446Smrj 
11513446Smrj 	ret = ddi_soft_state_init(&agptarget_glob_soft_handle,
11523446Smrj 	    sizeof (agp_target_softstate_t), 1);
11533446Smrj 
11543446Smrj 	if (ret)
11553446Smrj 		goto err1;
11563446Smrj 
11573446Smrj 	if ((ret = mod_install(&modlinkage)) != 0) {
11583446Smrj 		goto err2;
11593446Smrj 	}
11603446Smrj 
11613446Smrj 	return (DDI_SUCCESS);
11623446Smrj err2:
11633446Smrj 	ddi_soft_state_fini(&agptarget_glob_soft_handle);
11643446Smrj err1:
11653446Smrj 	return (ret);
11663446Smrj }
11673446Smrj 
11683446Smrj int
11693446Smrj _info(struct  modinfo *modinfop)
11703446Smrj {
11713446Smrj 	return (mod_info(&modlinkage, modinfop));
11723446Smrj }
11733446Smrj 
11743446Smrj int
11753446Smrj _fini(void)
11763446Smrj {
11773446Smrj 	int	ret;
11783446Smrj 
11793446Smrj 	if ((ret = mod_remove(&modlinkage)) == 0) {
11803446Smrj 		ddi_soft_state_fini(&agptarget_glob_soft_handle);
11813446Smrj 	}
11823446Smrj 	return (ret);
11833446Smrj }
1184