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 /*
236778Smc196098  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
243446Smrj  * Use is subject to license terms.
253446Smrj  */
263446Smrj 
273446Smrj 
283446Smrj #include <sys/systm.h>
293446Smrj #include <sys/conf.h>
303446Smrj #include <sys/modctl.h>
313446Smrj #include <sys/file.h>
323446Smrj #include <sys/stat.h>
333446Smrj #include <sys/ddi.h>
343446Smrj #include <sys/sunddi.h>
353446Smrj #include <sys/modctl.h>
363446Smrj #include <sys/sunldi.h>
373446Smrj #include <sys/pci.h>
383446Smrj #include <sys/agpgart.h>
393446Smrj #include <sys/agp/agpdefs.h>
403446Smrj #include <sys/agp/agptarget_io.h>
413446Smrj 
423446Smrj int agptarget_debug_var = 0;
433446Smrj #define	TARGETDB_PRINT2(fmt)	if (agptarget_debug_var >= 1) cmn_err fmt
443446Smrj #define	INST2NODENUM(inst)	(inst)
453446Smrj #define	DEV2INST(dev)		(getminor(dev))
463446Smrj 
473446Smrj typedef struct agp_target_softstate {
483446Smrj 	dev_info_t		*tsoft_dip;
493446Smrj 	ddi_acc_handle_t	tsoft_pcihdl;
503446Smrj 	uint32_t		tsoft_devid;
513446Smrj 	/* The offset of the ACAPID register */
523446Smrj 	off_t			tsoft_acaptr;
533446Smrj 	kmutex_t		tsoft_lock;
547130Sms148562 	int			tsoft_gms_off; /* GMS offset in config */
557130Sms148562 	uint32_t		tsoft_gms;
563446Smrj }agp_target_softstate_t;
573446Smrj 
585036Skz151634 /*
595036Skz151634  * To get the pre-allocated graphics mem size using Graphics Mode Select
605036Skz151634  * (GMS) value.
615036Skz151634  */
625036Skz151634 typedef struct gms_mode {
635036Skz151634 	uint32_t	gm_devid;	/* bridge vendor + device id */
645036Skz151634 	off_t		gm_regoff;	/* mode selection register offset */
655036Skz151634 	uint32_t	gm_mask;	/* GMS mask */
665036Skz151634 	uint32_t	gm_num;		/* number of modes in gm_vec */
675036Skz151634 	int 		*gm_vec;	/* modes array */
685036Skz151634 } gms_mode_t;
695036Skz151634 
703446Smrj static void *agptarget_glob_soft_handle;
713446Smrj 
723446Smrj #define	GETSOFTC(instance)	((agp_target_softstate_t *)	\
733446Smrj     ddi_get_soft_state(agptarget_glob_soft_handle, instance));
743446Smrj 
753446Smrj /*
763446Smrj  * The AMD8151 bridge is the only supported 64 bit hardware
773446Smrj  */
783446Smrj static int
793446Smrj is_64bit_aper(agp_target_softstate_t *softstate)
803446Smrj {
813446Smrj 	return (softstate->tsoft_devid == AMD_BR_8151);
823446Smrj }
837130Sms148562 
845131Sms148562 /*
855131Sms148562  * Check if it is an intel bridge
865131Sms148562  */
875131Sms148562 static int
885131Sms148562 is_intel_br(agp_target_softstate_t *softstate)
895131Sms148562 {
905131Sms148562 	return ((softstate->tsoft_devid & VENDOR_ID_MASK) ==
915131Sms148562 	    INTEL_VENDOR_ID);
925131Sms148562 }
933446Smrj 
943446Smrj /*
953446Smrj  * agp_target_cap_find()
963446Smrj  *
973446Smrj  * Description:
983446Smrj  * 	This function searches the linked capability list to find the offset
993446Smrj  * 	of the AGP capability register. When it was not found, return 0.
1003446Smrj  * 	This works for standard AGP chipsets, but not for some Intel chipsets,
1013446Smrj  * 	like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for
1023446Smrj  * 	these chipsets even if AGP is supported. So the offset of acapid
1033446Smrj  * 	should be set manually in thoses cases.
1043446Smrj  *
1053446Smrj  * Arguments:
1063446Smrj  * 	pci_handle		ddi acc handle of pci config
1073446Smrj  *
1083446Smrj  * Returns:
1093446Smrj  * 	0			No capability pointer register found
1103446Smrj  * 	nexcap			The AGP capability pointer register offset
1113446Smrj  */
1123446Smrj static off_t
1133446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle)
1143446Smrj {
1153446Smrj 	off_t		nextcap = 0;
1163446Smrj 	uint32_t	ncapid = 0;
1173446Smrj 	uint8_t		value = 0;
1183446Smrj 
1193446Smrj 	/* Check if this device supports the capability pointer */
1203446Smrj 	value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT)
1213446Smrj 	    & PCI_CONF_CAP_MASK);
1223446Smrj 
1233446Smrj 	if (!value)
1243446Smrj 		return (0);
1253446Smrj 	/* Get the offset of the first capability pointer from CAPPTR */
1263446Smrj 	nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR));
1273446Smrj 
1283446Smrj 	/* Check the AGP capability from the first capability pointer */
1293446Smrj 	while (nextcap) {
1303446Smrj 		ncapid = pci_config_get32(pci_handle, nextcap);
1313446Smrj 		/*
1323446Smrj 		 * AGP3.0 rev1.0 127  the capid was assigned by the PCI SIG,
1333446Smrj 		 * 845 data sheet page 69
1343446Smrj 		 */
1353446Smrj 		if ((ncapid & PCI_CONF_CAPID_MASK) ==
1363446Smrj 		    AGP_CAP_ID) /* The AGP cap was found */
1373446Smrj 			break;
1383446Smrj 
1393446Smrj 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
1403446Smrj 	}
1413446Smrj 
1423446Smrj 	return (nextcap);
1433446Smrj 
1443446Smrj }
1453446Smrj 
1463446Smrj /*
1473446Smrj  * agp_target_get_aperbase()
1483446Smrj  *
1493446Smrj  * Description:
1503446Smrj  * 	This function gets the AGP aperture base address from the AGP target
1513446Smrj  *	register, the AGP aperture base register was programmed by the BIOS.
1523446Smrj  *
1533446Smrj  * Arguments:
1543446Smrj  * 	softstate		driver soft state pointer
1553446Smrj  *
1563446Smrj  * Returns:
1573446Smrj  * 	aper_base 		AGP aperture base address
1583446Smrj  *
1593446Smrj  * Notes:
1603446Smrj  * 	If a 64bit bridge device is available, the AGP aperture base address
1613446Smrj  * 	can be 64 bit.
1623446Smrj  */
1633446Smrj static uint64_t
1643446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate)
1653446Smrj {
1663446Smrj 	uint64_t aper_base;
1673446Smrj 
1685131Sms148562 	if (is_intel_br(softstate)) {
1693446Smrj 		aper_base = pci_config_get32(softstate->tsoft_pcihdl,
1703446Smrj 		    AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK;
1715131Sms148562 	} else if (is_64bit_aper(softstate)) {
1723446Smrj 		aper_base = pci_config_get64(softstate->tsoft_pcihdl,
1733446Smrj 		    AGP_CONF_APERBASE);
1743446Smrj 		/* 32-bit or 64-bit aperbase base pointer */
1753446Smrj 		if ((aper_base & AGP_APER_TYPE_MASK) == 0)
1763446Smrj 			aper_base &= AGP_32_APERBASE_MASK;
1773446Smrj 		else
1783446Smrj 			aper_base &= AGP_64_APERBASE_MASK;
1793446Smrj 	}
1805131Sms148562 
1813446Smrj 	return (aper_base);
1823446Smrj }
1833446Smrj 
1843446Smrj /*
1853446Smrj  * agp_target_get_apsize()
1863446Smrj  *
1873446Smrj  * Description:
1883446Smrj  * 	This function gets the AGP aperture size by reading the AGP aperture
1893446Smrj  * 	size register.
1903446Smrj  * Arguments:
1913446Smrj  * 	softstate		driver soft state pointer
1923446Smrj  *
1933446Smrj  * Return:
1943446Smrj  * 	size		The AGP aperture size in megabytes
1953446Smrj  * 	0		an unexpected error
1963446Smrj  */
1973446Smrj static size_t
1983446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate)
1993446Smrj {
2003446Smrj 	off_t cap;
2013446Smrj 	uint16_t value;
2023446Smrj 	size_t size, regsize;
2033446Smrj 
2043446Smrj 	ASSERT(softstate->tsoft_acaptr);
2053446Smrj 	cap = softstate->tsoft_acaptr;
2063446Smrj 
2075131Sms148562 	if (is_intel_br(softstate)) {
2083446Smrj 		/* extend this value to 16 bit for later tests */
2093446Smrj 		value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl,
2103446Smrj 		    cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK;
2115131Sms148562 	} else if (is_64bit_aper(softstate)) {
2123446Smrj 		value = pci_config_get16(softstate->tsoft_pcihdl,
2133446Smrj 		    cap + AGP_CONF_APERSIZE);
2143446Smrj 	}
2153446Smrj 
2163446Smrj 	if (value & AGP_APER_128M_MASK) {
2173446Smrj 		switch (value & AGP_APER_128M_MASK) {
2183446Smrj 			case AGP_APER_4M:
2193446Smrj 				size = 4; /* 4M */
2203446Smrj 				break;
2213446Smrj 			case AGP_APER_8M:
2223446Smrj 				size = 8; /* 8M */
2233446Smrj 				break;
2243446Smrj 			case AGP_APER_16M:
2253446Smrj 				size = 16; /* 16M */
2263446Smrj 				break;
2273446Smrj 			case AGP_APER_32M:
2283446Smrj 				size = 32; /* 32M */
2293446Smrj 				break;
2303446Smrj 			case AGP_APER_64M:
2313446Smrj 				size = 64; /* 64M */
2323446Smrj 				break;
2333446Smrj 			case AGP_APER_128M:
2343446Smrj 				size = 128; /* 128M */
2353446Smrj 				break;
2363446Smrj 			default:
2373446Smrj 				size = 0; /* not true */
2383446Smrj 		}
2393446Smrj 	} else {
2403446Smrj 		switch (value & AGP_APER_4G_MASK) {
2413446Smrj 			case AGP_APER_256M:
2423446Smrj 				size = 256; /* 256 M */
2433446Smrj 				break;
2443446Smrj 			case AGP_APER_512M:
2453446Smrj 				size = 512; /* 512 M */
2463446Smrj 				break;
2473446Smrj 			case AGP_APER_1024M:
2483446Smrj 				size = 1024; /* 1024 M */
2493446Smrj 				break;
2503446Smrj 			case AGP_APER_2048M:
2513446Smrj 				size = 2048; /* 2048 M */
2523446Smrj 				break;
2533446Smrj 			case AGP_APER_4G:
2543446Smrj 				size = 4096; /* 4096 M */
2553446Smrj 				break;
2563446Smrj 			default:
2573446Smrj 				size = 0; /* not true */
2583446Smrj 		}
2593446Smrj 	}
2603446Smrj 	/*
2613446Smrj 	 * In some cases, there is no APSIZE register, so the size value
2623446Smrj 	 * of 256M could be wrong. Check the value by reading the size of
2633446Smrj 	 * the first register which was set in the PCI configuration space.
2643446Smrj 	 */
2653446Smrj 	if (size == 256) {
2663446Smrj 		if (ddi_dev_regsize(softstate->tsoft_dip,
2673446Smrj 		    AGP_TARGET_BAR1, (off_t *)&regsize) == DDI_FAILURE)
2683446Smrj 			return (0);
2693446Smrj 
2703446Smrj 		if (MB2BYTES(size) != regsize) {
2713446Smrj 			TARGETDB_PRINT2((CE_WARN,
2723446Smrj 			    "APSIZE 256M doesn't match regsize %lx",
2733446Smrj 			    regsize));
2743446Smrj 			TARGETDB_PRINT2((CE_WARN, "Use regsize instead"));
2753446Smrj 			size = BYTES2MB(regsize);
2763446Smrj 		}
2773446Smrj 	}
2783446Smrj 
2793446Smrj 	return (size);
2803446Smrj }
2813446Smrj 
2823446Smrj static void
2833446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr)
2843446Smrj {
2853446Smrj 	ASSERT(softstate->tsoft_acaptr);
2863446Smrj 
2873446Smrj 	/* Disable the GTLB for Intel chipsets */
2883446Smrj 	pci_config_put16(softstate->tsoft_pcihdl,
2893446Smrj 	    softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000);
2903446Smrj 
2913446Smrj 	pci_config_put32(softstate->tsoft_pcihdl,
2923446Smrj 	    softstate->tsoft_acaptr + AGP_CONF_ATTBASE,
2933446Smrj 	    gartaddr & AGP_ATTBASE_MASK);
2943446Smrj }
2953446Smrj 
2965036Skz151634 /*
2975036Skz151634  * Pre-allocated graphics memory for every type of Intel north bridge, mem size
2985036Skz151634  * are specified in kbytes.
2995036Skz151634  */
3005036Skz151634 #define	GMS_MB(n) 	((n) * 1024)
3015036Skz151634 #define	GMS_SHIFT 	4
3025036Skz151634 #define	GMS_SIZE(a)	(sizeof (a) / sizeof (int))
3035036Skz151634 
3045036Skz151634 /*
3055036Skz151634  * Since value zero always means "No memory pre-allocated", value of (GMS - 1)
3065036Skz151634  * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb)
3075036Skz151634  * that GMS value 0x1 corresponding to.
3085036Skz151634  *
3095036Skz151634  * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics
3105036Skz151634  * memory, unless some special BIOS settings exist.
3115036Skz151634  */
3125036Skz151634 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)};
3135036Skz151634 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)};
3145036Skz151634 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
3155036Skz151634 	GMS_MB(32)};
3165036Skz151634 /* There is no modes for 16M in datasheet, but some BIOS add it. */
3175036Skz151634 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)};
3185036Skz151634 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)};
3195036Skz151634 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
3205036Skz151634 	GMS_MB(32), GMS_MB(48), GMS_MB(64)};
3215036Skz151634 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
3225036Skz151634 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)};
3237662SMiao.Chen@Sun.COM static int gms_G4X[13] = {0, 0, 0, 0,
3247662SMiao.Chen@Sun.COM 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256),
3257662SMiao.Chen@Sun.COM 	GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)};
3265036Skz151634 
3275036Skz151634 static gms_mode_t gms_modes[] = {
3285036Skz151634 	{INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK,
3295036Skz151634 		GMS_SIZE(gms_810), gms_810},
3305036Skz151634 	{INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK,
3315036Skz151634 		GMS_SIZE(gms_810), gms_810},
3325036Skz151634 	{INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK,
3335036Skz151634 		GMS_SIZE(gms_810), gms_810},
3345036Skz151634 	{INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3355036Skz151634 		GMS_SIZE(gms_830_845), gms_830_845},
3365036Skz151634 	{INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3375036Skz151634 		GMS_SIZE(gms_830_845), gms_830_845},
3385036Skz151634 	{INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3395036Skz151634 		GMS_SIZE(gms_855GM), gms_855GM},
3405036Skz151634 	{INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3415036Skz151634 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
3425036Skz151634 	{INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3435036Skz151634 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
3445036Skz151634 	{INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3455036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3465036Skz151634 	{INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3475036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3485036Skz151634 	{INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3495036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3508020SMiao.Chen@Sun.COM 	{INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3518020SMiao.Chen@Sun.COM 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3525036Skz151634 	{INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3535036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3545036Skz151634 	{INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3555036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3565036Skz151634 	{INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3575036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3585036Skz151634 	{INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3595036Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
3605036Skz151634 	{INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3615036Skz151634 		GMS_SIZE(gms_965GM), gms_965GM},
3625036Skz151634 	{INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3635036Skz151634 		GMS_SIZE(gms_965GM), gms_965GM},
3645036Skz151634 	{INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK,
3655036Skz151634 		GMS_SIZE(gms_X33), gms_X33},
3665036Skz151634 	{INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
3675036Skz151634 		GMS_SIZE(gms_X33), gms_X33},
3685036Skz151634 	{INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
3696778Smc196098 		GMS_SIZE(gms_X33), gms_X33},
3706778Smc196098 	{INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3717662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_965GM), gms_965GM},
3727662SMiao.Chen@Sun.COM 	{INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3737662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
3747662SMiao.Chen@Sun.COM 	{INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3757662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X},
3767662SMiao.Chen@Sun.COM 	{INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3777662SMiao.Chen@Sun.COM 		GMS_SIZE(gms_G4X), gms_G4X}
3785036Skz151634 };
3797130Sms148562 static int
3807130Sms148562 get_chip_gms(uint32_t devid)
3817130Sms148562 {
3827130Sms148562 	int num_modes;
3837130Sms148562 	int i;
3847130Sms148562 
3857130Sms148562 	num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t));
3867130Sms148562 
3877130Sms148562 	for (i = 0; i < num_modes; i++) {
3887130Sms148562 		if (gms_modes[i].gm_devid == devid)
3897130Sms148562 			break;
3907130Sms148562 	}
3917130Sms148562 
3927130Sms148562 	return ((i == num_modes) ? -1 : i);
3937130Sms148562 }
3945036Skz151634 
3955036Skz151634 /* Returns the size (kbytes) of pre-allocated graphics memory */
3963446Smrj static size_t
3973446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate)
3983446Smrj {
3993446Smrj 	uint8_t memval;
4003446Smrj 	size_t kbytes;
4017130Sms148562 	int	gms_off;
4023446Smrj 
4035036Skz151634 	kbytes = 0;
4047130Sms148562 	gms_off = softstate->tsoft_gms_off;
4057130Sms148562 
4065036Skz151634 	/* fetch the GMS value from DRAM controller */
4075036Skz151634 	memval = pci_config_get8(softstate->tsoft_pcihdl,
4087130Sms148562 	    gms_modes[gms_off].gm_regoff);
4095036Skz151634 	TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval));
4107130Sms148562 	memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT;
4115036Skz151634 	/* assuming zero byte for 0 or "reserved" GMS values */
4127130Sms148562 	if (memval == 0 || memval > gms_modes[gms_off].gm_num) {
4135036Skz151634 		TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: "
4145036Skz151634 		    "devid = %x, GMS = %x. assuming zero byte of "
4157130Sms148562 		    "pre-allocated memory",
4167130Sms148562 		    gms_modes[gms_off].gm_devid, memval));
4175036Skz151634 		goto done;
4185036Skz151634 	}
4195036Skz151634 	memval--;	/* use (GMS_value - 1) as index */
4207130Sms148562 	kbytes = (gms_modes[gms_off].gm_vec)[memval];
4213446Smrj 
4225036Skz151634 done:
4234478Skz151634 	TARGETDB_PRINT2((CE_NOTE,
4244478Skz151634 	    "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected",
4254478Skz151634 	    kbytes));
4263446Smrj 	return (kbytes);
4273446Smrj }
4283446Smrj 
4293446Smrj /*ARGSUSED*/
4303446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
4313446Smrj     void *arg, void **resultp)
4323446Smrj {
4333446Smrj 	agp_target_softstate_t *st;
4343446Smrj 	int instance, rval = DDI_FAILURE;
4353446Smrj 	dev_t dev;
4363446Smrj 
4373446Smrj 	switch (cmd) {
4383446Smrj 	case DDI_INFO_DEVT2DEVINFO:
4393446Smrj 		dev = (dev_t)arg;
4403446Smrj 		instance = DEV2INST(dev);
4413446Smrj 		st = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
4423446Smrj 		if (st != NULL) {
4433446Smrj 			mutex_enter(&st->tsoft_lock);
4443446Smrj 			*resultp = st->tsoft_dip;
4453446Smrj 			mutex_exit(&st->tsoft_lock);
4463446Smrj 			rval = DDI_SUCCESS;
4473446Smrj 		} else
4483446Smrj 			*resultp = NULL;
4493446Smrj 
4503446Smrj 		break;
4513446Smrj 	case DDI_INFO_DEVT2INSTANCE:
4523446Smrj 		dev = (dev_t)arg;
4533446Smrj 		instance = DEV2INST(dev);
4543446Smrj 		*resultp = (void *)(uintptr_t)instance;
4553446Smrj 		rval = DDI_SUCCESS;
4563446Smrj 	default:
4573446Smrj 		break;
4583446Smrj 	}
4593446Smrj 
4603446Smrj 	return (rval);
4613446Smrj }
4623446Smrj 
4633446Smrj static int
4647130Sms148562 intel_br_resume(agp_target_softstate_t *softstate)
4657130Sms148562 {
4667130Sms148562 	int gms_off;
4677130Sms148562 
4687130Sms148562 	gms_off = softstate->tsoft_gms_off;
4697130Sms148562 
4707130Sms148562 	/*
4717130Sms148562 	 * We recover the gmch graphics control register here
4727130Sms148562 	 */
4737130Sms148562 	pci_config_put16(softstate->tsoft_pcihdl,
4747130Sms148562 	    gms_modes[gms_off].gm_regoff, softstate->tsoft_gms);
4757130Sms148562 
4767130Sms148562 	return (DDI_SUCCESS);
4777130Sms148562 }
4787130Sms148562 static int
4797130Sms148562 intel_br_suspend(agp_target_softstate_t *softstate)
4807130Sms148562 {
4817130Sms148562 	int gms_off;
4827130Sms148562 
4837130Sms148562 	gms_off = softstate->tsoft_gms_off;
4847130Sms148562 	softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl,
4857130Sms148562 	    gms_modes[gms_off].gm_regoff);
4867130Sms148562 
4877130Sms148562 	return (DDI_SUCCESS);
4887130Sms148562 }
4897130Sms148562 
4907130Sms148562 static int
4913446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4923446Smrj {
4933446Smrj 	agp_target_softstate_t *softstate;
4943446Smrj 	int instance;
4953446Smrj 	int status;
4963446Smrj 
4973446Smrj 	instance = ddi_get_instance(dip);
4983446Smrj 
4997130Sms148562 	switch (cmd) {
5007130Sms148562 	case DDI_ATTACH:
5017130Sms148562 		break;
5027130Sms148562 	case DDI_RESUME:
5037130Sms148562 		softstate =
5047130Sms148562 		    ddi_get_soft_state(agptarget_glob_soft_handle, instance);
5057130Sms148562 		return (intel_br_resume(softstate));
5067130Sms148562 	default:
5077130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
5087130Sms148562 		    "only attach and resume ops are supported"));
5093446Smrj 		return (DDI_FAILURE);
5107130Sms148562 	}
5117130Sms148562 
5127130Sms148562 	if (ddi_soft_state_zalloc(agptarget_glob_soft_handle,
5137130Sms148562 	    instance) != DDI_SUCCESS) {
5147130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
5157130Sms148562 		    "soft state zalloc failed"));
5167130Sms148562 		return (DDI_FAILURE);
5177130Sms148562 	}
5183446Smrj 
5193446Smrj 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
5203446Smrj 	mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL);
5213446Smrj 	softstate->tsoft_dip = dip;
5223446Smrj 	status = pci_config_setup(dip, &softstate->tsoft_pcihdl);
5233446Smrj 	if (status != DDI_SUCCESS) {
5247130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
5257130Sms148562 		    "pci config setup failed"));
5267130Sms148562 		ddi_soft_state_free(agptarget_glob_soft_handle,
5277130Sms148562 		    instance);
5283446Smrj 		return (DDI_FAILURE);
5293446Smrj 	}
5303446Smrj 
5313446Smrj 	softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl,
5323446Smrj 	    PCI_CONF_VENID);
5337130Sms148562 	softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid);
5347130Sms148562 	if (softstate->tsoft_gms_off < 0) {
5357130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
5367130Sms148562 		    "read gms offset failed"));
5377130Sms148562 		pci_config_teardown(&softstate->tsoft_pcihdl);
5387130Sms148562 		ddi_soft_state_free(agptarget_glob_soft_handle,
5397130Sms148562 		    instance);
5407130Sms148562 		return (DDI_FAILURE);
5417130Sms148562 	}
5423446Smrj 	softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl);
5433446Smrj 	if (softstate->tsoft_acaptr == 0) {
5443446Smrj 		/* Make a correction for some Intel chipsets */
5455131Sms148562 		if (is_intel_br(softstate))
5463446Smrj 			softstate->tsoft_acaptr = AGP_CAP_OFF_DEF;
5477130Sms148562 		else {
5487130Sms148562 			TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
5497130Sms148562 			    "Not a supposed corretion"));
5507130Sms148562 			pci_config_teardown(&softstate->tsoft_pcihdl);
5517130Sms148562 			ddi_soft_state_free(agptarget_glob_soft_handle,
5527130Sms148562 			    instance);
5533446Smrj 			return (DDI_FAILURE);
5547130Sms148562 		}
5553446Smrj 	}
5563446Smrj 
5573446Smrj 	status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR,
5583446Smrj 	    INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0);
5593446Smrj 
5603446Smrj 	if (status != DDI_SUCCESS) {
5617130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
5627130Sms148562 		    "Create minor node failed"));
5633446Smrj 		pci_config_teardown(&softstate->tsoft_pcihdl);
5643446Smrj 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
5653446Smrj 		return (DDI_FAILURE);
5663446Smrj 	}
5673446Smrj 
5683446Smrj 	return (DDI_SUCCESS);
5693446Smrj }
5703446Smrj 
5713446Smrj /*ARGSUSED*/
5723446Smrj static int
5733446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5743446Smrj {
5753446Smrj 	int instance;
5763446Smrj 	agp_target_softstate_t *softstate;
5773446Smrj 
5787130Sms148562 	instance = ddi_get_instance(dip);
5797130Sms148562 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
5803446Smrj 
5817130Sms148562 	if (cmd == DDI_SUSPEND) {
5827130Sms148562 		/* get GMS modes list entry */
5837130Sms148562 		return (intel_br_suspend(softstate));
5847130Sms148562 	}
5853446Smrj 
5867130Sms148562 	if (cmd != DDI_DETACH) {
5877130Sms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_detach:"
5887130Sms148562 		    "only detach and suspend ops are supported"));
5897130Sms148562 		return (DDI_FAILURE);
5907130Sms148562 	}
5913446Smrj 
5923446Smrj 	ddi_remove_minor_node(dip, AGPTARGET_NAME);
5933446Smrj 	pci_config_teardown(&softstate->tsoft_pcihdl);
5943446Smrj 	mutex_destroy(&softstate->tsoft_lock);
5953446Smrj 	ddi_soft_state_free(agptarget_glob_soft_handle, instance);
5963446Smrj 	return (DDI_SUCCESS);
5973446Smrj }
5983446Smrj 
5993446Smrj /*ARGSUSED*/
6003446Smrj static int
6013446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
6023446Smrj     cred_t *cred, int *rval)
6033446Smrj {
6043446Smrj 	int instance = DEV2INST(dev);
6053446Smrj 	agp_target_softstate_t *st;
6063446Smrj 	static char kernel_only[] =
6073446Smrj 	    "amd64_gart_ioctl: is a kernel only ioctl";
6083446Smrj 
6093446Smrj 	if (!(mode & FKIOCTL)) {
6103446Smrj 		TARGETDB_PRINT2((CE_CONT, kernel_only));
6113446Smrj 		return (ENXIO);
6123446Smrj 	}
6133446Smrj 	st = GETSOFTC(instance);
6143446Smrj 
6153446Smrj 	if (st == NULL)
6163446Smrj 		return (ENXIO);
6173446Smrj 
6183446Smrj 	mutex_enter(&st->tsoft_lock);
6193446Smrj 
6203446Smrj 	switch (cmd) {
6213446Smrj 	case CHIP_DETECT:
6223446Smrj 	{
6235131Sms148562 		int type = 0;
6245131Sms148562 
6255131Sms148562 		if (is_intel_br(st))
6263446Smrj 			type = CHIP_IS_INTEL;
6275131Sms148562 		else if (is_64bit_aper(st))
6283446Smrj 			type = CHIP_IS_AMD;
6295131Sms148562 		else {
6303446Smrj 			type = 0;
6315131Sms148562 			TARGETDB_PRINT2((CE_WARN, "Unknown bridge!"));
6323446Smrj 		}
6335131Sms148562 
6343446Smrj 		if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) {
6353446Smrj 			mutex_exit(&st->tsoft_lock);
6363446Smrj 			return (EFAULT);
6373446Smrj 		}
6383446Smrj 
6393446Smrj 		break;
6403446Smrj 	}
6413446Smrj 	case I8XX_GET_PREALLOC_SIZE:
6423446Smrj 	{
6433446Smrj 		size_t prealloc_size;
6443446Smrj 
6455131Sms148562 		if (!is_intel_br(st)) {
6463446Smrj 			mutex_exit(&st->tsoft_lock);
6473446Smrj 			return (EINVAL);
6483446Smrj 		}
6493446Smrj 
6503446Smrj 		prealloc_size = i8xx_biosmem_detect(st);
6513446Smrj 		if (ddi_copyout(&prealloc_size, (void *)data,
6523446Smrj 		    sizeof (size_t), mode)) {
6533446Smrj 			mutex_exit(&st->tsoft_lock);
6543446Smrj 			return (EFAULT);
6553446Smrj 		}
6563446Smrj 
6573446Smrj 		break;
6583446Smrj 	}
6593446Smrj 	case AGP_TARGET_GETINFO:
6603446Smrj 	{
6613446Smrj 		i_agp_info_t info;
6623446Smrj 		uint32_t value;
6633446Smrj 		off_t cap;
6643446Smrj 
6653446Smrj 		ASSERT(st->tsoft_acaptr);
6663446Smrj 
6673446Smrj 		cap = st->tsoft_acaptr;
6683446Smrj 		value = pci_config_get32(st->tsoft_pcihdl, cap);
6693446Smrj 		info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf);
6703446Smrj 		info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf);
6713446Smrj 		info.iagp_devid = st->tsoft_devid;
6723446Smrj 		info.iagp_mode = pci_config_get32(st->tsoft_pcihdl,
6734303Skz151634 		    cap + AGP_CONF_STATUS);
6743446Smrj 		info.iagp_aperbase = agp_target_get_apbase(st);
6753446Smrj 		info.iagp_apersize = agp_target_get_apsize(st);
6763446Smrj 
6773446Smrj 		if (ddi_copyout(&info, (void *)data,
6783446Smrj 		    sizeof (i_agp_info_t), mode)) {
6793446Smrj 			mutex_exit(&st->tsoft_lock);
6803446Smrj 			return (EFAULT);
6813446Smrj 		}
6823446Smrj 		break;
6833446Smrj 
6843446Smrj 	}
6853446Smrj 	/*
6863446Smrj 	 * This ioctl is only for Intel AGP chipsets.
6873446Smrj 	 * It is not necessary for the AMD8151 AGP bridge, because
6883446Smrj 	 * this register in the AMD8151 does not control any hardware.
6893446Smrj 	 * It is only provided for compatibility with an Intel AGP bridge.
6903446Smrj 	 * Please refer to the <<AMD8151 data sheet>> page 24,
6913446Smrj 	 * AGP device GART pointer.
6923446Smrj 	 */
6933446Smrj 	case AGP_TARGET_SET_GATTADDR:
6943446Smrj 	{
6953446Smrj 		uint32_t gartaddr;
6963446Smrj 
6973446Smrj 		if (ddi_copyin((void *)data, &gartaddr,
6983446Smrj 		    sizeof (uint32_t), mode)) {
6993446Smrj 			mutex_exit(&st->tsoft_lock);
7003446Smrj 			return (EFAULT);
7013446Smrj 		}
7023446Smrj 
7033446Smrj 		agp_target_set_gartaddr(st, gartaddr);
7043446Smrj 		break;
7053446Smrj 	}
7063446Smrj 	case AGP_TARGET_SETCMD:
7073446Smrj 	{
7083446Smrj 		uint32_t command;
7093446Smrj 
7103446Smrj 		if (ddi_copyin((void *)data, &command,
7113446Smrj 		    sizeof (uint32_t), mode)) {
7123446Smrj 			mutex_exit(&st->tsoft_lock);
7133446Smrj 			return (EFAULT);
7143446Smrj 		}
7153446Smrj 
7163446Smrj 		ASSERT(st->tsoft_acaptr);
7173446Smrj 
7183446Smrj 		pci_config_put32(st->tsoft_pcihdl,
7193446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
7203446Smrj 		    command);
7213446Smrj 		break;
7223446Smrj 
7233446Smrj 	}
7243446Smrj 	case AGP_TARGET_FLUSH_GTLB:
7253446Smrj 	{
7263446Smrj 		uint16_t value;
7273446Smrj 
7283446Smrj 		ASSERT(st->tsoft_acaptr);
7293446Smrj 
7303446Smrj 		value = pci_config_get16(st->tsoft_pcihdl,
7313446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL);
7323446Smrj 		value &= ~AGPCTRL_GTLBEN;
7333446Smrj 		pci_config_put16(st->tsoft_pcihdl,
7343446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
7353446Smrj 		value |= AGPCTRL_GTLBEN;
7363446Smrj 		pci_config_put16(st->tsoft_pcihdl,
7373446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
7383446Smrj 
7393446Smrj 		break;
7403446Smrj 	}
7413446Smrj 	case AGP_TARGET_CONFIGURE:
7423446Smrj 	{
7433446Smrj 		uint8_t value;
7443446Smrj 
7453446Smrj 		ASSERT(st->tsoft_acaptr);
7463446Smrj 
7475131Sms148562 		/*
7485131Sms148562 		 * In Intel agp bridges, agp misc register offset
7495131Sms148562 		 * is indexed from 0 instead of capability register.
7505131Sms148562 		 * AMD agp bridges have no such misc register
7515131Sms148562 		 * to control the aperture access, and they have
7525131Sms148562 		 * similar regsiters in CPU gart devices instead.
7535131Sms148562 		 */
7545131Sms148562 
7555131Sms148562 		if (is_intel_br(st)) {
7565131Sms148562 			value = pci_config_get8(st->tsoft_pcihdl,
7575131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC);
7585131Sms148562 			value |= AGP_MISC_APEN;
7595131Sms148562 			pci_config_put8(st->tsoft_pcihdl,
7605131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC, value);
7615131Sms148562 		}
7623446Smrj 		break;
7633446Smrj 
7643446Smrj 	}
7653446Smrj 	case AGP_TARGET_UNCONFIG:
7663446Smrj 	{
7673446Smrj 		uint32_t value1;
7683446Smrj 		uint8_t value2;
7693446Smrj 
7703446Smrj 		ASSERT(st->tsoft_acaptr);
7713446Smrj 
7723446Smrj 		pci_config_put16(st->tsoft_pcihdl,
7733446Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0);
7743446Smrj 
7755131Sms148562 		if (is_intel_br(st)) {
7765131Sms148562 			value2 = pci_config_get8(st->tsoft_pcihdl,
7775131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC);
7785131Sms148562 			value2 &= ~AGP_MISC_APEN;
7795131Sms148562 			pci_config_put8(st->tsoft_pcihdl,
7805131Sms148562 			    st->tsoft_acaptr + AGP_CONF_MISC, value2);
7815131Sms148562 		}
7823446Smrj 
7833446Smrj 		value1 = pci_config_get32(st->tsoft_pcihdl,
7843446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND);
7853446Smrj 		value1 &= ~AGPCMD_AGPEN;
7863446Smrj 		pci_config_put32(st->tsoft_pcihdl,
7873446Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
7883446Smrj 		    value1);
7893446Smrj 
7903446Smrj 		pci_config_put32(st->tsoft_pcihdl,
7913446Smrj 		    st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0);
7923446Smrj 
7933446Smrj 		break;
7943446Smrj 	}
7953446Smrj 
7963446Smrj 	default:
7973446Smrj 		mutex_exit(&st->tsoft_lock);
7983446Smrj 		return (ENXIO);
7993446Smrj 	} /* end switch */
8003446Smrj 
8013446Smrj 	mutex_exit(&st->tsoft_lock);
8023446Smrj 
8033446Smrj 	return (0);
8043446Smrj }
8053446Smrj 
8063446Smrj /*ARGSUSED*/
8073446Smrj static int
8083446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred)
8093446Smrj {
8103446Smrj 	int instance = DEV2INST(*devp);
8113446Smrj 	agp_target_softstate_t *st;
8123446Smrj 
8133446Smrj 	if (!(flag & FKLYR))
8143446Smrj 		return (ENXIO);
8153446Smrj 
8163446Smrj 	st = GETSOFTC(instance);
8173446Smrj 
8183446Smrj 	if (st == NULL)
8193446Smrj 		return (ENXIO);
8203446Smrj 
8213446Smrj 	return (0);
8223446Smrj }
8233446Smrj 
8243446Smrj /*ARGSUSED*/
8253446Smrj static int
8263446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred)
8273446Smrj {
8283446Smrj 	int instance = DEV2INST(dev);
8293446Smrj 	agp_target_softstate_t *st;
8303446Smrj 
8313446Smrj 	st = GETSOFTC(instance);
8323446Smrj 
8333446Smrj 	if (st == NULL)
8343446Smrj 		return (ENXIO);
8353446Smrj 
8363446Smrj 	return (0);
8373446Smrj }
8383446Smrj 
8393446Smrj static  struct  cb_ops  agp_target_cb_ops = {
8403446Smrj 	agp_target_open,		/* cb_open */
8413446Smrj 	agp_target_close,		/* cb_close */
8423446Smrj 	nodev,				/* cb_strategy */
8433446Smrj 	nodev,				/* cb_print */
8443446Smrj 	nodev,				/* cb_dump */
8453446Smrj 	nodev,				/* cb_read() */
8463446Smrj 	nodev,				/* cb_write() */
8473446Smrj 	agp_target_ioctl,		/* cb_ioctl */
8483446Smrj 	nodev,				/* cb_devmap */
8493446Smrj 	nodev,				/* cb_mmap */
8503446Smrj 	nodev,				/* cb_segmap */
8513446Smrj 	nochpoll,			/* cb_chpoll */
8523446Smrj 	ddi_prop_op,			/* cb_prop_op */
8533446Smrj 	0,				/* cb_stream */
8543446Smrj 	D_NEW | D_MP, 			/* cb_flag */
8553446Smrj 	CB_REV,				/* cb_ops version? */
8563446Smrj 	nodev,				/* cb_aread() */
8573446Smrj 	nodev,				/* cb_awrite() */
8583446Smrj };
8593446Smrj 
8603446Smrj /* device operations */
8613446Smrj static struct dev_ops agp_target_ops = {
8623446Smrj 	DEVO_REV,		/* devo_rev */
8633446Smrj 	0,			/* devo_refcnt */
8643446Smrj 	agptarget_getinfo, 	/* devo_getinfo */
8653446Smrj 	nulldev,		/* devo_identify */
8663446Smrj 	nulldev,		/* devo_probe */
8673446Smrj 	agp_target_attach,	/* devo_attach */
8683446Smrj 	agp_target_detach,	/* devo_detach */
8693446Smrj 	nodev,			/* devo_reset */
8703446Smrj 	&agp_target_cb_ops,	/* devo_cb_ops */
8713446Smrj 	0,			/* devo_bus_ops */
8723446Smrj 	0,			/* devo_power */
873*8328SMiao.Chen@Sun.COM 	ddi_quiesce_not_needed,	/* devo_quiesce */
8743446Smrj };
8753446Smrj 
8763446Smrj static  struct modldrv modldrv = {
8773446Smrj 	&mod_driverops,
8787130Sms148562 	"AGP target driver",
8793446Smrj 	&agp_target_ops,
8803446Smrj };
8813446Smrj 
8823446Smrj static  struct modlinkage modlinkage = {
8833446Smrj 	MODREV_1,		/* MODREV_1 is indicated by manual */
8843446Smrj 	{&modldrv, NULL, NULL, NULL}
8853446Smrj };
8863446Smrj 
8873446Smrj int
8883446Smrj _init(void)
8893446Smrj {
8903446Smrj 	int ret;
8913446Smrj 
8923446Smrj 	ret = ddi_soft_state_init(&agptarget_glob_soft_handle,
8933446Smrj 	    sizeof (agp_target_softstate_t), 1);
8943446Smrj 
8953446Smrj 	if (ret)
8963446Smrj 		goto err1;
8973446Smrj 
8983446Smrj 	if ((ret = mod_install(&modlinkage)) != 0) {
8993446Smrj 		goto err2;
9003446Smrj 	}
9013446Smrj 
9023446Smrj 	return (DDI_SUCCESS);
9033446Smrj err2:
9043446Smrj 	ddi_soft_state_fini(&agptarget_glob_soft_handle);
9053446Smrj err1:
9063446Smrj 	return (ret);
9073446Smrj }
9083446Smrj 
9093446Smrj int
9103446Smrj _info(struct  modinfo *modinfop)
9113446Smrj {
9123446Smrj 	return (mod_info(&modlinkage, modinfop));
9133446Smrj }
9143446Smrj 
9153446Smrj int
9163446Smrj _fini(void)
9173446Smrj {
9183446Smrj 	int	ret;
9193446Smrj 
9203446Smrj 	if ((ret = mod_remove(&modlinkage)) == 0) {
9213446Smrj 		ddi_soft_state_fini(&agptarget_glob_soft_handle);
9223446Smrj 	}
9233446Smrj 	return (ret);
9243446Smrj }
925