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