xref: /titanic_50/usr/src/uts/intel/io/agpgart/agptarget.c (revision 92d2c9e800f6d16b2980e28664926058477ef112)
1ae115bc7Smrj /*
2543414e0Skz151634  * CDDL HEADER START
3543414e0Skz151634  *
4543414e0Skz151634  * The contents of this file are subject to the terms of the
5543414e0Skz151634  * Common Development and Distribution License (the "License").
6543414e0Skz151634  * You may not use this file except in compliance with the License.
7543414e0Skz151634  *
8543414e0Skz151634  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9543414e0Skz151634  * or http://www.opensolaris.org/os/licensing.
10543414e0Skz151634  * See the License for the specific language governing permissions
11543414e0Skz151634  * and limitations under the License.
12543414e0Skz151634  *
13543414e0Skz151634  * When distributing Covered Code, include this CDDL HEADER in each
14543414e0Skz151634  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15543414e0Skz151634  * If applicable, add the following below this CDDL HEADER, with the
16543414e0Skz151634  * fields enclosed by brackets "[]" replaced with your own identifying
17543414e0Skz151634  * information: Portions Copyright [yyyy] [name of copyright owner]
18543414e0Skz151634  *
19543414e0Skz151634  * CDDL HEADER END
20543414e0Skz151634  */
21543414e0Skz151634 
22543414e0Skz151634 /*
230035d21cSmiao chen - Sun Microsystems - Beijing China  * Copyright (c) 2009, Intel Corporation.
240035d21cSmiao chen - Sun Microsystems - Beijing China  * All Rights Reserved.
250035d21cSmiao chen - Sun Microsystems - Beijing China  */
260035d21cSmiao chen - Sun Microsystems - Beijing China 
270035d21cSmiao chen - Sun Microsystems - Beijing China /*
28*92d2c9e8SEdward Shu  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
29ae115bc7Smrj  * Use is subject to license terms.
30ae115bc7Smrj  */
31ae115bc7Smrj 
32ae115bc7Smrj 
33ae115bc7Smrj #include <sys/systm.h>
34ae115bc7Smrj #include <sys/conf.h>
35ae115bc7Smrj #include <sys/modctl.h>
36ae115bc7Smrj #include <sys/file.h>
37ae115bc7Smrj #include <sys/stat.h>
38ae115bc7Smrj #include <sys/ddi.h>
39ae115bc7Smrj #include <sys/sunddi.h>
400035d21cSmiao chen - Sun Microsystems - Beijing China #include <sys/sunndi.h>
41ae115bc7Smrj #include <sys/modctl.h>
42ae115bc7Smrj #include <sys/sunldi.h>
43ae115bc7Smrj #include <sys/pci.h>
44ae115bc7Smrj #include <sys/agpgart.h>
45ae115bc7Smrj #include <sys/agp/agpdefs.h>
46ae115bc7Smrj #include <sys/agp/agptarget_io.h>
47ae115bc7Smrj 
48ae115bc7Smrj int agptarget_debug_var = 0;
49ae115bc7Smrj #define	TARGETDB_PRINT2(fmt)	if (agptarget_debug_var >= 1) cmn_err fmt
50ae115bc7Smrj #define	INST2NODENUM(inst)	(inst)
51ae115bc7Smrj #define	DEV2INST(dev)		(getminor(dev))
52ae115bc7Smrj 
530035d21cSmiao chen - Sun Microsystems - Beijing China #define	I915_IFPADDR	0x60
540035d21cSmiao chen - Sun Microsystems - Beijing China #define	I965_IFPADDR	0x70
550035d21cSmiao chen - Sun Microsystems - Beijing China 
560035d21cSmiao chen - Sun Microsystems - Beijing China #define	HIADDR(n)	((uint32_t)(((uint64_t)(n) & \
570035d21cSmiao chen - Sun Microsystems - Beijing China 			0xFFFFFFFF00000000ULL) >> 32))
580035d21cSmiao chen - Sun Microsystems - Beijing China #define	LOADDR(n)	((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
590035d21cSmiao chen - Sun Microsystems - Beijing China 
60ae115bc7Smrj typedef struct agp_target_softstate {
61ae115bc7Smrj 	dev_info_t		*tsoft_dip;
62ae115bc7Smrj 	ddi_acc_handle_t	tsoft_pcihdl;
63ae115bc7Smrj 	uint32_t		tsoft_devid;
64ae115bc7Smrj 	/* The offset of the ACAPID register */
65ae115bc7Smrj 	off_t			tsoft_acaptr;
66ae115bc7Smrj 	kmutex_t		tsoft_lock;
6731c83a1bSms148562 	int			tsoft_gms_off; /* GMS offset in config */
6831c83a1bSms148562 	uint32_t		tsoft_gms;
69ae115bc7Smrj }agp_target_softstate_t;
70ae115bc7Smrj 
71c4f91784Skz151634 /*
72c4f91784Skz151634  * To get the pre-allocated graphics mem size using Graphics Mode Select
73c4f91784Skz151634  * (GMS) value.
74c4f91784Skz151634  */
75c4f91784Skz151634 typedef struct gms_mode {
76c4f91784Skz151634 	uint32_t	gm_devid;	/* bridge vendor + device id */
77c4f91784Skz151634 	off_t		gm_regoff;	/* mode selection register offset */
78c4f91784Skz151634 	uint32_t	gm_mask;	/* GMS mask */
79c4f91784Skz151634 	uint32_t	gm_num;		/* number of modes in gm_vec */
80c4f91784Skz151634 	int 		*gm_vec;	/* modes array */
81c4f91784Skz151634 } gms_mode_t;
82c4f91784Skz151634 
83ae115bc7Smrj static void *agptarget_glob_soft_handle;
84ae115bc7Smrj 
85ae115bc7Smrj #define	GETSOFTC(instance)	((agp_target_softstate_t *)	\
86ae115bc7Smrj     ddi_get_soft_state(agptarget_glob_soft_handle, instance));
87ae115bc7Smrj 
88ae115bc7Smrj /*
89ae115bc7Smrj  * The AMD8151 bridge is the only supported 64 bit hardware
90ae115bc7Smrj  */
91ae115bc7Smrj static int
is_64bit_aper(agp_target_softstate_t * softstate)92ae115bc7Smrj is_64bit_aper(agp_target_softstate_t *softstate)
93ae115bc7Smrj {
94ae115bc7Smrj 	return (softstate->tsoft_devid == AMD_BR_8151);
95ae115bc7Smrj }
9631c83a1bSms148562 
973deb7cedSms148562 /*
983deb7cedSms148562  * Check if it is an intel bridge
993deb7cedSms148562  */
1003deb7cedSms148562 static int
is_intel_br(agp_target_softstate_t * softstate)1013deb7cedSms148562 is_intel_br(agp_target_softstate_t *softstate)
1023deb7cedSms148562 {
1033deb7cedSms148562 	return ((softstate->tsoft_devid & VENDOR_ID_MASK) ==
1043deb7cedSms148562 	    INTEL_VENDOR_ID);
1053deb7cedSms148562 }
106ae115bc7Smrj 
107ae115bc7Smrj /*
108ae115bc7Smrj  * agp_target_cap_find()
109ae115bc7Smrj  *
110ae115bc7Smrj  * Description:
111ae115bc7Smrj  * 	This function searches the linked capability list to find the offset
112ae115bc7Smrj  * 	of the AGP capability register. When it was not found, return 0.
113ae115bc7Smrj  * 	This works for standard AGP chipsets, but not for some Intel chipsets,
114ae115bc7Smrj  * 	like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for
115ae115bc7Smrj  * 	these chipsets even if AGP is supported. So the offset of acapid
116ae115bc7Smrj  * 	should be set manually in thoses cases.
117ae115bc7Smrj  *
118ae115bc7Smrj  * Arguments:
119ae115bc7Smrj  * 	pci_handle		ddi acc handle of pci config
120ae115bc7Smrj  *
121ae115bc7Smrj  * Returns:
122ae115bc7Smrj  * 	0			No capability pointer register found
123ae115bc7Smrj  * 	nexcap			The AGP capability pointer register offset
124ae115bc7Smrj  */
125ae115bc7Smrj static off_t
agp_target_cap_find(ddi_acc_handle_t pci_handle)126ae115bc7Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle)
127ae115bc7Smrj {
128ae115bc7Smrj 	off_t		nextcap = 0;
129ae115bc7Smrj 	uint32_t	ncapid = 0;
130ae115bc7Smrj 	uint8_t		value = 0;
131ae115bc7Smrj 
132ae115bc7Smrj 	/* Check if this device supports the capability pointer */
133ae115bc7Smrj 	value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT)
134ae115bc7Smrj 	    & PCI_CONF_CAP_MASK);
135ae115bc7Smrj 
136ae115bc7Smrj 	if (!value)
137ae115bc7Smrj 		return (0);
138ae115bc7Smrj 	/* Get the offset of the first capability pointer from CAPPTR */
139ae115bc7Smrj 	nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR));
140ae115bc7Smrj 
141ae115bc7Smrj 	/* Check the AGP capability from the first capability pointer */
142ae115bc7Smrj 	while (nextcap) {
143ae115bc7Smrj 		ncapid = pci_config_get32(pci_handle, nextcap);
144ae115bc7Smrj 		/*
145ae115bc7Smrj 		 * AGP3.0 rev1.0 127  the capid was assigned by the PCI SIG,
146ae115bc7Smrj 		 * 845 data sheet page 69
147ae115bc7Smrj 		 */
148ae115bc7Smrj 		if ((ncapid & PCI_CONF_CAPID_MASK) ==
149ae115bc7Smrj 		    AGP_CAP_ID) /* The AGP cap was found */
150ae115bc7Smrj 			break;
151ae115bc7Smrj 
152ae115bc7Smrj 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
153ae115bc7Smrj 	}
154ae115bc7Smrj 
155ae115bc7Smrj 	return (nextcap);
156ae115bc7Smrj 
157ae115bc7Smrj }
158ae115bc7Smrj 
159ae115bc7Smrj /*
160ae115bc7Smrj  * agp_target_get_aperbase()
161ae115bc7Smrj  *
162ae115bc7Smrj  * Description:
163ae115bc7Smrj  * 	This function gets the AGP aperture base address from the AGP target
164ae115bc7Smrj  *	register, the AGP aperture base register was programmed by the BIOS.
165ae115bc7Smrj  *
166ae115bc7Smrj  * Arguments:
167ae115bc7Smrj  * 	softstate		driver soft state pointer
168ae115bc7Smrj  *
169ae115bc7Smrj  * Returns:
170ae115bc7Smrj  * 	aper_base 		AGP aperture base address
171ae115bc7Smrj  *
172ae115bc7Smrj  * Notes:
173ae115bc7Smrj  * 	If a 64bit bridge device is available, the AGP aperture base address
174ae115bc7Smrj  * 	can be 64 bit.
175ae115bc7Smrj  */
176ae115bc7Smrj static uint64_t
agp_target_get_apbase(agp_target_softstate_t * softstate)177ae115bc7Smrj agp_target_get_apbase(agp_target_softstate_t *softstate)
178ae115bc7Smrj {
179ae115bc7Smrj 	uint64_t aper_base;
180ae115bc7Smrj 
1813deb7cedSms148562 	if (is_intel_br(softstate)) {
182ae115bc7Smrj 		aper_base = pci_config_get32(softstate->tsoft_pcihdl,
183ae115bc7Smrj 		    AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK;
1843deb7cedSms148562 	} else if (is_64bit_aper(softstate)) {
185ae115bc7Smrj 		aper_base = pci_config_get64(softstate->tsoft_pcihdl,
186ae115bc7Smrj 		    AGP_CONF_APERBASE);
187ae115bc7Smrj 		/* 32-bit or 64-bit aperbase base pointer */
188ae115bc7Smrj 		if ((aper_base & AGP_APER_TYPE_MASK) == 0)
189ae115bc7Smrj 			aper_base &= AGP_32_APERBASE_MASK;
190ae115bc7Smrj 		else
191ae115bc7Smrj 			aper_base &= AGP_64_APERBASE_MASK;
192ae115bc7Smrj 	}
1933deb7cedSms148562 
194ae115bc7Smrj 	return (aper_base);
195ae115bc7Smrj }
196ae115bc7Smrj 
197ae115bc7Smrj /*
198ae115bc7Smrj  * agp_target_get_apsize()
199ae115bc7Smrj  *
200ae115bc7Smrj  * Description:
201ae115bc7Smrj  * 	This function gets the AGP aperture size by reading the AGP aperture
202ae115bc7Smrj  * 	size register.
203ae115bc7Smrj  * Arguments:
204ae115bc7Smrj  * 	softstate		driver soft state pointer
205ae115bc7Smrj  *
206ae115bc7Smrj  * Return:
207ae115bc7Smrj  * 	size		The AGP aperture size in megabytes
208ae115bc7Smrj  * 	0		an unexpected error
209ae115bc7Smrj  */
210ae115bc7Smrj static size_t
agp_target_get_apsize(agp_target_softstate_t * softstate)211ae115bc7Smrj agp_target_get_apsize(agp_target_softstate_t *softstate)
212ae115bc7Smrj {
213ae115bc7Smrj 	off_t cap;
214ae115bc7Smrj 	uint16_t value;
215ae115bc7Smrj 	size_t size, regsize;
216ae115bc7Smrj 
217ae115bc7Smrj 	ASSERT(softstate->tsoft_acaptr);
218ae115bc7Smrj 	cap = softstate->tsoft_acaptr;
219ae115bc7Smrj 
2203deb7cedSms148562 	if (is_intel_br(softstate)) {
221ae115bc7Smrj 		/* extend this value to 16 bit for later tests */
222ae115bc7Smrj 		value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl,
223ae115bc7Smrj 		    cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK;
2243deb7cedSms148562 	} else if (is_64bit_aper(softstate)) {
225ae115bc7Smrj 		value = pci_config_get16(softstate->tsoft_pcihdl,
226ae115bc7Smrj 		    cap + AGP_CONF_APERSIZE);
227ae115bc7Smrj 	}
228ae115bc7Smrj 
229ae115bc7Smrj 	if (value & AGP_APER_128M_MASK) {
230ae115bc7Smrj 		switch (value & AGP_APER_128M_MASK) {
231ae115bc7Smrj 			case AGP_APER_4M:
232ae115bc7Smrj 				size = 4; /* 4M */
233ae115bc7Smrj 				break;
234ae115bc7Smrj 			case AGP_APER_8M:
235ae115bc7Smrj 				size = 8; /* 8M */
236ae115bc7Smrj 				break;
237ae115bc7Smrj 			case AGP_APER_16M:
238ae115bc7Smrj 				size = 16; /* 16M */
239ae115bc7Smrj 				break;
240ae115bc7Smrj 			case AGP_APER_32M:
241ae115bc7Smrj 				size = 32; /* 32M */
242ae115bc7Smrj 				break;
243ae115bc7Smrj 			case AGP_APER_64M:
244ae115bc7Smrj 				size = 64; /* 64M */
245ae115bc7Smrj 				break;
246ae115bc7Smrj 			case AGP_APER_128M:
247ae115bc7Smrj 				size = 128; /* 128M */
248ae115bc7Smrj 				break;
249ae115bc7Smrj 			default:
250ae115bc7Smrj 				size = 0; /* not true */
251ae115bc7Smrj 		}
252ae115bc7Smrj 	} else {
253ae115bc7Smrj 		switch (value & AGP_APER_4G_MASK) {
254ae115bc7Smrj 			case AGP_APER_256M:
255ae115bc7Smrj 				size = 256; /* 256 M */
256ae115bc7Smrj 				break;
257ae115bc7Smrj 			case AGP_APER_512M:
258ae115bc7Smrj 				size = 512; /* 512 M */
259ae115bc7Smrj 				break;
260ae115bc7Smrj 			case AGP_APER_1024M:
261ae115bc7Smrj 				size = 1024; /* 1024 M */
262ae115bc7Smrj 				break;
263ae115bc7Smrj 			case AGP_APER_2048M:
264ae115bc7Smrj 				size = 2048; /* 2048 M */
265ae115bc7Smrj 				break;
266ae115bc7Smrj 			case AGP_APER_4G:
267ae115bc7Smrj 				size = 4096; /* 4096 M */
268ae115bc7Smrj 				break;
269ae115bc7Smrj 			default:
270ae115bc7Smrj 				size = 0; /* not true */
271ae115bc7Smrj 		}
272ae115bc7Smrj 	}
273ae115bc7Smrj 	/*
274ae115bc7Smrj 	 * In some cases, there is no APSIZE register, so the size value
275ae115bc7Smrj 	 * of 256M could be wrong. Check the value by reading the size of
276ae115bc7Smrj 	 * the first register which was set in the PCI configuration space.
277ae115bc7Smrj 	 */
278ae115bc7Smrj 	if (size == 256) {
279ae115bc7Smrj 		if (ddi_dev_regsize(softstate->tsoft_dip,
280ae115bc7Smrj 		    AGP_TARGET_BAR1, (off_t *)&regsize) == DDI_FAILURE)
281ae115bc7Smrj 			return (0);
282ae115bc7Smrj 
283ae115bc7Smrj 		if (MB2BYTES(size) != regsize) {
284ae115bc7Smrj 			TARGETDB_PRINT2((CE_WARN,
285ae115bc7Smrj 			    "APSIZE 256M doesn't match regsize %lx",
286ae115bc7Smrj 			    regsize));
287ae115bc7Smrj 			TARGETDB_PRINT2((CE_WARN, "Use regsize instead"));
288ae115bc7Smrj 			size = BYTES2MB(regsize);
289ae115bc7Smrj 		}
290ae115bc7Smrj 	}
291ae115bc7Smrj 
292ae115bc7Smrj 	return (size);
293ae115bc7Smrj }
294ae115bc7Smrj 
295ae115bc7Smrj static void
agp_target_set_gartaddr(agp_target_softstate_t * softstate,uint32_t gartaddr)296ae115bc7Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr)
297ae115bc7Smrj {
298ae115bc7Smrj 	ASSERT(softstate->tsoft_acaptr);
299ae115bc7Smrj 
300ae115bc7Smrj 	/* Disable the GTLB for Intel chipsets */
301ae115bc7Smrj 	pci_config_put16(softstate->tsoft_pcihdl,
302ae115bc7Smrj 	    softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000);
303ae115bc7Smrj 
304ae115bc7Smrj 	pci_config_put32(softstate->tsoft_pcihdl,
305ae115bc7Smrj 	    softstate->tsoft_acaptr + AGP_CONF_ATTBASE,
306ae115bc7Smrj 	    gartaddr & AGP_ATTBASE_MASK);
307ae115bc7Smrj }
308ae115bc7Smrj 
309c4f91784Skz151634 /*
310c4f91784Skz151634  * Pre-allocated graphics memory for every type of Intel north bridge, mem size
311c4f91784Skz151634  * are specified in kbytes.
312c4f91784Skz151634  */
313c4f91784Skz151634 #define	GMS_MB(n) 	((n) * 1024)
314c4f91784Skz151634 #define	GMS_SHIFT 	4
315c4f91784Skz151634 #define	GMS_SIZE(a)	(sizeof (a) / sizeof (int))
316c4f91784Skz151634 
317c4f91784Skz151634 /*
318c4f91784Skz151634  * Since value zero always means "No memory pre-allocated", value of (GMS - 1)
319c4f91784Skz151634  * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb)
320c4f91784Skz151634  * that GMS value 0x1 corresponding to.
321c4f91784Skz151634  *
322c4f91784Skz151634  * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics
323c4f91784Skz151634  * memory, unless some special BIOS settings exist.
324c4f91784Skz151634  */
325c4f91784Skz151634 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)};
326c4f91784Skz151634 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)};
327c4f91784Skz151634 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
328c4f91784Skz151634 	GMS_MB(32)};
329c4f91784Skz151634 /* There is no modes for 16M in datasheet, but some BIOS add it. */
330c4f91784Skz151634 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)};
331c4f91784Skz151634 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)};
332c4f91784Skz151634 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
333c4f91784Skz151634 	GMS_MB(32), GMS_MB(48), GMS_MB(64)};
334c4f91784Skz151634 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
335c4f91784Skz151634 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)};
336fc6df3bdSmiao chen - Sun Microsystems - Beijing China static int gms_G4X[13] = {0, 0, 0, 0,
337fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256),
338fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)};
339c4f91784Skz151634 
340c4f91784Skz151634 static gms_mode_t gms_modes[] = {
341c4f91784Skz151634 	{INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK,
342c4f91784Skz151634 		GMS_SIZE(gms_810), gms_810},
343c4f91784Skz151634 	{INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK,
344c4f91784Skz151634 		GMS_SIZE(gms_810), gms_810},
345c4f91784Skz151634 	{INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK,
346c4f91784Skz151634 		GMS_SIZE(gms_810), gms_810},
347c4f91784Skz151634 	{INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
348c4f91784Skz151634 		GMS_SIZE(gms_830_845), gms_830_845},
349c4f91784Skz151634 	{INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
350c4f91784Skz151634 		GMS_SIZE(gms_830_845), gms_830_845},
351c4f91784Skz151634 	{INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
352c4f91784Skz151634 		GMS_SIZE(gms_855GM), gms_855GM},
353c4f91784Skz151634 	{INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
354c4f91784Skz151634 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
355c4f91784Skz151634 	{INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
356c4f91784Skz151634 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
357c4f91784Skz151634 	{INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
358c4f91784Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
359c4f91784Skz151634 	{INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
360c4f91784Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
361c4f91784Skz151634 	{INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
362c4f91784Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
36312db04d3Smiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
36412db04d3Smiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
365c4f91784Skz151634 	{INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
366c4f91784Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
367c4f91784Skz151634 	{INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
368c4f91784Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
369c4f91784Skz151634 	{INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
370c4f91784Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
371c4f91784Skz151634 	{INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
372c4f91784Skz151634 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
373c4f91784Skz151634 	{INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
374c4f91784Skz151634 		GMS_SIZE(gms_965GM), gms_965GM},
375c4f91784Skz151634 	{INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
376c4f91784Skz151634 		GMS_SIZE(gms_965GM), gms_965GM},
377c4f91784Skz151634 	{INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK,
378c4f91784Skz151634 		GMS_SIZE(gms_X33), gms_X33},
379c4f91784Skz151634 	{INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
380c4f91784Skz151634 		GMS_SIZE(gms_X33), gms_X33},
381c4f91784Skz151634 	{INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
382219cee99Smc196098 		GMS_SIZE(gms_X33), gms_X33},
383219cee99Smc196098 	{INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
384fc6df3bdSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_965GM), gms_965GM},
385fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
386fc6df3bdSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
387fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
388fc6df3bdSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
389fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
390d0231070Smiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
391d0231070Smiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3920035d21cSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
3932e6e901dSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_IGDNG_D, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3942e6e901dSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
3952e6e901dSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_IGDNG_M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3962e6e901dSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
3972e6e901dSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_IGDNG_MA, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
3982e6e901dSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
3992e6e901dSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_IGDNG_MC2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
4002e6e901dSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X},
4010035d21cSmiao chen - Sun Microsystems - Beijing China 	{INTEL_BR_B43, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
402fc6df3bdSmiao chen - Sun Microsystems - Beijing China 		GMS_SIZE(gms_G4X), gms_G4X}
403c4f91784Skz151634 };
40431c83a1bSms148562 static int
get_chip_gms(uint32_t devid)40531c83a1bSms148562 get_chip_gms(uint32_t devid)
40631c83a1bSms148562 {
40731c83a1bSms148562 	int num_modes;
40831c83a1bSms148562 	int i;
40931c83a1bSms148562 
41031c83a1bSms148562 	num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t));
41131c83a1bSms148562 
41231c83a1bSms148562 	for (i = 0; i < num_modes; i++) {
41331c83a1bSms148562 		if (gms_modes[i].gm_devid == devid)
41431c83a1bSms148562 			break;
41531c83a1bSms148562 	}
41631c83a1bSms148562 
41731c83a1bSms148562 	return ((i == num_modes) ? -1 : i);
41831c83a1bSms148562 }
419c4f91784Skz151634 
420c4f91784Skz151634 /* Returns the size (kbytes) of pre-allocated graphics memory */
421ae115bc7Smrj static size_t
i8xx_biosmem_detect(agp_target_softstate_t * softstate)422ae115bc7Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate)
423ae115bc7Smrj {
424ae115bc7Smrj 	uint8_t memval;
425ae115bc7Smrj 	size_t kbytes;
42631c83a1bSms148562 	int	gms_off;
427ae115bc7Smrj 
428ae115bc7Smrj 	kbytes = 0;
42931c83a1bSms148562 	gms_off = softstate->tsoft_gms_off;
43031c83a1bSms148562 
431c4f91784Skz151634 	/* fetch the GMS value from DRAM controller */
432c4f91784Skz151634 	memval = pci_config_get8(softstate->tsoft_pcihdl,
43331c83a1bSms148562 	    gms_modes[gms_off].gm_regoff);
434c4f91784Skz151634 	TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval));
43531c83a1bSms148562 	memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT;
436c4f91784Skz151634 	/* assuming zero byte for 0 or "reserved" GMS values */
43731c83a1bSms148562 	if (memval == 0 || memval > gms_modes[gms_off].gm_num) {
438c4f91784Skz151634 		TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: "
439c4f91784Skz151634 		    "devid = %x, GMS = %x. assuming zero byte of "
44031c83a1bSms148562 		    "pre-allocated memory",
44131c83a1bSms148562 		    gms_modes[gms_off].gm_devid, memval));
442c4f91784Skz151634 		goto done;
443c4f91784Skz151634 	}
444c4f91784Skz151634 	memval--;	/* use (GMS_value - 1) as index */
44531c83a1bSms148562 	kbytes = (gms_modes[gms_off].gm_vec)[memval];
446ae115bc7Smrj 
447c4f91784Skz151634 done:
448543414e0Skz151634 	TARGETDB_PRINT2((CE_NOTE,
449543414e0Skz151634 	    "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected",
450543414e0Skz151634 	    kbytes));
451ae115bc7Smrj 	return (kbytes);
452ae115bc7Smrj }
453ae115bc7Smrj 
454ae115bc7Smrj /*ARGSUSED*/
agptarget_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)455ae115bc7Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
456ae115bc7Smrj     void *arg, void **resultp)
457ae115bc7Smrj {
458ae115bc7Smrj 	agp_target_softstate_t *st;
459ae115bc7Smrj 	int instance, rval = DDI_FAILURE;
460ae115bc7Smrj 	dev_t dev;
461ae115bc7Smrj 
462ae115bc7Smrj 	switch (cmd) {
463ae115bc7Smrj 	case DDI_INFO_DEVT2DEVINFO:
464ae115bc7Smrj 		dev = (dev_t)arg;
465ae115bc7Smrj 		instance = DEV2INST(dev);
466ae115bc7Smrj 		st = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
467ae115bc7Smrj 		if (st != NULL) {
468ae115bc7Smrj 			mutex_enter(&st->tsoft_lock);
469ae115bc7Smrj 			*resultp = st->tsoft_dip;
470ae115bc7Smrj 			mutex_exit(&st->tsoft_lock);
471ae115bc7Smrj 			rval = DDI_SUCCESS;
472ae115bc7Smrj 		} else
473ae115bc7Smrj 			*resultp = NULL;
474ae115bc7Smrj 
475ae115bc7Smrj 		break;
476ae115bc7Smrj 	case DDI_INFO_DEVT2INSTANCE:
477ae115bc7Smrj 		dev = (dev_t)arg;
478ae115bc7Smrj 		instance = DEV2INST(dev);
479ae115bc7Smrj 		*resultp = (void *)(uintptr_t)instance;
480ae115bc7Smrj 		rval = DDI_SUCCESS;
481ae115bc7Smrj 	default:
482ae115bc7Smrj 		break;
483ae115bc7Smrj 	}
484ae115bc7Smrj 
485ae115bc7Smrj 	return (rval);
486ae115bc7Smrj }
487ae115bc7Smrj 
488ae115bc7Smrj static int
intel_br_resume(agp_target_softstate_t * softstate)48931c83a1bSms148562 intel_br_resume(agp_target_softstate_t *softstate)
49031c83a1bSms148562 {
49131c83a1bSms148562 	int gms_off;
49231c83a1bSms148562 
49331c83a1bSms148562 	gms_off = softstate->tsoft_gms_off;
49431c83a1bSms148562 
49531c83a1bSms148562 	/*
49631c83a1bSms148562 	 * We recover the gmch graphics control register here
49731c83a1bSms148562 	 */
49831c83a1bSms148562 	pci_config_put16(softstate->tsoft_pcihdl,
49931c83a1bSms148562 	    gms_modes[gms_off].gm_regoff, softstate->tsoft_gms);
50031c83a1bSms148562 
50131c83a1bSms148562 	return (DDI_SUCCESS);
50231c83a1bSms148562 }
50331c83a1bSms148562 static int
intel_br_suspend(agp_target_softstate_t * softstate)50431c83a1bSms148562 intel_br_suspend(agp_target_softstate_t *softstate)
50531c83a1bSms148562 {
50631c83a1bSms148562 	int gms_off;
50731c83a1bSms148562 
50831c83a1bSms148562 	gms_off = softstate->tsoft_gms_off;
50931c83a1bSms148562 	softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl,
51031c83a1bSms148562 	    gms_modes[gms_off].gm_regoff);
51131c83a1bSms148562 
51231c83a1bSms148562 	return (DDI_SUCCESS);
51331c83a1bSms148562 }
51431c83a1bSms148562 
51531c83a1bSms148562 static int
agp_target_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)516ae115bc7Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
517ae115bc7Smrj {
518ae115bc7Smrj 	agp_target_softstate_t *softstate;
519ae115bc7Smrj 	int instance;
520ae115bc7Smrj 	int status;
521ae115bc7Smrj 
522ae115bc7Smrj 	instance = ddi_get_instance(dip);
523ae115bc7Smrj 
52431c83a1bSms148562 	switch (cmd) {
52531c83a1bSms148562 	case DDI_ATTACH:
52631c83a1bSms148562 		break;
52731c83a1bSms148562 	case DDI_RESUME:
52831c83a1bSms148562 		softstate =
52931c83a1bSms148562 		    ddi_get_soft_state(agptarget_glob_soft_handle, instance);
53031c83a1bSms148562 		return (intel_br_resume(softstate));
53131c83a1bSms148562 	default:
53231c83a1bSms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
53331c83a1bSms148562 		    "only attach and resume ops are supported"));
534ae115bc7Smrj 		return (DDI_FAILURE);
53531c83a1bSms148562 	}
53631c83a1bSms148562 
53731c83a1bSms148562 	if (ddi_soft_state_zalloc(agptarget_glob_soft_handle,
53831c83a1bSms148562 	    instance) != DDI_SUCCESS) {
53931c83a1bSms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
54031c83a1bSms148562 		    "soft state zalloc failed"));
54131c83a1bSms148562 		return (DDI_FAILURE);
54231c83a1bSms148562 	}
543ae115bc7Smrj 
544ae115bc7Smrj 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
545ae115bc7Smrj 	mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL);
546ae115bc7Smrj 	softstate->tsoft_dip = dip;
547ae115bc7Smrj 	status = pci_config_setup(dip, &softstate->tsoft_pcihdl);
548ae115bc7Smrj 	if (status != DDI_SUCCESS) {
54931c83a1bSms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
55031c83a1bSms148562 		    "pci config setup failed"));
55131c83a1bSms148562 		ddi_soft_state_free(agptarget_glob_soft_handle,
55231c83a1bSms148562 		    instance);
553ae115bc7Smrj 		return (DDI_FAILURE);
554ae115bc7Smrj 	}
555ae115bc7Smrj 
556ae115bc7Smrj 	softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl,
557ae115bc7Smrj 	    PCI_CONF_VENID);
55831c83a1bSms148562 	softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid);
55931c83a1bSms148562 	if (softstate->tsoft_gms_off < 0) {
56031c83a1bSms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
56131c83a1bSms148562 		    "read gms offset failed"));
56231c83a1bSms148562 		pci_config_teardown(&softstate->tsoft_pcihdl);
56331c83a1bSms148562 		ddi_soft_state_free(agptarget_glob_soft_handle,
56431c83a1bSms148562 		    instance);
56531c83a1bSms148562 		return (DDI_FAILURE);
56631c83a1bSms148562 	}
567ae115bc7Smrj 	softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl);
568ae115bc7Smrj 	if (softstate->tsoft_acaptr == 0) {
569ae115bc7Smrj 		/* Make a correction for some Intel chipsets */
5703deb7cedSms148562 		if (is_intel_br(softstate))
571ae115bc7Smrj 			softstate->tsoft_acaptr = AGP_CAP_OFF_DEF;
57231c83a1bSms148562 		else {
57331c83a1bSms148562 			TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
57431c83a1bSms148562 			    "Not a supposed corretion"));
57531c83a1bSms148562 			pci_config_teardown(&softstate->tsoft_pcihdl);
57631c83a1bSms148562 			ddi_soft_state_free(agptarget_glob_soft_handle,
57731c83a1bSms148562 			    instance);
578ae115bc7Smrj 			return (DDI_FAILURE);
579ae115bc7Smrj 		}
58031c83a1bSms148562 	}
581ae115bc7Smrj 
582ae115bc7Smrj 	status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR,
583ae115bc7Smrj 	    INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0);
584ae115bc7Smrj 
585ae115bc7Smrj 	if (status != DDI_SUCCESS) {
58631c83a1bSms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
58731c83a1bSms148562 		    "Create minor node failed"));
588ae115bc7Smrj 		pci_config_teardown(&softstate->tsoft_pcihdl);
589ae115bc7Smrj 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
590ae115bc7Smrj 		return (DDI_FAILURE);
591ae115bc7Smrj 	}
592ae115bc7Smrj 
593ae115bc7Smrj 	return (DDI_SUCCESS);
594ae115bc7Smrj }
595ae115bc7Smrj 
596ae115bc7Smrj /*ARGSUSED*/
597ae115bc7Smrj static int
agp_target_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)598ae115bc7Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
599ae115bc7Smrj {
600ae115bc7Smrj 	int instance;
601ae115bc7Smrj 	agp_target_softstate_t *softstate;
602ae115bc7Smrj 
603ae115bc7Smrj 	instance = ddi_get_instance(dip);
604ae115bc7Smrj 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
605ae115bc7Smrj 
60631c83a1bSms148562 	if (cmd == DDI_SUSPEND) {
60731c83a1bSms148562 		/* get GMS modes list entry */
60831c83a1bSms148562 		return (intel_br_suspend(softstate));
60931c83a1bSms148562 	}
61031c83a1bSms148562 
61131c83a1bSms148562 	if (cmd != DDI_DETACH) {
61231c83a1bSms148562 		TARGETDB_PRINT2((CE_WARN, "agp_target_detach:"
61331c83a1bSms148562 		    "only detach and suspend ops are supported"));
61431c83a1bSms148562 		return (DDI_FAILURE);
61531c83a1bSms148562 	}
61631c83a1bSms148562 
617ae115bc7Smrj 	ddi_remove_minor_node(dip, AGPTARGET_NAME);
618ae115bc7Smrj 	pci_config_teardown(&softstate->tsoft_pcihdl);
619ae115bc7Smrj 	mutex_destroy(&softstate->tsoft_lock);
620ae115bc7Smrj 	ddi_soft_state_free(agptarget_glob_soft_handle, instance);
621ae115bc7Smrj 	return (DDI_SUCCESS);
622ae115bc7Smrj }
623ae115bc7Smrj 
624ae115bc7Smrj /*ARGSUSED*/
625ae115bc7Smrj static int
agp_target_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval)626ae115bc7Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
627ae115bc7Smrj     cred_t *cred, int *rval)
628ae115bc7Smrj {
629ae115bc7Smrj 	int instance = DEV2INST(dev);
630ae115bc7Smrj 	agp_target_softstate_t *st;
631ae115bc7Smrj 	static char kernel_only[] =
632ae115bc7Smrj 	    "amd64_gart_ioctl: is a kernel only ioctl";
633ae115bc7Smrj 
634ae115bc7Smrj 	if (!(mode & FKIOCTL)) {
635ae115bc7Smrj 		TARGETDB_PRINT2((CE_CONT, kernel_only));
636ae115bc7Smrj 		return (ENXIO);
637ae115bc7Smrj 	}
638ae115bc7Smrj 	st = GETSOFTC(instance);
639ae115bc7Smrj 
640ae115bc7Smrj 	if (st == NULL)
641ae115bc7Smrj 		return (ENXIO);
642ae115bc7Smrj 
643ae115bc7Smrj 	mutex_enter(&st->tsoft_lock);
644ae115bc7Smrj 
645ae115bc7Smrj 	switch (cmd) {
646ae115bc7Smrj 	case CHIP_DETECT:
647ae115bc7Smrj 	{
6483deb7cedSms148562 		int type = 0;
6493deb7cedSms148562 
6503deb7cedSms148562 		if (is_intel_br(st))
651ae115bc7Smrj 			type = CHIP_IS_INTEL;
6523deb7cedSms148562 		else if (is_64bit_aper(st))
653ae115bc7Smrj 			type = CHIP_IS_AMD;
6543deb7cedSms148562 		else {
655ae115bc7Smrj 			type = 0;
6563deb7cedSms148562 			TARGETDB_PRINT2((CE_WARN, "Unknown bridge!"));
657ae115bc7Smrj 		}
6583deb7cedSms148562 
659ae115bc7Smrj 		if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) {
660ae115bc7Smrj 			mutex_exit(&st->tsoft_lock);
661ae115bc7Smrj 			return (EFAULT);
662ae115bc7Smrj 		}
663ae115bc7Smrj 
664ae115bc7Smrj 		break;
665ae115bc7Smrj 	}
666ae115bc7Smrj 	case I8XX_GET_PREALLOC_SIZE:
667ae115bc7Smrj 	{
668ae115bc7Smrj 		size_t prealloc_size;
669ae115bc7Smrj 
6703deb7cedSms148562 		if (!is_intel_br(st)) {
671ae115bc7Smrj 			mutex_exit(&st->tsoft_lock);
672ae115bc7Smrj 			return (EINVAL);
673ae115bc7Smrj 		}
674ae115bc7Smrj 
675ae115bc7Smrj 		prealloc_size = i8xx_biosmem_detect(st);
676ae115bc7Smrj 		if (ddi_copyout(&prealloc_size, (void *)data,
677ae115bc7Smrj 		    sizeof (size_t), mode)) {
678ae115bc7Smrj 			mutex_exit(&st->tsoft_lock);
679ae115bc7Smrj 			return (EFAULT);
680ae115bc7Smrj 		}
681ae115bc7Smrj 
682ae115bc7Smrj 		break;
683ae115bc7Smrj 	}
684ae115bc7Smrj 	case AGP_TARGET_GETINFO:
685ae115bc7Smrj 	{
686ae115bc7Smrj 		i_agp_info_t info;
687ae115bc7Smrj 		uint32_t value;
688ae115bc7Smrj 		off_t cap;
689ae115bc7Smrj 
690ae115bc7Smrj 		ASSERT(st->tsoft_acaptr);
691ae115bc7Smrj 
692ae115bc7Smrj 		cap = st->tsoft_acaptr;
693ae115bc7Smrj 		value = pci_config_get32(st->tsoft_pcihdl, cap);
694ae115bc7Smrj 		info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf);
695ae115bc7Smrj 		info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf);
696ae115bc7Smrj 		info.iagp_devid = st->tsoft_devid;
697ae115bc7Smrj 		info.iagp_mode = pci_config_get32(st->tsoft_pcihdl,
698ae115bc7Smrj 		    cap + AGP_CONF_STATUS);
699ae115bc7Smrj 		info.iagp_aperbase = agp_target_get_apbase(st);
700ae115bc7Smrj 		info.iagp_apersize = agp_target_get_apsize(st);
701ae115bc7Smrj 
702ae115bc7Smrj 		if (ddi_copyout(&info, (void *)data,
703ae115bc7Smrj 		    sizeof (i_agp_info_t), mode)) {
704ae115bc7Smrj 			mutex_exit(&st->tsoft_lock);
705ae115bc7Smrj 			return (EFAULT);
706ae115bc7Smrj 		}
707ae115bc7Smrj 		break;
708ae115bc7Smrj 
709ae115bc7Smrj 	}
710ae115bc7Smrj 	/*
711ae115bc7Smrj 	 * This ioctl is only for Intel AGP chipsets.
712ae115bc7Smrj 	 * It is not necessary for the AMD8151 AGP bridge, because
713ae115bc7Smrj 	 * this register in the AMD8151 does not control any hardware.
714ae115bc7Smrj 	 * It is only provided for compatibility with an Intel AGP bridge.
715ae115bc7Smrj 	 * Please refer to the <<AMD8151 data sheet>> page 24,
716ae115bc7Smrj 	 * AGP device GART pointer.
717ae115bc7Smrj 	 */
718ae115bc7Smrj 	case AGP_TARGET_SET_GATTADDR:
719ae115bc7Smrj 	{
720ae115bc7Smrj 		uint32_t gartaddr;
721ae115bc7Smrj 
722ae115bc7Smrj 		if (ddi_copyin((void *)data, &gartaddr,
723ae115bc7Smrj 		    sizeof (uint32_t), mode)) {
724ae115bc7Smrj 			mutex_exit(&st->tsoft_lock);
725ae115bc7Smrj 			return (EFAULT);
726ae115bc7Smrj 		}
727ae115bc7Smrj 
728ae115bc7Smrj 		agp_target_set_gartaddr(st, gartaddr);
729ae115bc7Smrj 		break;
730ae115bc7Smrj 	}
731ae115bc7Smrj 	case AGP_TARGET_SETCMD:
732ae115bc7Smrj 	{
733ae115bc7Smrj 		uint32_t command;
734ae115bc7Smrj 
735ae115bc7Smrj 		if (ddi_copyin((void *)data, &command,
736ae115bc7Smrj 		    sizeof (uint32_t), mode)) {
737ae115bc7Smrj 			mutex_exit(&st->tsoft_lock);
738ae115bc7Smrj 			return (EFAULT);
739ae115bc7Smrj 		}
740ae115bc7Smrj 
741ae115bc7Smrj 		ASSERT(st->tsoft_acaptr);
742ae115bc7Smrj 
743ae115bc7Smrj 		pci_config_put32(st->tsoft_pcihdl,
744ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
745ae115bc7Smrj 		    command);
746ae115bc7Smrj 		break;
747ae115bc7Smrj 
748ae115bc7Smrj 	}
749ae115bc7Smrj 	case AGP_TARGET_FLUSH_GTLB:
750ae115bc7Smrj 	{
751ae115bc7Smrj 		uint16_t value;
752ae115bc7Smrj 
753ae115bc7Smrj 		ASSERT(st->tsoft_acaptr);
754ae115bc7Smrj 
755ae115bc7Smrj 		value = pci_config_get16(st->tsoft_pcihdl,
756ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL);
757ae115bc7Smrj 		value &= ~AGPCTRL_GTLBEN;
758ae115bc7Smrj 		pci_config_put16(st->tsoft_pcihdl,
759ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
760ae115bc7Smrj 		value |= AGPCTRL_GTLBEN;
761ae115bc7Smrj 		pci_config_put16(st->tsoft_pcihdl,
762ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
763ae115bc7Smrj 
764ae115bc7Smrj 		break;
765ae115bc7Smrj 	}
766ae115bc7Smrj 	case AGP_TARGET_CONFIGURE:
767ae115bc7Smrj 	{
768ae115bc7Smrj 		uint8_t value;
769ae115bc7Smrj 
770ae115bc7Smrj 		ASSERT(st->tsoft_acaptr);
771ae115bc7Smrj 
7723deb7cedSms148562 		/*
7733deb7cedSms148562 		 * In Intel agp bridges, agp misc register offset
7743deb7cedSms148562 		 * is indexed from 0 instead of capability register.
7753deb7cedSms148562 		 * AMD agp bridges have no such misc register
7763deb7cedSms148562 		 * to control the aperture access, and they have
7773deb7cedSms148562 		 * similar regsiters in CPU gart devices instead.
7783deb7cedSms148562 		 */
7793deb7cedSms148562 
7803deb7cedSms148562 		if (is_intel_br(st)) {
781ae115bc7Smrj 			value = pci_config_get8(st->tsoft_pcihdl,
782ae115bc7Smrj 			    st->tsoft_acaptr + AGP_CONF_MISC);
783ae115bc7Smrj 			value |= AGP_MISC_APEN;
784ae115bc7Smrj 			pci_config_put8(st->tsoft_pcihdl,
785ae115bc7Smrj 			    st->tsoft_acaptr + AGP_CONF_MISC, value);
7863deb7cedSms148562 		}
787ae115bc7Smrj 		break;
788ae115bc7Smrj 
789ae115bc7Smrj 	}
790ae115bc7Smrj 	case AGP_TARGET_UNCONFIG:
791ae115bc7Smrj 	{
792ae115bc7Smrj 		uint32_t value1;
793ae115bc7Smrj 		uint8_t value2;
794ae115bc7Smrj 
795ae115bc7Smrj 		ASSERT(st->tsoft_acaptr);
796ae115bc7Smrj 
797ae115bc7Smrj 		pci_config_put16(st->tsoft_pcihdl,
798ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0);
799ae115bc7Smrj 
8003deb7cedSms148562 		if (is_intel_br(st)) {
801ae115bc7Smrj 			value2 = pci_config_get8(st->tsoft_pcihdl,
802ae115bc7Smrj 			    st->tsoft_acaptr + AGP_CONF_MISC);
803ae115bc7Smrj 			value2 &= ~AGP_MISC_APEN;
804ae115bc7Smrj 			pci_config_put8(st->tsoft_pcihdl,
805ae115bc7Smrj 			    st->tsoft_acaptr + AGP_CONF_MISC, value2);
8063deb7cedSms148562 		}
807ae115bc7Smrj 
808ae115bc7Smrj 		value1 = pci_config_get32(st->tsoft_pcihdl,
809ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND);
810ae115bc7Smrj 		value1 &= ~AGPCMD_AGPEN;
811ae115bc7Smrj 		pci_config_put32(st->tsoft_pcihdl,
812ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
813ae115bc7Smrj 		    value1);
814ae115bc7Smrj 
815ae115bc7Smrj 		pci_config_put32(st->tsoft_pcihdl,
816ae115bc7Smrj 		    st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0);
817ae115bc7Smrj 
818ae115bc7Smrj 		break;
819ae115bc7Smrj 	}
820ae115bc7Smrj 
8210035d21cSmiao chen - Sun Microsystems - Beijing China 	case INTEL_CHIPSET_FLUSH_SETUP:
8220035d21cSmiao chen - Sun Microsystems - Beijing China 	case INTEL_CHIPSET_FLUSH:
8230035d21cSmiao chen - Sun Microsystems - Beijing China 	case INTEL_CHIPSET_FLUSH_FREE:
8240035d21cSmiao chen - Sun Microsystems - Beijing China 		break;
825ae115bc7Smrj 	default:
826ae115bc7Smrj 		mutex_exit(&st->tsoft_lock);
827ae115bc7Smrj 		return (ENXIO);
828ae115bc7Smrj 	} /* end switch */
829ae115bc7Smrj 
830ae115bc7Smrj 	mutex_exit(&st->tsoft_lock);
831ae115bc7Smrj 
832ae115bc7Smrj 	return (0);
833ae115bc7Smrj }
834ae115bc7Smrj 
835ae115bc7Smrj /*ARGSUSED*/
836ae115bc7Smrj static int
agp_target_open(dev_t * devp,int flag,int otyp,cred_t * cred)837ae115bc7Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred)
838ae115bc7Smrj {
839ae115bc7Smrj 	int instance = DEV2INST(*devp);
840ae115bc7Smrj 	agp_target_softstate_t *st;
841ae115bc7Smrj 
842ae115bc7Smrj 	if (!(flag & FKLYR))
843ae115bc7Smrj 		return (ENXIO);
844ae115bc7Smrj 
845ae115bc7Smrj 	st = GETSOFTC(instance);
846ae115bc7Smrj 
847ae115bc7Smrj 	if (st == NULL)
848ae115bc7Smrj 		return (ENXIO);
849ae115bc7Smrj 
850ae115bc7Smrj 	return (0);
851ae115bc7Smrj }
852ae115bc7Smrj 
853ae115bc7Smrj /*ARGSUSED*/
854ae115bc7Smrj static int
agp_target_close(dev_t dev,int flag,int otyp,cred_t * cred)855ae115bc7Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred)
856ae115bc7Smrj {
857ae115bc7Smrj 	int instance = DEV2INST(dev);
858ae115bc7Smrj 	agp_target_softstate_t *st;
859ae115bc7Smrj 
860ae115bc7Smrj 	st = GETSOFTC(instance);
861ae115bc7Smrj 
862ae115bc7Smrj 	if (st == NULL)
863ae115bc7Smrj 		return (ENXIO);
864ae115bc7Smrj 
865ae115bc7Smrj 	return (0);
866ae115bc7Smrj }
867ae115bc7Smrj 
868ae115bc7Smrj static  struct  cb_ops  agp_target_cb_ops = {
869ae115bc7Smrj 	agp_target_open,		/* cb_open */
870ae115bc7Smrj 	agp_target_close,		/* cb_close */
871ae115bc7Smrj 	nodev,				/* cb_strategy */
872ae115bc7Smrj 	nodev,				/* cb_print */
873ae115bc7Smrj 	nodev,				/* cb_dump */
874ae115bc7Smrj 	nodev,				/* cb_read() */
875ae115bc7Smrj 	nodev,				/* cb_write() */
876ae115bc7Smrj 	agp_target_ioctl,		/* cb_ioctl */
877ae115bc7Smrj 	nodev,				/* cb_devmap */
878ae115bc7Smrj 	nodev,				/* cb_mmap */
879ae115bc7Smrj 	nodev,				/* cb_segmap */
880ae115bc7Smrj 	nochpoll,			/* cb_chpoll */
881ae115bc7Smrj 	ddi_prop_op,			/* cb_prop_op */
882ae115bc7Smrj 	0,				/* cb_stream */
883ae115bc7Smrj 	D_NEW | D_MP, 			/* cb_flag */
884ae115bc7Smrj 	CB_REV,				/* cb_ops version? */
885ae115bc7Smrj 	nodev,				/* cb_aread() */
886ae115bc7Smrj 	nodev,				/* cb_awrite() */
887ae115bc7Smrj };
888ae115bc7Smrj 
889ae115bc7Smrj /* device operations */
890ae115bc7Smrj static struct dev_ops agp_target_ops = {
891ae115bc7Smrj 	DEVO_REV,		/* devo_rev */
892ae115bc7Smrj 	0,			/* devo_refcnt */
893ae115bc7Smrj 	agptarget_getinfo, 	/* devo_getinfo */
894ae115bc7Smrj 	nulldev,		/* devo_identify */
895ae115bc7Smrj 	nulldev,		/* devo_probe */
896ae115bc7Smrj 	agp_target_attach,	/* devo_attach */
897ae115bc7Smrj 	agp_target_detach,	/* devo_detach */
898ae115bc7Smrj 	nodev,			/* devo_reset */
899ae115bc7Smrj 	&agp_target_cb_ops,	/* devo_cb_ops */
900ae115bc7Smrj 	0,			/* devo_bus_ops */
901ae115bc7Smrj 	0,			/* devo_power */
902dc5ffc8eSmiao chen - Sun Microsystems - Beijing China 	ddi_quiesce_not_needed,	/* devo_quiesce */
903ae115bc7Smrj };
904ae115bc7Smrj 
905ae115bc7Smrj static  struct modldrv modldrv = {
906ae115bc7Smrj 	&mod_driverops,
90731c83a1bSms148562 	"AGP target driver",
908ae115bc7Smrj 	&agp_target_ops,
909ae115bc7Smrj };
910ae115bc7Smrj 
911ae115bc7Smrj static  struct modlinkage modlinkage = {
912ae115bc7Smrj 	MODREV_1,		/* MODREV_1 is indicated by manual */
913ae115bc7Smrj 	{&modldrv, NULL, NULL, NULL}
914ae115bc7Smrj };
915ae115bc7Smrj 
916ae115bc7Smrj int
_init(void)917ae115bc7Smrj _init(void)
918ae115bc7Smrj {
919ae115bc7Smrj 	int ret;
920ae115bc7Smrj 
921ae115bc7Smrj 	ret = ddi_soft_state_init(&agptarget_glob_soft_handle,
922ae115bc7Smrj 	    sizeof (agp_target_softstate_t), 1);
923ae115bc7Smrj 
924ae115bc7Smrj 	if (ret)
925ae115bc7Smrj 		goto err1;
926ae115bc7Smrj 
927ae115bc7Smrj 	if ((ret = mod_install(&modlinkage)) != 0) {
928ae115bc7Smrj 		goto err2;
929ae115bc7Smrj 	}
930ae115bc7Smrj 
931ae115bc7Smrj 	return (DDI_SUCCESS);
932ae115bc7Smrj err2:
933ae115bc7Smrj 	ddi_soft_state_fini(&agptarget_glob_soft_handle);
934ae115bc7Smrj err1:
935ae115bc7Smrj 	return (ret);
936ae115bc7Smrj }
937ae115bc7Smrj 
938ae115bc7Smrj int
_info(struct modinfo * modinfop)939ae115bc7Smrj _info(struct  modinfo *modinfop)
940ae115bc7Smrj {
941ae115bc7Smrj 	return (mod_info(&modlinkage, modinfop));
942ae115bc7Smrj }
943ae115bc7Smrj 
944ae115bc7Smrj int
_fini(void)945ae115bc7Smrj _fini(void)
946ae115bc7Smrj {
947ae115bc7Smrj 	int	ret;
948ae115bc7Smrj 
949ae115bc7Smrj 	if ((ret = mod_remove(&modlinkage)) == 0) {
950ae115bc7Smrj 		ddi_soft_state_fini(&agptarget_glob_soft_handle);
951ae115bc7Smrj 	}
952ae115bc7Smrj 	return (ret);
953ae115bc7Smrj }
954