13446Smrj /*
23446Smrj  * CDDL HEADER START
33446Smrj  *
43446Smrj  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
73446Smrj  *
83446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj  * or http://www.opensolaris.org/os/licensing.
103446Smrj  * See the License for the specific language governing permissions
113446Smrj  * and limitations under the License.
123446Smrj  *
133446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj  * If applicable, add the following below this CDDL HEADER, with the
163446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj  *
193446Smrj  * CDDL HEADER END
203446Smrj  */
213446Smrj 
223446Smrj /*
234303Skz151634  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
243446Smrj  * Use is subject to license terms.
253446Smrj  */
263446Smrj 
273446Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
283446Smrj 
293446Smrj /*
303446Smrj  * Misc module for AGP master device support
313446Smrj  */
323446Smrj 
333446Smrj #include <sys/modctl.h>
343446Smrj #include <sys/pci.h>
353446Smrj #include <sys/stat.h>
363446Smrj #include <sys/file.h>
373446Smrj #include <sys/types.h>
383446Smrj #include <sys/dditypes.h>
393446Smrj #include <sys/sunddi.h>
403446Smrj #include <sys/agpgart.h>
413446Smrj #include <sys/agp/agpdefs.h>
423446Smrj #include <sys/agp/agpmaster_io.h>
433446Smrj 
44*4478Skz151634 #define	PGTBL_CTL	0x2020	/* Page table control register */
45*4478Skz151634 #define	I8XX_FB_BAR	1
46*4478Skz151634 #define	I8XX_MMIO_BAR	2
47*4478Skz151634 #define	I8XX_PTE_OFFSET	0x10000
48*4478Skz151634 #define	I915_MMADR	1	/* mem-mapped registers BAR */
49*4478Skz151634 #define	I915_GMADR	3	/* graphics mem BAR */
50*4478Skz151634 #define	I915_GTTADDR	4	/* GTT BAR */
51*4478Skz151634 #define	I965_GTTMMADR	1	/* mem-mapped registers BAR + GTT */
52*4478Skz151634 #define	I965_GMADR	2	/* graphics mem BAR */
53*4478Skz151634 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */
54*4478Skz151634 #define	I965_GTT_OFFSET	0x80000
55*4478Skz151634 #define	GTT_SIZE_MASK	0xe
56*4478Skz151634 #define	GTT_512KB	(0 << 1)
57*4478Skz151634 #define	GTT_256KB	(1 << 1)
58*4478Skz151634 #define	GTT_128KB	(2 << 1)
59*4478Skz151634 
60*4478Skz151634 #define	MMIO_BASE(x)	(x)->agpm_data.agpm_gtt.gtt_mmio_base
61*4478Skz151634 #define	MMIO_HANDLE(x)	(x)->agpm_data.agpm_gtt.gtt_mmio_handle
62*4478Skz151634 #define	GTT_ADDR(x)	(x)->agpm_data.agpm_gtt.gtt_addr
63*4478Skz151634 #define	APER_BASE(x)	(x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase
64*4478Skz151634 
65*4478Skz151634 #define	AGPM_WRITE(x, off, val) \
66*4478Skz151634     ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val));
67*4478Skz151634 
68*4478Skz151634 #define	AGPM_READ(x, off) \
69*4478Skz151634     ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)));
703446Smrj 
713446Smrj #ifdef DEBUG
723446Smrj #define	CONFIRM(value) ASSERT(value)
733446Smrj #else
743446Smrj #define	CONFIRM(value) if (!(value)) return (EINVAL)
753446Smrj #endif
763446Smrj 
773446Smrj int agpm_debug = 0;
783446Smrj #define	AGPM_DEBUG(args)	if (agpm_debug >= 1) cmn_err args
793446Smrj 
803446Smrj /*
813446Smrj  * Whether it is a Intel integrated graphics card
823446Smrj  */
833446Smrj #define	IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \
84*4478Skz151634 	(agpmaster->agpm_dev_type == DEVICE_IS_I830))
853446Smrj 
863446Smrj 
87*4478Skz151634 /* Intel 915 and 945 series */
88*4478Skz151634 #define	IS_INTEL_915(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_915) || \
89*4478Skz151634 	(agpmaster->agpm_id == INTEL_IGD_915GM) || \
90*4478Skz151634 	(agpmaster->agpm_id == INTEL_IGD_945) || \
91*4478Skz151634 	(agpmaster->agpm_id == INTEL_IGD_945GM))
92*4478Skz151634 
93*4478Skz151634 /* Intel 965 series */
94*4478Skz151634 #define	IS_INTEL_965(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_946GZ) || \
95*4478Skz151634 	(agpmaster->agpm_id == INTEL_IGD_965G1) || \
96*4478Skz151634 	(agpmaster->agpm_id == INTEL_IGD_965Q) || \
97*4478Skz151634 	(agpmaster->agpm_id == INTEL_IGD_965G2) || \
98*4478Skz151634 	(agpmaster->agpm_id == INTEL_IGD_965GM))
993446Smrj 
1003446Smrj static struct modlmisc modlmisc = {
1013446Smrj 	&mod_miscops, "AGP master interfaces v%I%"
1023446Smrj };
1033446Smrj 
1043446Smrj static struct modlinkage modlinkage = {
1053446Smrj 	MODREV_1, (void *)&modlmisc, NULL
1063446Smrj };
1073446Smrj 
1083446Smrj static ddi_device_acc_attr_t i8xx_dev_access = {
1093446Smrj 	DDI_DEVICE_ATTR_V0,
1103446Smrj 	DDI_NEVERSWAP_ACC,
1113446Smrj 	DDI_STRICTORDER_ACC
1123446Smrj };
1133446Smrj 
1143446Smrj static off_t agpmaster_cap_find(ddi_acc_handle_t);
1153446Smrj static int detect_i8xx_device(agp_master_softc_t *);
1163446Smrj static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t);
1173446Smrj static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t);
1183446Smrj static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t);
1193446Smrj 
1203446Smrj int
1213446Smrj _init(void)
1223446Smrj {
1233446Smrj 	int	err;
1243446Smrj 
1253446Smrj 	if ((err = mod_install(&modlinkage)) != 0)
1263446Smrj 		return (err);
1273446Smrj 
1283446Smrj 	return (0);
1293446Smrj }
1303446Smrj 
1313446Smrj int
1323446Smrj _fini(void)
1333446Smrj {
1343446Smrj 	int	err;
1353446Smrj 
1363446Smrj 	if ((err = mod_remove(&modlinkage)) != 0)
1373446Smrj 		return (err);
1383446Smrj 
1393446Smrj 	return (0);
1403446Smrj }
1413446Smrj 
1423446Smrj int
1433446Smrj _info(struct modinfo *modinfop)
1443446Smrj {
1453446Smrj 	return (mod_info(&modlinkage, modinfop));
1463446Smrj }
1473446Smrj 
1483446Smrj /*
1493446Smrj  * Minor node is not removed here, since the caller (xx_attach) is
1503446Smrj  * responsible for removing all nodes.
1513446Smrj  */
1523446Smrj void
1533446Smrj agpmaster_detach(agp_master_softc_t **master_softcp)
1543446Smrj {
1553446Smrj 	agp_master_softc_t *master_softc;
1563446Smrj 
1573446Smrj 	ASSERT(master_softcp);
1583446Smrj 	master_softc = *master_softcp;
1593446Smrj 
1603446Smrj 	/* intel integrated device */
1613446Smrj 	if (IS_IGD(master_softc)) {
162*4478Skz151634 		if (MMIO_HANDLE(master_softc) != NULL) {
163*4478Skz151634 			ddi_regs_map_free(&MMIO_HANDLE(master_softc));
1643446Smrj 		}
1653446Smrj 	}
1663446Smrj 
1673446Smrj 	kmem_free(master_softc, sizeof (agp_master_softc_t));
1683446Smrj 	master_softc = NULL;
1693446Smrj 
1703446Smrj 	return;
1713446Smrj 
1723446Smrj }
1733446Smrj 
1743446Smrj /*
175*4478Skz151634  * 965 has a fixed GTT table size (512KB), so check to see the actual aperture
176*4478Skz151634  * size. Aperture size = GTT table size * 1024.
177*4478Skz151634  */
178*4478Skz151634 static off_t
179*4478Skz151634 i965_apersize(agp_master_softc_t *agpmaster)
180*4478Skz151634 {
181*4478Skz151634 	off_t apersize;
182*4478Skz151634 
183*4478Skz151634 	apersize = AGPM_READ(agpmaster, PGTBL_CTL);
184*4478Skz151634 	AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize));
185*4478Skz151634 	switch (apersize & GTT_SIZE_MASK) {
186*4478Skz151634 	case GTT_512KB:
187*4478Skz151634 		apersize = 512;
188*4478Skz151634 		break;
189*4478Skz151634 	case GTT_256KB:
190*4478Skz151634 		apersize = 256;
191*4478Skz151634 		break;
192*4478Skz151634 	case GTT_128KB:
193*4478Skz151634 		apersize = 128;
194*4478Skz151634 		break;
195*4478Skz151634 	default:
196*4478Skz151634 		AGPM_DEBUG((CE_WARN,
197*4478Skz151634 		    "i965_apersize: invalid GTT size in PGTBL_CTL"));
198*4478Skz151634 	}
199*4478Skz151634 	apersize = MB2BYTES(apersize);
200*4478Skz151634 	return (apersize);
201*4478Skz151634 }
202*4478Skz151634 
203*4478Skz151634 #define	CHECK_STATUS(status)	\
204*4478Skz151634     if (status != DDI_SUCCESS) { \
205*4478Skz151634 	    AGPM_DEBUG((CE_WARN, \
206*4478Skz151634 		"set_gtt_mmio: regs_map_setup error")); \
207*4478Skz151634 	    return (-1); \
208*4478Skz151634 }
209*4478Skz151634 /*
210*4478Skz151634  * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid
211*4478Skz151634  * according to chipset.
212*4478Skz151634  */
213*4478Skz151634 static int
214*4478Skz151634 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster, ddi_acc_handle_t
215*4478Skz151634     pci_acc_hdl)
216*4478Skz151634 {
217*4478Skz151634 	off_t apersize;
218*4478Skz151634 	uint32_t value;
219*4478Skz151634 	off_t conf_off; /* offset in PCI conf space for aperture */
220*4478Skz151634 	int status;
221*4478Skz151634 
222*4478Skz151634 	if (IS_INTEL_965(agpmaster)) {
223*4478Skz151634 		status = ddi_regs_map_setup(devi, I965_GTTMMADR,
224*4478Skz151634 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
225*4478Skz151634 		    &MMIO_HANDLE(agpmaster));
226*4478Skz151634 		CHECK_STATUS(status);
227*4478Skz151634 		GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I965_GTT_OFFSET;
228*4478Skz151634 
229*4478Skz151634 		conf_off = I915_CONF_GMADR;
230*4478Skz151634 		apersize = i965_apersize(agpmaster);
231*4478Skz151634 		/* make this the last line, to clear follow-up status check */
232*4478Skz151634 		status = DDI_SUCCESS;
233*4478Skz151634 
234*4478Skz151634 	} else if (IS_INTEL_915(agpmaster)) {
235*4478Skz151634 		status = ddi_regs_map_setup(devi, I915_GTTADDR,
236*4478Skz151634 		    &GTT_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
237*4478Skz151634 		    &MMIO_HANDLE(agpmaster));
238*4478Skz151634 		CHECK_STATUS(status);
239*4478Skz151634 
240*4478Skz151634 		status = ddi_regs_map_setup(devi, I915_MMADR,
241*4478Skz151634 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
242*4478Skz151634 		    &MMIO_HANDLE(agpmaster));
243*4478Skz151634 		CHECK_STATUS(status);
244*4478Skz151634 
245*4478Skz151634 		conf_off = I915_CONF_GMADR;
246*4478Skz151634 		status = ddi_dev_regsize(devi, I915_GMADR, &apersize);
247*4478Skz151634 	} else {
248*4478Skz151634 		/* I8XX series */
249*4478Skz151634 		status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR,
250*4478Skz151634 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
251*4478Skz151634 		    &MMIO_HANDLE(agpmaster));
252*4478Skz151634 		CHECK_STATUS(status);
253*4478Skz151634 
254*4478Skz151634 		GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET;
255*4478Skz151634 		conf_off = I8XX_CONF_GMADR;
256*4478Skz151634 		status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize);
257*4478Skz151634 		CHECK_STATUS(status);
258*4478Skz151634 	}
259*4478Skz151634 
260*4478Skz151634 	/*
261*4478Skz151634 	 * if memory size is smaller than a certain value, it means
262*4478Skz151634 	 * the register set number for graphics memory range might
263*4478Skz151634 	 * be wrong
264*4478Skz151634 	 */
265*4478Skz151634 	if (status != DDI_SUCCESS || apersize < 0x400000) {
266*4478Skz151634 		AGPM_DEBUG((CE_WARN,
267*4478Skz151634 		    "set_gtt_mmio: ddi_dev_regsize error"));
268*4478Skz151634 		return (-1);
269*4478Skz151634 	}
270*4478Skz151634 
271*4478Skz151634 	agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize =
272*4478Skz151634 	    BYTES2MB(apersize);
273*4478Skz151634 
274*4478Skz151634 	/* get GTT base */
275*4478Skz151634 	value = pci_config_get32(pci_acc_hdl, conf_off);
276*4478Skz151634 
277*4478Skz151634 	APER_BASE(agpmaster) = value & GTT_BASE_MASK;
278*4478Skz151634 	agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid =
279*4478Skz151634 	    agpmaster->agpm_id;
280*4478Skz151634 	AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = %x, apersize = %lx, "
281*4478Skz151634 	    "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize,
282*4478Skz151634 	    (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster)));
283*4478Skz151634 	return (0);
284*4478Skz151634 }
285*4478Skz151634 
286*4478Skz151634 /*
2873446Smrj  * Try to initialize agp master.
2883446Smrj  * 0 is returned if the device is successfully initialized. AGP master soft
2893446Smrj  * state is returned in master_softcp if needed.
2903446Smrj  * Otherwise -1 is returned and *master_softcp is set to NULL.
2913446Smrj  */
2923446Smrj int
2933446Smrj agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp,
2943446Smrj     ddi_acc_handle_t pci_acc_hdl, minor_t minor)
2953446Smrj {
2963446Smrj 	int instance;
2973446Smrj 	int status;
2983446Smrj 	agp_master_softc_t *agpmaster;
2993446Smrj 	char buf[80];
3003446Smrj 
3013446Smrj 
3023446Smrj 	ASSERT(pci_acc_hdl);
3033446Smrj 	*master_softcp = NULL;
3043446Smrj 	agpmaster = (agp_master_softc_t *)
3053446Smrj 	    kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP);
3063446Smrj 
3073446Smrj 	agpmaster->agpm_id =
3083446Smrj 	    pci_config_get32(pci_acc_hdl, PCI_CONF_VENID);
3093446Smrj 	agpmaster->agpm_acc_hdl = pci_acc_hdl;
3103446Smrj 
3113446Smrj 	if (!detect_i8xx_device(agpmaster)) {
312*4478Skz151634 		/* Intel 8XX, 915, 945 and 965 series */
313*4478Skz151634 		if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0)
3143446Smrj 			goto fail;
3153446Smrj 	} else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) {
316*4478Skz151634 		/* non IGD or AGP devices, AMD64 gart */
3173446Smrj 		AGPM_DEBUG((CE_WARN,
3183446Smrj 		    "agpmaster_attach: neither IGD or AGP devices exists"));
3193446Smrj 		agpmaster_detach(&agpmaster);
3203446Smrj 		return (0);
3213446Smrj 	}
3223446Smrj 
3233446Smrj 	/* create minor node for IGD or AGP device */
3243446Smrj 	instance = ddi_get_instance(devi);
3253446Smrj 
3263446Smrj 	(void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance);
3273446Smrj 	status = ddi_create_minor_node(devi, buf, S_IFCHR, minor,
3283446Smrj 	    DDI_NT_AGP_MASTER, 0);
3293446Smrj 
3303446Smrj 	if (status != DDI_SUCCESS) {
3313446Smrj 		AGPM_DEBUG((CE_WARN,
3323446Smrj 		    "agpmaster_attach: create agpmaster node failed"));
3333446Smrj 		goto fail;
3343446Smrj 	}
3353446Smrj 
3363446Smrj 	*master_softcp = agpmaster;
3373446Smrj 	return (0);
3383446Smrj fail:
3393446Smrj 	agpmaster_detach(&agpmaster);
3403446Smrj 	return (-1);
3413446Smrj }
3423446Smrj 
3433446Smrj /*
3443446Smrj  * Currently, it handles ioctl requests related with agp master device for
3453446Smrj  * layered driver (agpgart) only.
3463446Smrj  */
3473446Smrj /*ARGSUSED*/
3483446Smrj int
3493446Smrj agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred,
3503446Smrj     int *rval, agp_master_softc_t *softc)
3513446Smrj {
3523446Smrj 	uint32_t base;
3533446Smrj 	uint32_t addr;
3543446Smrj 	igd_gtt_seg_t seg;
3553446Smrj 	agp_info_t info;
3563446Smrj 	uint32_t value;
3573446Smrj 	off_t cap;
3583446Smrj 	uint32_t command;
3593446Smrj 	static char kernel_only[] =
3603446Smrj 	    "agpmaster_ioctl: %s is a kernel only ioctl";
3613446Smrj 
3623446Smrj 	CONFIRM(softc);
3633446Smrj 
3643446Smrj 	switch (cmd) {
3653446Smrj 	case DEVICE_DETECT:
3663446Smrj 		if (!(mode & FKIOCTL)) {
3673446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT"));
3683446Smrj 			return (ENXIO);
3693446Smrj 		}
3703446Smrj 
3713446Smrj 		if (ddi_copyout(&softc->agpm_dev_type,
3723446Smrj 		    (void *)data, sizeof (int), mode))
3733446Smrj 			return (EFAULT);
3743446Smrj 		break;
3753446Smrj 	case AGP_MASTER_SETCMD:
3763446Smrj 		if (!(mode & FKIOCTL)) {
3773446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD"));
3783446Smrj 			return (ENXIO);
3793446Smrj 		}
3803446Smrj 
3813446Smrj 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
3823446Smrj 		CONFIRM(softc->agpm_data.agpm_acaptr);
3833446Smrj 
3843446Smrj 		if (ddi_copyin((void *)data, &command,
3853446Smrj 		    sizeof (uint32_t), mode))
3863446Smrj 			return (EFAULT);
3873446Smrj 
3883446Smrj 		pci_config_put32(softc->agpm_acc_hdl,
3893446Smrj 		    softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND,
3903446Smrj 		    command);
3913446Smrj 		break;
3923446Smrj 	case AGP_MASTER_GETINFO:
3933446Smrj 		if (!(mode & FKIOCTL)) {
3943446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only,
3953446Smrj 			    "AGP_MASTER_GETINFO"));
3963446Smrj 			return (ENXIO);
3973446Smrj 		}
3983446Smrj 
3993446Smrj 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
4003446Smrj 		CONFIRM(softc->agpm_data.agpm_acaptr);
4013446Smrj 
4023446Smrj 		cap = softc->agpm_data.agpm_acaptr;
4033446Smrj 		value = pci_config_get32(softc->agpm_acc_hdl, cap);
4043446Smrj 		info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf);
4053446Smrj 		info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf);
4063446Smrj 		info.agpi_devid = softc->agpm_id;
4073446Smrj 		info.agpi_mode = pci_config_get32(
4083446Smrj 		    softc->agpm_acc_hdl, cap + AGP_CONF_STATUS);
4093446Smrj 
4103446Smrj 		if (ddi_copyout(&info, (void *)data,
4113446Smrj 		    sizeof (agp_info_t), mode))
4123446Smrj 			return (EFAULT);
4133446Smrj 		break;
4143446Smrj 	case I810_SET_GTT_BASE:
4153446Smrj 		if (!(mode & FKIOCTL)) {
4163446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR"));
4173446Smrj 			return (ENXIO);
4183446Smrj 		}
4193446Smrj 
4203446Smrj 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810);
4213446Smrj 
4223446Smrj 		if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode))
4233446Smrj 			return (EFAULT);
4243446Smrj 
4253446Smrj 		/* enables page table */
4263446Smrj 		addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID;
4273446Smrj 
428*4478Skz151634 		AGPM_WRITE(softc, PGTBL_CTL, addr);
4293446Smrj 		break;
4303446Smrj 	case I8XX_GET_INFO:
4313446Smrj 		if (!(mode & FKIOCTL)) {
4323446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO"));
4333446Smrj 			return (ENXIO);
4343446Smrj 		}
4353446Smrj 
4363446Smrj 		CONFIRM(IS_IGD(softc));
4373446Smrj 
4383446Smrj 		if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info,
4393446Smrj 		    (void *)data, sizeof (igd_info_t), mode))
4403446Smrj 			return (EFAULT);
4413446Smrj 		break;
4423446Smrj 	case I8XX_ADD2GTT:
4433446Smrj 		if (!(mode & FKIOCTL)) {
4443446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT"));
4453446Smrj 			return (ENXIO);
4463446Smrj 		}
4473446Smrj 
4483446Smrj 		CONFIRM(IS_IGD(softc));
4493446Smrj 
4503446Smrj 		if (ddi_copyin((void *)data, &seg,
4513446Smrj 		    sizeof (igd_gtt_seg_t), mode))
4523446Smrj 			return (EFAULT);
4533446Smrj 
4543446Smrj 		if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg))
4553446Smrj 			return (EINVAL);
4563446Smrj 		break;
4573446Smrj 	case I8XX_REM_GTT:
4583446Smrj 		if (!(mode & FKIOCTL)) {
4593446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT"));
4603446Smrj 			return (ENXIO);
4613446Smrj 		}
4623446Smrj 
4633446Smrj 		CONFIRM(IS_IGD(softc));
4643446Smrj 
4653446Smrj 		if (ddi_copyin((void *)data, &seg,
4663446Smrj 		    sizeof (igd_gtt_seg_t), mode))
4673446Smrj 			return (EFAULT);
4683446Smrj 
4693446Smrj 		i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg);
4703446Smrj 		break;
4713446Smrj 	case I8XX_UNCONFIG:
4723446Smrj 		if (!(mode & FKIOCTL)) {
4733446Smrj 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG"));
4743446Smrj 			return (ENXIO);
4753446Smrj 		}
4763446Smrj 
4773446Smrj 		CONFIRM(IS_IGD(softc));
4783446Smrj 
4793446Smrj 		if (softc->agpm_dev_type == DEVICE_IS_I810)
480*4478Skz151634 			AGPM_WRITE(softc, PGTBL_CTL, 0);
4813446Smrj 		/*
4823446Smrj 		 * may need to clear all gtt entries here for i830 series,
4833446Smrj 		 * but may not be necessary
4843446Smrj 		 */
4853446Smrj 		break;
4863446Smrj 	}
4873446Smrj 	return (0);
4883446Smrj }
4893446Smrj 
4903446Smrj /*
4913446Smrj  * If AGP cap pointer is successfully found, none-zero value is returned.
4923446Smrj  * Otherwise 0 is returned.
4933446Smrj  */
4943446Smrj static off_t
4953446Smrj agpmaster_cap_find(ddi_acc_handle_t acc_handle)
4963446Smrj {
4973446Smrj 	off_t		nextcap;
4983446Smrj 	uint32_t	ncapid;
4993446Smrj 	uint8_t		value;
5003446Smrj 
5013446Smrj 	/* check if this device supports capibility pointer */
5023446Smrj 	value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT)
5034303Skz151634 	    & PCI_CONF_CAP_MASK);
5043446Smrj 
5053446Smrj 	if (!value)
5063446Smrj 		return (0);
5073446Smrj 	/* get the offset of the first capability pointer from CAPPTR */
5083446Smrj 	nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR));
5093446Smrj 
5103446Smrj 	/* check AGP capability from the first capability pointer */
5113446Smrj 	while (nextcap) {
5123446Smrj 		ncapid = pci_config_get32(acc_handle, nextcap);
5133446Smrj 		if ((ncapid & PCI_CONF_CAPID_MASK)
5143446Smrj 		    == AGP_CAP_ID) /* find AGP cap */
5153446Smrj 			break;
5163446Smrj 
5173446Smrj 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
5183446Smrj 	}
5193446Smrj 
5203446Smrj 	return (nextcap);
5213446Smrj 
5223446Smrj }
5233446Smrj 
5243446Smrj /*
5253446Smrj  * If i8xx device is successfully detected, 0 is returned.
5263446Smrj  * Otherwise -1 is returned.
5273446Smrj  */
5283446Smrj static int
5293446Smrj detect_i8xx_device(agp_master_softc_t *master_softc)
5303446Smrj {
5313446Smrj 
5323446Smrj 	switch (master_softc->agpm_id) {
5333446Smrj 	case INTEL_IGD_810:
5343446Smrj 	case INTEL_IGD_810DC:
5353446Smrj 	case INTEL_IGD_810E:
5363446Smrj 	case INTEL_IGD_815:
5373446Smrj 		master_softc->agpm_dev_type = DEVICE_IS_I810;
5383446Smrj 		break;
5393446Smrj 	case INTEL_IGD_830M:
5403446Smrj 	case INTEL_IGD_845G:
5413446Smrj 	case INTEL_IGD_855GM:
5423446Smrj 	case INTEL_IGD_865G:
543*4478Skz151634 	case INTEL_IGD_915:
544*4478Skz151634 	case INTEL_IGD_915GM:
5453446Smrj 	case INTEL_IGD_945:
5464303Skz151634 	case INTEL_IGD_945GM:
547*4478Skz151634 	case INTEL_IGD_946GZ:
548*4478Skz151634 	case INTEL_IGD_965G1:
549*4478Skz151634 	case INTEL_IGD_965G2:
550*4478Skz151634 	case INTEL_IGD_965GM:
551*4478Skz151634 	case INTEL_IGD_965Q:
5523446Smrj 		master_softc->agpm_dev_type = DEVICE_IS_I830;
5533446Smrj 		break;
5543446Smrj 	default:		/* unknown id */
5553446Smrj 		return (-1);
5563446Smrj 	}
5573446Smrj 
5583446Smrj 	return (0);
5593446Smrj }
5603446Smrj 
5613446Smrj /*
5623446Smrj  * If agp master is succssfully detected, 0 is returned.
5633446Smrj  * Otherwise -1 is returned.
5643446Smrj  */
5653446Smrj static int
5663446Smrj detect_agp_devcice(agp_master_softc_t *master_softc,
5673446Smrj     ddi_acc_handle_t acc_handle)
5683446Smrj {
5693446Smrj 	off_t cap;
5703446Smrj 
5713446Smrj 	cap = agpmaster_cap_find(acc_handle);
5723446Smrj 	if (cap) {
5733446Smrj 		master_softc->agpm_dev_type = DEVICE_IS_AGP;
5743446Smrj 		master_softc->agpm_data.agpm_acaptr = cap;
5753446Smrj 		return (0);
5763446Smrj 	} else {
5773446Smrj 		return (-1);
5783446Smrj 	}
5793446Smrj 
5803446Smrj }
5813446Smrj 
5823446Smrj /*
5833446Smrj  * Please refer to GART and GTT entry format table in agpdefs.h for
5843446Smrj  * intel GTT entry format.
5853446Smrj  */
5863446Smrj static int
5873446Smrj phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry)
5883446Smrj {
5893446Smrj 	uint32_t value;
5903446Smrj 
5913446Smrj 	switch (type) {
5923446Smrj 	case AGP_PHYSICAL:
5933446Smrj 	case AGP_NORMAL:
5943446Smrj 		value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID;
5953446Smrj 		break;
5963446Smrj 	default:
5973446Smrj 		return (-1);
5983446Smrj 	}
5993446Smrj 
6003446Smrj 	*entry = value;
6013446Smrj 
6023446Smrj 	return (0);
6033446Smrj }
6043446Smrj 
6053446Smrj static int
6063446Smrj i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
6073446Smrj {
6083446Smrj 	int i;
6093446Smrj 	uint32_t *paddr;
6103446Smrj 	uint32_t entry;
6113446Smrj 	uint32_t maxpages;
6123446Smrj 
6133446Smrj 	maxpages = gtt->gtt_info.igd_apersize;
6143446Smrj 	maxpages = GTT_MB_TO_PAGES(maxpages);
6153446Smrj 
6163446Smrj 	paddr = seg.igs_phyaddr;
6173446Smrj 
6183446Smrj 	/* check if gtt max page number is reached */
6193446Smrj 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
6203446Smrj 		return (-1);
6213446Smrj 
6223446Smrj 	paddr = seg.igs_phyaddr;
6233446Smrj 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
6243446Smrj 	    i++, paddr++) {
6253446Smrj 		if (phys2entry(seg.igs_type, *paddr, &entry))
6263446Smrj 			return (-1);
6273446Smrj 		ddi_put32(gtt->gtt_mmio_handle,
6283446Smrj 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
6293446Smrj 		    entry);
6303446Smrj 	}
6313446Smrj 
6323446Smrj 	return (0);
6333446Smrj }
6343446Smrj 
6353446Smrj static void
6363446Smrj i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
6373446Smrj {
6383446Smrj 	int i;
6393446Smrj 	uint32_t maxpages;
6403446Smrj 
6413446Smrj 	maxpages = gtt->gtt_info.igd_apersize;
6423446Smrj 	maxpages = GTT_MB_TO_PAGES(maxpages);
6433446Smrj 
6443446Smrj 	/* check if gtt max page number is reached */
6453446Smrj 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
6463446Smrj 		return;
6473446Smrj 
6483446Smrj 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) {
6493446Smrj 		ddi_put32(gtt->gtt_mmio_handle,
650*4478Skz151634 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 0);
6513446Smrj 	}
6523446Smrj }
653