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