xref: /titanic_50/usr/src/uts/intel/io/agpmaster/agpmaster.c (revision 1c8fe10208a76c134f1a057de8be6ba1bc1fc499)
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 /*
28  * Misc module for AGP master device support
29  */
30 
31 #include <sys/modctl.h>
32 #include <sys/pci.h>
33 #include <sys/stat.h>
34 #include <sys/file.h>
35 #include <sys/types.h>
36 #include <sys/dditypes.h>
37 #include <sys/sunddi.h>
38 #include <sys/agpgart.h>
39 #include <sys/agp/agpdefs.h>
40 #include <sys/agp/agpmaster_io.h>
41 
42 #define	PGTBL_CTL	0x2020	/* Page table control register */
43 #define	I8XX_FB_BAR	1
44 #define	I8XX_MMIO_BAR	2
45 #define	I8XX_PTE_OFFSET	0x10000
46 #define	I915_MMADR	1	/* mem-mapped registers BAR */
47 #define	I915_GMADR	3	/* graphics mem BAR */
48 #define	I915_GTTADDR	4	/* GTT BAR */
49 #define	I965_GTTMMADR	1	/* mem-mapped registers BAR + GTT */
50 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */
51 #define	I965_GTT_OFFSET	0x80000
52 #define	GM45_GTT_OFFSET	0x200000
53 #define	GTT_SIZE_MASK	0xe
54 #define	GTT_512KB	(0 << 1)
55 #define	GTT_256KB	(1 << 1)
56 #define	GTT_128KB	(2 << 1)
57 #define	GTT_1MB		(3 << 1)
58 #define	GTT_2MB		(4 << 1)
59 #define	GTT_1_5MB	(5 << 1)
60 
61 #define	MMIO_BASE(x)	(x)->agpm_data.agpm_gtt.gtt_mmio_base
62 #define	MMIO_HANDLE(x)	(x)->agpm_data.agpm_gtt.gtt_mmio_handle
63 #define	GTT_HANDLE(x)	(x)->agpm_data.agpm_gtt.gtt_handle
64 /* Base address of GTT */
65 #define	GTT_ADDR(x)	(x)->agpm_data.agpm_gtt.gtt_addr
66 /* Graphics memory base address */
67 #define	APER_BASE(x)	(x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase
68 
69 #define	AGPM_WRITE(x, off, val) \
70     ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val));
71 
72 #define	AGPM_READ(x, off) \
73     ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)));
74 
75 #ifdef DEBUG
76 #define	CONFIRM(value) ASSERT(value)
77 #else
78 #define	CONFIRM(value) if (!(value)) return (EINVAL)
79 #endif
80 
81 int agpm_debug = 0;
82 #define	AGPM_DEBUG(args)	if (agpm_debug >= 1) cmn_err args
83 
84 /*
85  * Whether it is a Intel integrated graphics card
86  */
87 #define	IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \
88 	(agpmaster->agpm_dev_type == DEVICE_IS_I830))
89 
90 
91 /* Intel 915 and 945 series */
92 #define	IS_INTEL_915(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_915) || \
93 	(agpmaster->agpm_id == INTEL_IGD_915GM) || \
94 	(agpmaster->agpm_id == INTEL_IGD_945) || \
95 	(agpmaster->agpm_id == INTEL_IGD_945GM))
96 
97 /* Intel 965 series */
98 #define	IS_INTEL_965(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_946GZ) || \
99 	(agpmaster->agpm_id == INTEL_IGD_965G1) || \
100 	(agpmaster->agpm_id == INTEL_IGD_965Q) || \
101 	(agpmaster->agpm_id == INTEL_IGD_965G2) || \
102 	(agpmaster->agpm_id == INTEL_IGD_965GM) || \
103 	(agpmaster->agpm_id == INTEL_IGD_965GME) || \
104 	(agpmaster->agpm_id == INTEL_IGD_GM45))
105 
106 /* Intel G33 series */
107 #define	IS_INTEL_X33(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_Q35) || \
108 	(agpmaster->agpm_id == INTEL_IGD_G33) || \
109 	(agpmaster->agpm_id == INTEL_IGD_Q33))
110 
111 
112 static struct modlmisc modlmisc = {
113 	&mod_miscops, "AGP master interfaces"
114 };
115 
116 static struct modlinkage modlinkage = {
117 	MODREV_1, (void *)&modlmisc, NULL
118 };
119 
120 static ddi_device_acc_attr_t i8xx_dev_access = {
121 	DDI_DEVICE_ATTR_V0,
122 	DDI_NEVERSWAP_ACC,
123 	DDI_STRICTORDER_ACC
124 };
125 
126 static off_t agpmaster_cap_find(ddi_acc_handle_t);
127 static int detect_i8xx_device(agp_master_softc_t *);
128 static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t);
129 static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t);
130 static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t);
131 
132 int
133 _init(void)
134 {
135 	int	err;
136 
137 	if ((err = mod_install(&modlinkage)) != 0)
138 		return (err);
139 
140 	return (0);
141 }
142 
143 int
144 _fini(void)
145 {
146 	int	err;
147 
148 	if ((err = mod_remove(&modlinkage)) != 0)
149 		return (err);
150 
151 	return (0);
152 }
153 
154 int
155 _info(struct modinfo *modinfop)
156 {
157 	return (mod_info(&modlinkage, modinfop));
158 }
159 
160 /*
161  * Minor node is not removed here, since the caller (xx_attach) is
162  * responsible for removing all nodes.
163  */
164 void
165 agpmaster_detach(agp_master_softc_t **master_softcp)
166 {
167 	agp_master_softc_t *master_softc;
168 
169 	ASSERT(master_softcp);
170 	master_softc = *master_softcp;
171 
172 	/* intel integrated device */
173 	if (IS_IGD(master_softc) &&
174 	    ((MMIO_HANDLE(master_softc) != NULL) ||
175 	    (GTT_HANDLE(master_softc) != NULL))) {
176 		/*
177 		 * for some chipsets, mmap handle is shared between both mmio
178 		 * and GTT table.
179 		 */
180 		if ((GTT_HANDLE(master_softc) != MMIO_HANDLE(master_softc)) &&
181 		    (GTT_HANDLE(master_softc) != NULL))
182 			ddi_regs_map_free(&GTT_HANDLE(master_softc));
183 		if (MMIO_HANDLE(master_softc) != NULL)
184 			ddi_regs_map_free(&MMIO_HANDLE(master_softc));
185 	}
186 
187 	kmem_free(master_softc, sizeof (agp_master_softc_t));
188 	master_softc = NULL;
189 
190 	return;
191 
192 }
193 
194 /*
195  * 965 has a fixed GTT table size (512KB), so check to see the actual aperture
196  * size. Aperture size = GTT table size * 1024.
197  */
198 static off_t
199 i965_apersize(agp_master_softc_t *agpmaster)
200 {
201 	off_t apersize;
202 
203 	apersize = AGPM_READ(agpmaster, PGTBL_CTL);
204 	AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize));
205 	switch (apersize & GTT_SIZE_MASK) {
206 	case GTT_2MB:
207 		apersize = 2048;
208 		break;
209 	case GTT_1_5MB:
210 		apersize = 1536;
211 		break;
212 	case GTT_1MB:
213 		apersize = 1024;
214 		break;
215 	case GTT_512KB:
216 		apersize = 512;
217 		break;
218 	case GTT_256KB:
219 		apersize = 256;
220 		break;
221 	case GTT_128KB:
222 		apersize = 128;
223 		break;
224 	default:
225 		apersize = 0;
226 		AGPM_DEBUG((CE_WARN,
227 		    "i965_apersize: invalid GTT size in PGTBL_CTL"));
228 	}
229 	return (apersize);
230 }
231 
232 /*
233  * For Intel 3 series, we need to get GTT size from the GGMS field in GMCH
234  * Graphics Control Register. Return aperture size in MB.
235  */
236 static off_t
237 i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)
238 {
239 	uint16_t value;
240 	off_t apersize;
241 
242 	/*
243 	 * Get the value of configuration register MGGC "Mirror of Dev0 GMCH
244 	 * Graphics Control" from Internal Graphics #2 (Device2:Function0).
245 	 */
246 	value = pci_config_get16(pci_acc_hdl, I8XX_CONF_GC);
247 	AGPM_DEBUG((CE_NOTE, "i3XX_apersize: MGGC = 0x%x", value));
248 	/* computing aperture size using the pre-allocated GTT size */
249 	switch (value & IX33_GGMS_MASK) {
250 	case IX33_GGMS_1M:
251 		apersize = 1024;
252 		break;
253 	case IX33_GGMS_2M:
254 		apersize = 2048;
255 		break;
256 	default:
257 		apersize = 0;	/* no memory pre-allocated */
258 		AGPM_DEBUG((CE_WARN,
259 		    "i3XX_apersize: no memory allocated for GTT"));
260 	}
261 	AGPM_DEBUG((CE_NOTE, "i3xx_apersize: apersize = %ldM", apersize));
262 	return (apersize);
263 }
264 
265 #define	CHECK_STATUS(status)	\
266     if (status != DDI_SUCCESS) { \
267 	    AGPM_DEBUG((CE_WARN, \
268 		"set_gtt_mmio: regs_map_setup error")); \
269 	    return (-1); \
270 }
271 /*
272  * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid
273  * according to chipset.
274  */
275 static int
276 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster,
277     ddi_acc_handle_t pci_acc_hdl)
278 {
279 	off_t apersize;  /* size of graphics mem (MB) == GTT size (KB) */
280 	uint32_t value;
281 	off_t gmadr_off;  /* GMADR offset in PCI config space */
282 	int status;
283 
284 	if (IS_INTEL_X33(agpmaster)) {
285 		/* Intel 3 series are similar with 915/945 series */
286 		status = ddi_regs_map_setup(devi, I915_GTTADDR,
287 		    &GTT_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
288 		    &GTT_HANDLE(agpmaster));
289 		CHECK_STATUS(status);
290 
291 		status = ddi_regs_map_setup(devi, I915_MMADR,
292 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
293 		    &MMIO_HANDLE(agpmaster));
294 		CHECK_STATUS(status);
295 
296 		gmadr_off = I915_CONF_GMADR;
297 		/* Different computing method used in getting aperture size. */
298 		apersize = i3XX_apersize(pci_acc_hdl);
299 	} else if (IS_INTEL_965(agpmaster)) {
300 		status = ddi_regs_map_setup(devi, I965_GTTMMADR,
301 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
302 		    &MMIO_HANDLE(agpmaster));
303 		CHECK_STATUS(status);
304 		if (agpmaster->agpm_id == INTEL_IGD_GM45)
305 			GTT_ADDR(agpmaster) =
306 			    MMIO_BASE(agpmaster) + GM45_GTT_OFFSET;
307 		else
308 			GTT_ADDR(agpmaster) =
309 			    MMIO_BASE(agpmaster) + I965_GTT_OFFSET;
310 		GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
311 
312 		gmadr_off = I915_CONF_GMADR;
313 		apersize = i965_apersize(agpmaster);
314 	} else if (IS_INTEL_915(agpmaster)) {
315 		/* I915/945 series */
316 		status = ddi_regs_map_setup(devi, I915_GTTADDR,
317 		    &GTT_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
318 		    &GTT_HANDLE(agpmaster));
319 		CHECK_STATUS(status);
320 
321 		status = ddi_regs_map_setup(devi, I915_MMADR,
322 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
323 		    &MMIO_HANDLE(agpmaster));
324 		CHECK_STATUS(status);
325 
326 		gmadr_off = I915_CONF_GMADR;
327 		status = ddi_dev_regsize(devi, I915_GMADR, &apersize);
328 		apersize = BYTES2MB(apersize);
329 	} else {
330 		/* I8XX series */
331 		status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR,
332 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
333 		    &MMIO_HANDLE(agpmaster));
334 		CHECK_STATUS(status);
335 
336 		GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET;
337 		GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
338 		gmadr_off = I8XX_CONF_GMADR;
339 		status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize);
340 		apersize = BYTES2MB(apersize);
341 		CHECK_STATUS(status);
342 	}
343 
344 	/*
345 	 * If memory size is smaller than a certain value, it means
346 	 * the register set number for graphics memory range might
347 	 * be wrong
348 	 */
349 	if (status != DDI_SUCCESS || apersize < 4) {
350 		AGPM_DEBUG((CE_WARN,
351 		    "set_gtt_mmio: error in getting graphics memory"));
352 		return (-1);
353 	}
354 
355 	agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = apersize;
356 
357 	/* get graphics memory base address from GMADR */
358 	value = pci_config_get32(pci_acc_hdl, gmadr_off);
359 	APER_BASE(agpmaster) = value & GTT_BASE_MASK;
360 	AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = 0x%x, apersize = %ldM, "
361 	    "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize,
362 	    (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster)));
363 	return (0);
364 }
365 
366 /*
367  * Try to initialize agp master.
368  * 0 is returned if the device is successfully initialized. AGP master soft
369  * state is returned in master_softcp if needed.
370  * Otherwise -1 is returned and *master_softcp is set to NULL.
371  */
372 int
373 agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp,
374     ddi_acc_handle_t pci_acc_hdl, minor_t minor)
375 {
376 	int instance;
377 	int status;
378 	agp_master_softc_t *agpmaster;
379 	char buf[80];
380 
381 
382 	ASSERT(pci_acc_hdl);
383 	*master_softcp = NULL;
384 	agpmaster = (agp_master_softc_t *)
385 	    kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP);
386 
387 	agpmaster->agpm_id =
388 	    pci_config_get32(pci_acc_hdl, PCI_CONF_VENID);
389 	agpmaster->agpm_acc_hdl = pci_acc_hdl;
390 
391 	if (!detect_i8xx_device(agpmaster)) {
392 		/* Intel 8XX, 915, 945 and 965 series */
393 		if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0)
394 			goto fail;
395 	} else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) {
396 		/* non IGD or AGP devices, AMD64 gart */
397 		AGPM_DEBUG((CE_WARN,
398 		    "agpmaster_attach: neither IGD or AGP devices exists"));
399 		agpmaster_detach(&agpmaster);
400 		return (0);
401 	}
402 
403 	agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid =
404 	    agpmaster->agpm_id;
405 
406 	/* create minor node for IGD or AGP device */
407 	instance = ddi_get_instance(devi);
408 
409 	(void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance);
410 	status = ddi_create_minor_node(devi, buf, S_IFCHR, minor,
411 	    DDI_NT_AGP_MASTER, 0);
412 
413 	if (status != DDI_SUCCESS) {
414 		AGPM_DEBUG((CE_WARN,
415 		    "agpmaster_attach: create agpmaster node failed"));
416 		goto fail;
417 	}
418 
419 	*master_softcp = agpmaster;
420 	return (0);
421 fail:
422 	agpmaster_detach(&agpmaster);
423 	return (-1);
424 }
425 
426 /*
427  * Currently, it handles ioctl requests related with agp master device for
428  * layered driver (agpgart) only.
429  */
430 /*ARGSUSED*/
431 int
432 agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred,
433     int *rval, agp_master_softc_t *softc)
434 {
435 	uint32_t base;
436 	uint32_t addr;
437 	igd_gtt_seg_t seg;
438 	agp_info_t info;
439 	uint32_t value;
440 	off_t cap;
441 	uint32_t command;
442 	static char kernel_only[] =
443 	    "agpmaster_ioctl: %s is a kernel only ioctl";
444 
445 	CONFIRM(softc);
446 
447 	switch (cmd) {
448 	case DEVICE_DETECT:
449 		if (!(mode & FKIOCTL)) {
450 			AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT"));
451 			return (ENXIO);
452 		}
453 
454 		if (ddi_copyout(&softc->agpm_dev_type,
455 		    (void *)data, sizeof (int), mode))
456 			return (EFAULT);
457 		break;
458 	case AGP_MASTER_SETCMD:
459 		if (!(mode & FKIOCTL)) {
460 			AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD"));
461 			return (ENXIO);
462 		}
463 
464 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
465 		CONFIRM(softc->agpm_data.agpm_acaptr);
466 
467 		if (ddi_copyin((void *)data, &command,
468 		    sizeof (uint32_t), mode))
469 			return (EFAULT);
470 
471 		pci_config_put32(softc->agpm_acc_hdl,
472 		    softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND,
473 		    command);
474 		break;
475 	case AGP_MASTER_GETINFO:
476 		if (!(mode & FKIOCTL)) {
477 			AGPM_DEBUG((CE_CONT, kernel_only,
478 			    "AGP_MASTER_GETINFO"));
479 			return (ENXIO);
480 		}
481 
482 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
483 		CONFIRM(softc->agpm_data.agpm_acaptr);
484 
485 		cap = softc->agpm_data.agpm_acaptr;
486 		value = pci_config_get32(softc->agpm_acc_hdl, cap);
487 		info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf);
488 		info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf);
489 		info.agpi_devid = softc->agpm_id;
490 		info.agpi_mode = pci_config_get32(
491 		    softc->agpm_acc_hdl, cap + AGP_CONF_STATUS);
492 
493 		if (ddi_copyout(&info, (void *)data,
494 		    sizeof (agp_info_t), mode))
495 			return (EFAULT);
496 		break;
497 	case I810_SET_GTT_BASE:
498 		if (!(mode & FKIOCTL)) {
499 			AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR"));
500 			return (ENXIO);
501 		}
502 
503 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810);
504 
505 		if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode))
506 			return (EFAULT);
507 
508 		/* enables page table */
509 		addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID;
510 
511 		AGPM_WRITE(softc, PGTBL_CTL, addr);
512 		break;
513 	case I8XX_GET_INFO:
514 		if (!(mode & FKIOCTL)) {
515 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO"));
516 			return (ENXIO);
517 		}
518 
519 		CONFIRM(IS_IGD(softc));
520 
521 		if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info,
522 		    (void *)data, sizeof (igd_info_t), mode))
523 			return (EFAULT);
524 		break;
525 	case I8XX_ADD2GTT:
526 		if (!(mode & FKIOCTL)) {
527 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT"));
528 			return (ENXIO);
529 		}
530 
531 		CONFIRM(IS_IGD(softc));
532 
533 		if (ddi_copyin((void *)data, &seg,
534 		    sizeof (igd_gtt_seg_t), mode))
535 			return (EFAULT);
536 
537 		if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg))
538 			return (EINVAL);
539 		break;
540 	case I8XX_REM_GTT:
541 		if (!(mode & FKIOCTL)) {
542 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT"));
543 			return (ENXIO);
544 		}
545 
546 		CONFIRM(IS_IGD(softc));
547 
548 		if (ddi_copyin((void *)data, &seg,
549 		    sizeof (igd_gtt_seg_t), mode))
550 			return (EFAULT);
551 
552 		i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg);
553 		break;
554 	case I8XX_UNCONFIG:
555 		if (!(mode & FKIOCTL)) {
556 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG"));
557 			return (ENXIO);
558 		}
559 
560 		CONFIRM(IS_IGD(softc));
561 
562 		if (softc->agpm_dev_type == DEVICE_IS_I810)
563 			AGPM_WRITE(softc, PGTBL_CTL, 0);
564 		/*
565 		 * may need to clear all gtt entries here for i830 series,
566 		 * but may not be necessary
567 		 */
568 		break;
569 	}
570 	return (0);
571 }
572 
573 /*
574  * If AGP cap pointer is successfully found, none-zero value is returned.
575  * Otherwise 0 is returned.
576  */
577 static off_t
578 agpmaster_cap_find(ddi_acc_handle_t acc_handle)
579 {
580 	off_t		nextcap;
581 	uint32_t	ncapid;
582 	uint8_t		value;
583 
584 	/* check if this device supports capibility pointer */
585 	value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT)
586 	    & PCI_CONF_CAP_MASK);
587 
588 	if (!value)
589 		return (0);
590 	/* get the offset of the first capability pointer from CAPPTR */
591 	nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR));
592 
593 	/* check AGP capability from the first capability pointer */
594 	while (nextcap) {
595 		ncapid = pci_config_get32(acc_handle, nextcap);
596 		if ((ncapid & PCI_CONF_CAPID_MASK)
597 		    == AGP_CAP_ID) /* find AGP cap */
598 			break;
599 
600 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
601 	}
602 
603 	return (nextcap);
604 
605 }
606 
607 /*
608  * If i8xx device is successfully detected, 0 is returned.
609  * Otherwise -1 is returned.
610  */
611 static int
612 detect_i8xx_device(agp_master_softc_t *master_softc)
613 {
614 
615 	switch (master_softc->agpm_id) {
616 	case INTEL_IGD_810:
617 	case INTEL_IGD_810DC:
618 	case INTEL_IGD_810E:
619 	case INTEL_IGD_815:
620 		master_softc->agpm_dev_type = DEVICE_IS_I810;
621 		break;
622 	case INTEL_IGD_830M:
623 	case INTEL_IGD_845G:
624 	case INTEL_IGD_855GM:
625 	case INTEL_IGD_865G:
626 	case INTEL_IGD_915:
627 	case INTEL_IGD_915GM:
628 	case INTEL_IGD_945:
629 	case INTEL_IGD_945GM:
630 	case INTEL_IGD_946GZ:
631 	case INTEL_IGD_965G1:
632 	case INTEL_IGD_965G2:
633 	case INTEL_IGD_965GM:
634 	case INTEL_IGD_965GME:
635 	case INTEL_IGD_965Q:
636 	case INTEL_IGD_Q35:
637 	case INTEL_IGD_G33:
638 	case INTEL_IGD_Q33:
639 	case INTEL_IGD_GM45:
640 		master_softc->agpm_dev_type = DEVICE_IS_I830;
641 		break;
642 	default:		/* unknown id */
643 		return (-1);
644 	}
645 
646 	return (0);
647 }
648 
649 /*
650  * If agp master is succssfully detected, 0 is returned.
651  * Otherwise -1 is returned.
652  */
653 static int
654 detect_agp_devcice(agp_master_softc_t *master_softc,
655     ddi_acc_handle_t acc_handle)
656 {
657 	off_t cap;
658 
659 	cap = agpmaster_cap_find(acc_handle);
660 	if (cap) {
661 		master_softc->agpm_dev_type = DEVICE_IS_AGP;
662 		master_softc->agpm_data.agpm_acaptr = cap;
663 		return (0);
664 	} else {
665 		return (-1);
666 	}
667 
668 }
669 
670 /*
671  * Please refer to GART and GTT entry format table in agpdefs.h for
672  * intel GTT entry format.
673  */
674 static int
675 phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry)
676 {
677 	uint32_t value;
678 
679 	switch (type) {
680 	case AGP_PHYSICAL:
681 	case AGP_NORMAL:
682 		value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID;
683 		break;
684 	default:
685 		return (-1);
686 	}
687 
688 	*entry = value;
689 
690 	return (0);
691 }
692 
693 static int
694 i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
695 {
696 	int i;
697 	uint32_t *paddr;
698 	uint32_t entry;
699 	uint32_t maxpages;
700 
701 	maxpages = gtt->gtt_info.igd_apersize;
702 	maxpages = GTT_MB_TO_PAGES(maxpages);
703 
704 	paddr = seg.igs_phyaddr;
705 
706 	/* check if gtt max page number is reached */
707 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
708 		return (-1);
709 
710 	paddr = seg.igs_phyaddr;
711 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
712 	    i++, paddr++) {
713 		if (phys2entry(seg.igs_type, *paddr, &entry))
714 			return (-1);
715 		ddi_put32(gtt->gtt_handle,
716 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
717 		    entry);
718 	}
719 
720 	return (0);
721 }
722 
723 static void
724 i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
725 {
726 	int i;
727 	uint32_t maxpages;
728 
729 	maxpages = gtt->gtt_info.igd_apersize;
730 	maxpages = GTT_MB_TO_PAGES(maxpages);
731 
732 	/* check if gtt max page number is reached */
733 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
734 		return;
735 
736 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) {
737 		ddi_put32(gtt->gtt_handle,
738 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 0);
739 	}
740 }
741