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