xref: /titanic_44/usr/src/uts/intel/io/agpgart/agptarget.c (revision 63ea9ad24896f2939472f8f96f568086d190eb33)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <sys/systm.h>
29 #include <sys/conf.h>
30 #include <sys/modctl.h>
31 #include <sys/file.h>
32 #include <sys/stat.h>
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/modctl.h>
36 #include <sys/sunldi.h>
37 #include <sys/pci.h>
38 #include <sys/agpgart.h>
39 #include <sys/agp/agpdefs.h>
40 #include <sys/agp/agptarget_io.h>
41 
42 int agptarget_debug_var = 0;
43 #define	TARGETDB_PRINT2(fmt)	if (agptarget_debug_var >= 1) cmn_err fmt
44 #define	INST2NODENUM(inst)	(inst)
45 #define	DEV2INST(dev)		(getminor(dev))
46 
47 typedef struct agp_target_softstate {
48 	dev_info_t		*tsoft_dip;
49 	ddi_acc_handle_t	tsoft_pcihdl;
50 	uint32_t		tsoft_devid;
51 	/* The offset of the ACAPID register */
52 	off_t			tsoft_acaptr;
53 	kmutex_t		tsoft_lock;
54 	int			tsoft_gms_off; /* GMS offset in config */
55 	uint32_t		tsoft_gms;
56 }agp_target_softstate_t;
57 
58 /*
59  * To get the pre-allocated graphics mem size using Graphics Mode Select
60  * (GMS) value.
61  */
62 typedef struct gms_mode {
63 	uint32_t	gm_devid;	/* bridge vendor + device id */
64 	off_t		gm_regoff;	/* mode selection register offset */
65 	uint32_t	gm_mask;	/* GMS mask */
66 	uint32_t	gm_num;		/* number of modes in gm_vec */
67 	int 		*gm_vec;	/* modes array */
68 } gms_mode_t;
69 
70 static void *agptarget_glob_soft_handle;
71 
72 #define	GETSOFTC(instance)	((agp_target_softstate_t *)	\
73     ddi_get_soft_state(agptarget_glob_soft_handle, instance));
74 
75 /*
76  * The AMD8151 bridge is the only supported 64 bit hardware
77  */
78 static int
79 is_64bit_aper(agp_target_softstate_t *softstate)
80 {
81 	return (softstate->tsoft_devid == AMD_BR_8151);
82 }
83 
84 /*
85  * Check if it is an intel bridge
86  */
87 static int
88 is_intel_br(agp_target_softstate_t *softstate)
89 {
90 	return ((softstate->tsoft_devid & VENDOR_ID_MASK) ==
91 	    INTEL_VENDOR_ID);
92 }
93 
94 /*
95  * agp_target_cap_find()
96  *
97  * Description:
98  * 	This function searches the linked capability list to find the offset
99  * 	of the AGP capability register. When it was not found, return 0.
100  * 	This works for standard AGP chipsets, but not for some Intel chipsets,
101  * 	like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for
102  * 	these chipsets even if AGP is supported. So the offset of acapid
103  * 	should be set manually in thoses cases.
104  *
105  * Arguments:
106  * 	pci_handle		ddi acc handle of pci config
107  *
108  * Returns:
109  * 	0			No capability pointer register found
110  * 	nexcap			The AGP capability pointer register offset
111  */
112 static off_t
113 agp_target_cap_find(ddi_acc_handle_t pci_handle)
114 {
115 	off_t		nextcap = 0;
116 	uint32_t	ncapid = 0;
117 	uint8_t		value = 0;
118 
119 	/* Check if this device supports the capability pointer */
120 	value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT)
121 	    & PCI_CONF_CAP_MASK);
122 
123 	if (!value)
124 		return (0);
125 	/* Get the offset of the first capability pointer from CAPPTR */
126 	nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR));
127 
128 	/* Check the AGP capability from the first capability pointer */
129 	while (nextcap) {
130 		ncapid = pci_config_get32(pci_handle, nextcap);
131 		/*
132 		 * AGP3.0 rev1.0 127  the capid was assigned by the PCI SIG,
133 		 * 845 data sheet page 69
134 		 */
135 		if ((ncapid & PCI_CONF_CAPID_MASK) ==
136 		    AGP_CAP_ID) /* The AGP cap was found */
137 			break;
138 
139 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
140 	}
141 
142 	return (nextcap);
143 
144 }
145 
146 /*
147  * agp_target_get_aperbase()
148  *
149  * Description:
150  * 	This function gets the AGP aperture base address from the AGP target
151  *	register, the AGP aperture base register was programmed by the BIOS.
152  *
153  * Arguments:
154  * 	softstate		driver soft state pointer
155  *
156  * Returns:
157  * 	aper_base 		AGP aperture base address
158  *
159  * Notes:
160  * 	If a 64bit bridge device is available, the AGP aperture base address
161  * 	can be 64 bit.
162  */
163 static uint64_t
164 agp_target_get_apbase(agp_target_softstate_t *softstate)
165 {
166 	uint64_t aper_base;
167 
168 	if (is_intel_br(softstate)) {
169 		aper_base = pci_config_get32(softstate->tsoft_pcihdl,
170 		    AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK;
171 	} else if (is_64bit_aper(softstate)) {
172 		aper_base = pci_config_get64(softstate->tsoft_pcihdl,
173 		    AGP_CONF_APERBASE);
174 		/* 32-bit or 64-bit aperbase base pointer */
175 		if ((aper_base & AGP_APER_TYPE_MASK) == 0)
176 			aper_base &= AGP_32_APERBASE_MASK;
177 		else
178 			aper_base &= AGP_64_APERBASE_MASK;
179 	}
180 
181 	return (aper_base);
182 }
183 
184 /*
185  * agp_target_get_apsize()
186  *
187  * Description:
188  * 	This function gets the AGP aperture size by reading the AGP aperture
189  * 	size register.
190  * Arguments:
191  * 	softstate		driver soft state pointer
192  *
193  * Return:
194  * 	size		The AGP aperture size in megabytes
195  * 	0		an unexpected error
196  */
197 static size_t
198 agp_target_get_apsize(agp_target_softstate_t *softstate)
199 {
200 	off_t cap;
201 	uint16_t value;
202 	size_t size, regsize;
203 
204 	ASSERT(softstate->tsoft_acaptr);
205 	cap = softstate->tsoft_acaptr;
206 
207 	if (is_intel_br(softstate)) {
208 		/* extend this value to 16 bit for later tests */
209 		value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl,
210 		    cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK;
211 	} else if (is_64bit_aper(softstate)) {
212 		value = pci_config_get16(softstate->tsoft_pcihdl,
213 		    cap + AGP_CONF_APERSIZE);
214 	}
215 
216 	if (value & AGP_APER_128M_MASK) {
217 		switch (value & AGP_APER_128M_MASK) {
218 			case AGP_APER_4M:
219 				size = 4; /* 4M */
220 				break;
221 			case AGP_APER_8M:
222 				size = 8; /* 8M */
223 				break;
224 			case AGP_APER_16M:
225 				size = 16; /* 16M */
226 				break;
227 			case AGP_APER_32M:
228 				size = 32; /* 32M */
229 				break;
230 			case AGP_APER_64M:
231 				size = 64; /* 64M */
232 				break;
233 			case AGP_APER_128M:
234 				size = 128; /* 128M */
235 				break;
236 			default:
237 				size = 0; /* not true */
238 		}
239 	} else {
240 		switch (value & AGP_APER_4G_MASK) {
241 			case AGP_APER_256M:
242 				size = 256; /* 256 M */
243 				break;
244 			case AGP_APER_512M:
245 				size = 512; /* 512 M */
246 				break;
247 			case AGP_APER_1024M:
248 				size = 1024; /* 1024 M */
249 				break;
250 			case AGP_APER_2048M:
251 				size = 2048; /* 2048 M */
252 				break;
253 			case AGP_APER_4G:
254 				size = 4096; /* 4096 M */
255 				break;
256 			default:
257 				size = 0; /* not true */
258 		}
259 	}
260 	/*
261 	 * In some cases, there is no APSIZE register, so the size value
262 	 * of 256M could be wrong. Check the value by reading the size of
263 	 * the first register which was set in the PCI configuration space.
264 	 */
265 	if (size == 256) {
266 		if (ddi_dev_regsize(softstate->tsoft_dip,
267 		    AGP_TARGET_BAR1, (off_t *)&regsize) == DDI_FAILURE)
268 			return (0);
269 
270 		if (MB2BYTES(size) != regsize) {
271 			TARGETDB_PRINT2((CE_WARN,
272 			    "APSIZE 256M doesn't match regsize %lx",
273 			    regsize));
274 			TARGETDB_PRINT2((CE_WARN, "Use regsize instead"));
275 			size = BYTES2MB(regsize);
276 		}
277 	}
278 
279 	return (size);
280 }
281 
282 static void
283 agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr)
284 {
285 	ASSERT(softstate->tsoft_acaptr);
286 
287 	/* Disable the GTLB for Intel chipsets */
288 	pci_config_put16(softstate->tsoft_pcihdl,
289 	    softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000);
290 
291 	pci_config_put32(softstate->tsoft_pcihdl,
292 	    softstate->tsoft_acaptr + AGP_CONF_ATTBASE,
293 	    gartaddr & AGP_ATTBASE_MASK);
294 }
295 
296 /*
297  * Pre-allocated graphics memory for every type of Intel north bridge, mem size
298  * are specified in kbytes.
299  */
300 #define	GMS_MB(n) 	((n) * 1024)
301 #define	GMS_SHIFT 	4
302 #define	GMS_SIZE(a)	(sizeof (a) / sizeof (int))
303 
304 /*
305  * Since value zero always means "No memory pre-allocated", value of (GMS - 1)
306  * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb)
307  * that GMS value 0x1 corresponding to.
308  *
309  * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics
310  * memory, unless some special BIOS settings exist.
311  */
312 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)};
313 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)};
314 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
315 	GMS_MB(32)};
316 /* There is no modes for 16M in datasheet, but some BIOS add it. */
317 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)};
318 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)};
319 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
320 	GMS_MB(32), GMS_MB(48), GMS_MB(64)};
321 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
322 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)};
323 static int gms_G4X[13] = {0, 0, 0, 0,
324 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256),
325 	GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)};
326 
327 static gms_mode_t gms_modes[] = {
328 	{INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK,
329 		GMS_SIZE(gms_810), gms_810},
330 	{INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK,
331 		GMS_SIZE(gms_810), gms_810},
332 	{INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK,
333 		GMS_SIZE(gms_810), gms_810},
334 	{INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
335 		GMS_SIZE(gms_830_845), gms_830_845},
336 	{INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
337 		GMS_SIZE(gms_830_845), gms_830_845},
338 	{INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
339 		GMS_SIZE(gms_855GM), gms_855GM},
340 	{INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
341 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
342 	{INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
343 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
344 	{INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
345 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
346 	{INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
347 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
348 	{INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
349 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
350 	{INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
351 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
352 	{INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
353 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
354 	{INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
355 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
356 	{INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
357 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
358 	{INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
359 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
360 	{INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
361 		GMS_SIZE(gms_965GM), gms_965GM},
362 	{INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
363 		GMS_SIZE(gms_965GM), gms_965GM},
364 	{INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK,
365 		GMS_SIZE(gms_X33), gms_X33},
366 	{INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
367 		GMS_SIZE(gms_X33), gms_X33},
368 	{INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
369 		GMS_SIZE(gms_X33), gms_X33},
370 	{INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
371 		GMS_SIZE(gms_965GM), gms_965GM},
372 	{INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
373 		GMS_SIZE(gms_G4X), gms_G4X},
374 	{INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
375 		GMS_SIZE(gms_G4X), gms_G4X},
376 	{INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
377 		GMS_SIZE(gms_G4X), gms_G4X},
378 	{INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
379 		GMS_SIZE(gms_G4X), gms_G4X}
380 };
381 static int
382 get_chip_gms(uint32_t devid)
383 {
384 	int num_modes;
385 	int i;
386 
387 	num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t));
388 
389 	for (i = 0; i < num_modes; i++) {
390 		if (gms_modes[i].gm_devid == devid)
391 			break;
392 	}
393 
394 	return ((i == num_modes) ? -1 : i);
395 }
396 
397 /* Returns the size (kbytes) of pre-allocated graphics memory */
398 static size_t
399 i8xx_biosmem_detect(agp_target_softstate_t *softstate)
400 {
401 	uint8_t memval;
402 	size_t kbytes;
403 	int	gms_off;
404 
405 	kbytes = 0;
406 	gms_off = softstate->tsoft_gms_off;
407 
408 	/* fetch the GMS value from DRAM controller */
409 	memval = pci_config_get8(softstate->tsoft_pcihdl,
410 	    gms_modes[gms_off].gm_regoff);
411 	TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval));
412 	memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT;
413 	/* assuming zero byte for 0 or "reserved" GMS values */
414 	if (memval == 0 || memval > gms_modes[gms_off].gm_num) {
415 		TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: "
416 		    "devid = %x, GMS = %x. assuming zero byte of "
417 		    "pre-allocated memory",
418 		    gms_modes[gms_off].gm_devid, memval));
419 		goto done;
420 	}
421 	memval--;	/* use (GMS_value - 1) as index */
422 	kbytes = (gms_modes[gms_off].gm_vec)[memval];
423 
424 done:
425 	TARGETDB_PRINT2((CE_NOTE,
426 	    "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected",
427 	    kbytes));
428 	return (kbytes);
429 }
430 
431 /*ARGSUSED*/
432 static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
433     void *arg, void **resultp)
434 {
435 	agp_target_softstate_t *st;
436 	int instance, rval = DDI_FAILURE;
437 	dev_t dev;
438 
439 	switch (cmd) {
440 	case DDI_INFO_DEVT2DEVINFO:
441 		dev = (dev_t)arg;
442 		instance = DEV2INST(dev);
443 		st = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
444 		if (st != NULL) {
445 			mutex_enter(&st->tsoft_lock);
446 			*resultp = st->tsoft_dip;
447 			mutex_exit(&st->tsoft_lock);
448 			rval = DDI_SUCCESS;
449 		} else
450 			*resultp = NULL;
451 
452 		break;
453 	case DDI_INFO_DEVT2INSTANCE:
454 		dev = (dev_t)arg;
455 		instance = DEV2INST(dev);
456 		*resultp = (void *)(uintptr_t)instance;
457 		rval = DDI_SUCCESS;
458 	default:
459 		break;
460 	}
461 
462 	return (rval);
463 }
464 
465 static int
466 intel_br_resume(agp_target_softstate_t *softstate)
467 {
468 	int gms_off;
469 
470 	gms_off = softstate->tsoft_gms_off;
471 
472 	/*
473 	 * We recover the gmch graphics control register here
474 	 */
475 	pci_config_put16(softstate->tsoft_pcihdl,
476 	    gms_modes[gms_off].gm_regoff, softstate->tsoft_gms);
477 
478 	return (DDI_SUCCESS);
479 }
480 static int
481 intel_br_suspend(agp_target_softstate_t *softstate)
482 {
483 	int gms_off;
484 
485 	gms_off = softstate->tsoft_gms_off;
486 	softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl,
487 	    gms_modes[gms_off].gm_regoff);
488 
489 	return (DDI_SUCCESS);
490 }
491 
492 static int
493 agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
494 {
495 	agp_target_softstate_t *softstate;
496 	int instance;
497 	int status;
498 
499 	instance = ddi_get_instance(dip);
500 
501 	switch (cmd) {
502 	case DDI_ATTACH:
503 		break;
504 	case DDI_RESUME:
505 		softstate =
506 		    ddi_get_soft_state(agptarget_glob_soft_handle, instance);
507 		return (intel_br_resume(softstate));
508 	default:
509 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
510 		    "only attach and resume ops are supported"));
511 		return (DDI_FAILURE);
512 	}
513 
514 	if (ddi_soft_state_zalloc(agptarget_glob_soft_handle,
515 	    instance) != DDI_SUCCESS) {
516 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
517 		    "soft state zalloc failed"));
518 		return (DDI_FAILURE);
519 	}
520 
521 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
522 	mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL);
523 	softstate->tsoft_dip = dip;
524 	status = pci_config_setup(dip, &softstate->tsoft_pcihdl);
525 	if (status != DDI_SUCCESS) {
526 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
527 		    "pci config setup failed"));
528 		ddi_soft_state_free(agptarget_glob_soft_handle,
529 		    instance);
530 		return (DDI_FAILURE);
531 	}
532 
533 	softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl,
534 	    PCI_CONF_VENID);
535 	softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid);
536 	if (softstate->tsoft_gms_off < 0) {
537 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
538 		    "read gms offset failed"));
539 		pci_config_teardown(&softstate->tsoft_pcihdl);
540 		ddi_soft_state_free(agptarget_glob_soft_handle,
541 		    instance);
542 		return (DDI_FAILURE);
543 	}
544 	softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl);
545 	if (softstate->tsoft_acaptr == 0) {
546 		/* Make a correction for some Intel chipsets */
547 		if (is_intel_br(softstate))
548 			softstate->tsoft_acaptr = AGP_CAP_OFF_DEF;
549 		else {
550 			TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
551 			    "Not a supposed corretion"));
552 			pci_config_teardown(&softstate->tsoft_pcihdl);
553 			ddi_soft_state_free(agptarget_glob_soft_handle,
554 			    instance);
555 			return (DDI_FAILURE);
556 		}
557 	}
558 
559 	status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR,
560 	    INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0);
561 
562 	if (status != DDI_SUCCESS) {
563 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
564 		    "Create minor node failed"));
565 		pci_config_teardown(&softstate->tsoft_pcihdl);
566 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
567 		return (DDI_FAILURE);
568 	}
569 
570 	return (DDI_SUCCESS);
571 }
572 
573 /*ARGSUSED*/
574 static int
575 agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
576 {
577 	int instance;
578 	agp_target_softstate_t *softstate;
579 
580 	instance = ddi_get_instance(dip);
581 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
582 
583 	if (cmd == DDI_SUSPEND) {
584 		/* get GMS modes list entry */
585 		return (intel_br_suspend(softstate));
586 	}
587 
588 	if (cmd != DDI_DETACH) {
589 		TARGETDB_PRINT2((CE_WARN, "agp_target_detach:"
590 		    "only detach and suspend ops are supported"));
591 		return (DDI_FAILURE);
592 	}
593 
594 	ddi_remove_minor_node(dip, AGPTARGET_NAME);
595 	pci_config_teardown(&softstate->tsoft_pcihdl);
596 	mutex_destroy(&softstate->tsoft_lock);
597 	ddi_soft_state_free(agptarget_glob_soft_handle, instance);
598 	return (DDI_SUCCESS);
599 }
600 
601 /*ARGSUSED*/
602 static int
603 agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
604     cred_t *cred, int *rval)
605 {
606 	int instance = DEV2INST(dev);
607 	agp_target_softstate_t *st;
608 	static char kernel_only[] =
609 	    "amd64_gart_ioctl: is a kernel only ioctl";
610 
611 	if (!(mode & FKIOCTL)) {
612 		TARGETDB_PRINT2((CE_CONT, kernel_only));
613 		return (ENXIO);
614 	}
615 	st = GETSOFTC(instance);
616 
617 	if (st == NULL)
618 		return (ENXIO);
619 
620 	mutex_enter(&st->tsoft_lock);
621 
622 	switch (cmd) {
623 	case CHIP_DETECT:
624 	{
625 		int type = 0;
626 
627 		if (is_intel_br(st))
628 			type = CHIP_IS_INTEL;
629 		else if (is_64bit_aper(st))
630 			type = CHIP_IS_AMD;
631 		else {
632 			type = 0;
633 			TARGETDB_PRINT2((CE_WARN, "Unknown bridge!"));
634 		}
635 
636 		if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) {
637 			mutex_exit(&st->tsoft_lock);
638 			return (EFAULT);
639 		}
640 
641 		break;
642 	}
643 	case I8XX_GET_PREALLOC_SIZE:
644 	{
645 		size_t prealloc_size;
646 
647 		if (!is_intel_br(st)) {
648 			mutex_exit(&st->tsoft_lock);
649 			return (EINVAL);
650 		}
651 
652 		prealloc_size = i8xx_biosmem_detect(st);
653 		if (ddi_copyout(&prealloc_size, (void *)data,
654 		    sizeof (size_t), mode)) {
655 			mutex_exit(&st->tsoft_lock);
656 			return (EFAULT);
657 		}
658 
659 		break;
660 	}
661 	case AGP_TARGET_GETINFO:
662 	{
663 		i_agp_info_t info;
664 		uint32_t value;
665 		off_t cap;
666 
667 		ASSERT(st->tsoft_acaptr);
668 
669 		cap = st->tsoft_acaptr;
670 		value = pci_config_get32(st->tsoft_pcihdl, cap);
671 		info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf);
672 		info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf);
673 		info.iagp_devid = st->tsoft_devid;
674 		info.iagp_mode = pci_config_get32(st->tsoft_pcihdl,
675 		    cap + AGP_CONF_STATUS);
676 		info.iagp_aperbase = agp_target_get_apbase(st);
677 		info.iagp_apersize = agp_target_get_apsize(st);
678 
679 		if (ddi_copyout(&info, (void *)data,
680 		    sizeof (i_agp_info_t), mode)) {
681 			mutex_exit(&st->tsoft_lock);
682 			return (EFAULT);
683 		}
684 		break;
685 
686 	}
687 	/*
688 	 * This ioctl is only for Intel AGP chipsets.
689 	 * It is not necessary for the AMD8151 AGP bridge, because
690 	 * this register in the AMD8151 does not control any hardware.
691 	 * It is only provided for compatibility with an Intel AGP bridge.
692 	 * Please refer to the <<AMD8151 data sheet>> page 24,
693 	 * AGP device GART pointer.
694 	 */
695 	case AGP_TARGET_SET_GATTADDR:
696 	{
697 		uint32_t gartaddr;
698 
699 		if (ddi_copyin((void *)data, &gartaddr,
700 		    sizeof (uint32_t), mode)) {
701 			mutex_exit(&st->tsoft_lock);
702 			return (EFAULT);
703 		}
704 
705 		agp_target_set_gartaddr(st, gartaddr);
706 		break;
707 	}
708 	case AGP_TARGET_SETCMD:
709 	{
710 		uint32_t command;
711 
712 		if (ddi_copyin((void *)data, &command,
713 		    sizeof (uint32_t), mode)) {
714 			mutex_exit(&st->tsoft_lock);
715 			return (EFAULT);
716 		}
717 
718 		ASSERT(st->tsoft_acaptr);
719 
720 		pci_config_put32(st->tsoft_pcihdl,
721 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
722 		    command);
723 		break;
724 
725 	}
726 	case AGP_TARGET_FLUSH_GTLB:
727 	{
728 		uint16_t value;
729 
730 		ASSERT(st->tsoft_acaptr);
731 
732 		value = pci_config_get16(st->tsoft_pcihdl,
733 		    st->tsoft_acaptr + AGP_CONF_CONTROL);
734 		value &= ~AGPCTRL_GTLBEN;
735 		pci_config_put16(st->tsoft_pcihdl,
736 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
737 		value |= AGPCTRL_GTLBEN;
738 		pci_config_put16(st->tsoft_pcihdl,
739 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
740 
741 		break;
742 	}
743 	case AGP_TARGET_CONFIGURE:
744 	{
745 		uint8_t value;
746 
747 		ASSERT(st->tsoft_acaptr);
748 
749 		/*
750 		 * In Intel agp bridges, agp misc register offset
751 		 * is indexed from 0 instead of capability register.
752 		 * AMD agp bridges have no such misc register
753 		 * to control the aperture access, and they have
754 		 * similar regsiters in CPU gart devices instead.
755 		 */
756 
757 		if (is_intel_br(st)) {
758 			value = pci_config_get8(st->tsoft_pcihdl,
759 			    st->tsoft_acaptr + AGP_CONF_MISC);
760 			value |= AGP_MISC_APEN;
761 			pci_config_put8(st->tsoft_pcihdl,
762 			    st->tsoft_acaptr + AGP_CONF_MISC, value);
763 		}
764 		break;
765 
766 	}
767 	case AGP_TARGET_UNCONFIG:
768 	{
769 		uint32_t value1;
770 		uint8_t value2;
771 
772 		ASSERT(st->tsoft_acaptr);
773 
774 		pci_config_put16(st->tsoft_pcihdl,
775 		    st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0);
776 
777 		if (is_intel_br(st)) {
778 			value2 = pci_config_get8(st->tsoft_pcihdl,
779 			    st->tsoft_acaptr + AGP_CONF_MISC);
780 			value2 &= ~AGP_MISC_APEN;
781 			pci_config_put8(st->tsoft_pcihdl,
782 			    st->tsoft_acaptr + AGP_CONF_MISC, value2);
783 		}
784 
785 		value1 = pci_config_get32(st->tsoft_pcihdl,
786 		    st->tsoft_acaptr + AGP_CONF_COMMAND);
787 		value1 &= ~AGPCMD_AGPEN;
788 		pci_config_put32(st->tsoft_pcihdl,
789 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
790 		    value1);
791 
792 		pci_config_put32(st->tsoft_pcihdl,
793 		    st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0);
794 
795 		break;
796 	}
797 
798 	default:
799 		mutex_exit(&st->tsoft_lock);
800 		return (ENXIO);
801 	} /* end switch */
802 
803 	mutex_exit(&st->tsoft_lock);
804 
805 	return (0);
806 }
807 
808 /*ARGSUSED*/
809 static int
810 agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred)
811 {
812 	int instance = DEV2INST(*devp);
813 	agp_target_softstate_t *st;
814 
815 	if (!(flag & FKLYR))
816 		return (ENXIO);
817 
818 	st = GETSOFTC(instance);
819 
820 	if (st == NULL)
821 		return (ENXIO);
822 
823 	return (0);
824 }
825 
826 /*ARGSUSED*/
827 static int
828 agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred)
829 {
830 	int instance = DEV2INST(dev);
831 	agp_target_softstate_t *st;
832 
833 	st = GETSOFTC(instance);
834 
835 	if (st == NULL)
836 		return (ENXIO);
837 
838 	return (0);
839 }
840 
841 static  struct  cb_ops  agp_target_cb_ops = {
842 	agp_target_open,		/* cb_open */
843 	agp_target_close,		/* cb_close */
844 	nodev,				/* cb_strategy */
845 	nodev,				/* cb_print */
846 	nodev,				/* cb_dump */
847 	nodev,				/* cb_read() */
848 	nodev,				/* cb_write() */
849 	agp_target_ioctl,		/* cb_ioctl */
850 	nodev,				/* cb_devmap */
851 	nodev,				/* cb_mmap */
852 	nodev,				/* cb_segmap */
853 	nochpoll,			/* cb_chpoll */
854 	ddi_prop_op,			/* cb_prop_op */
855 	0,				/* cb_stream */
856 	D_NEW | D_MP, 			/* cb_flag */
857 	CB_REV,				/* cb_ops version? */
858 	nodev,				/* cb_aread() */
859 	nodev,				/* cb_awrite() */
860 };
861 
862 /* device operations */
863 static struct dev_ops agp_target_ops = {
864 	DEVO_REV,		/* devo_rev */
865 	0,			/* devo_refcnt */
866 	agptarget_getinfo, 	/* devo_getinfo */
867 	nulldev,		/* devo_identify */
868 	nulldev,		/* devo_probe */
869 	agp_target_attach,	/* devo_attach */
870 	agp_target_detach,	/* devo_detach */
871 	nodev,			/* devo_reset */
872 	&agp_target_cb_ops,	/* devo_cb_ops */
873 	0,			/* devo_bus_ops */
874 	0,			/* devo_power */
875 	ddi_quiesce_not_needed,	/* devo_quiesce */
876 };
877 
878 static  struct modldrv modldrv = {
879 	&mod_driverops,
880 	"AGP target driver",
881 	&agp_target_ops,
882 };
883 
884 static  struct modlinkage modlinkage = {
885 	MODREV_1,		/* MODREV_1 is indicated by manual */
886 	{&modldrv, NULL, NULL, NULL}
887 };
888 
889 int
890 _init(void)
891 {
892 	int ret;
893 
894 	ret = ddi_soft_state_init(&agptarget_glob_soft_handle,
895 	    sizeof (agp_target_softstate_t), 1);
896 
897 	if (ret)
898 		goto err1;
899 
900 	if ((ret = mod_install(&modlinkage)) != 0) {
901 		goto err2;
902 	}
903 
904 	return (DDI_SUCCESS);
905 err2:
906 	ddi_soft_state_fini(&agptarget_glob_soft_handle);
907 err1:
908 	return (ret);
909 }
910 
911 int
912 _info(struct  modinfo *modinfop)
913 {
914 	return (mod_info(&modlinkage, modinfop));
915 }
916 
917 int
918 _fini(void)
919 {
920 	int	ret;
921 
922 	if ((ret = mod_remove(&modlinkage)) == 0) {
923 		ddi_soft_state_fini(&agptarget_glob_soft_handle);
924 	}
925 	return (ret);
926 }
927