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