xref: /gfx-drm/usr/src/uts/intel/io/agpmaster/agpmaster.c (revision 3db4bae9)
1829150b0SGordon Ross /*
2829150b0SGordon Ross  * CDDL HEADER START
3829150b0SGordon Ross  *
4829150b0SGordon Ross  * The contents of this file are subject to the terms of the
5829150b0SGordon Ross  * Common Development and Distribution License (the "License").
6829150b0SGordon Ross  * You may not use this file except in compliance with the License.
7829150b0SGordon Ross  *
8829150b0SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9829150b0SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10829150b0SGordon Ross  * See the License for the specific language governing permissions
11829150b0SGordon Ross  * and limitations under the License.
12829150b0SGordon Ross  *
13829150b0SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14829150b0SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15829150b0SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16829150b0SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17829150b0SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18829150b0SGordon Ross  *
19829150b0SGordon Ross  * CDDL HEADER END
20829150b0SGordon Ross  */
21829150b0SGordon Ross 
22829150b0SGordon Ross /*
23829150b0SGordon Ross  * Copyright (c) 2009, Intel Corporation.
24829150b0SGordon Ross  * All Rights Reserved.
25829150b0SGordon Ross  */
26829150b0SGordon Ross 
27829150b0SGordon Ross /*
28829150b0SGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
29829150b0SGordon Ross  * Use is subject to license terms.
30829150b0SGordon Ross  */
31829150b0SGordon Ross 
32829150b0SGordon Ross /*
33829150b0SGordon Ross  * Misc module for AGP master device support
34829150b0SGordon Ross  */
35829150b0SGordon Ross 
36829150b0SGordon Ross #include <sys/modctl.h>
37829150b0SGordon Ross #include <sys/pci.h>
38829150b0SGordon Ross #include <sys/stat.h>
39829150b0SGordon Ross #include <sys/file.h>
40829150b0SGordon Ross #include <sys/types.h>
41829150b0SGordon Ross #include <sys/dditypes.h>
42829150b0SGordon Ross #include <sys/sunddi.h>
43829150b0SGordon Ross #include <sys/agpgart.h>
44829150b0SGordon Ross #include <sys/agp/agpdefs.h>
45829150b0SGordon Ross #include <sys/agp/agpmaster_io.h>
46829150b0SGordon Ross 
47829150b0SGordon Ross #define	PGTBL_CTL	0x2020	/* Page table control register */
48829150b0SGordon Ross #define	I8XX_FB_BAR	1
49829150b0SGordon Ross #define	I8XX_MMIO_BAR	2
50829150b0SGordon Ross #define	I8XX_PTE_OFFSET	0x10000
51829150b0SGordon Ross #define	I915_MMADR	1	/* mem-mapped registers BAR */
52829150b0SGordon Ross #define	I915_GMADR	3	/* graphics mem BAR */
53829150b0SGordon Ross #define	I915_GTTADDR	4	/* GTT BAR */
54829150b0SGordon Ross #define	I965_GTTMMADR	1	/* mem-mapped registers BAR + GTT */
55829150b0SGordon Ross /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */
56829150b0SGordon Ross #define	I965_GTT_OFFSET	0x80000
57829150b0SGordon Ross #define	GM45_GTT_OFFSET	0x200000
58829150b0SGordon Ross #define	GTT_SIZE_MASK	0xe
59829150b0SGordon Ross #define	GTT_512KB	(0 << 1)
60829150b0SGordon Ross #define	GTT_256KB	(1 << 1)
61829150b0SGordon Ross #define	GTT_128KB	(2 << 1)
62829150b0SGordon Ross #define	GTT_1MB		(3 << 1)
63829150b0SGordon Ross #define	GTT_2MB		(4 << 1)
64829150b0SGordon Ross #define	GTT_1_5MB	(5 << 1)
65829150b0SGordon Ross 
66829150b0SGordon Ross #define	MMIO_BASE(x)	(x)->agpm_data.agpm_gtt.gtt_mmio_base
67829150b0SGordon Ross #define	MMIO_HANDLE(x)	(x)->agpm_data.agpm_gtt.gtt_mmio_handle
68829150b0SGordon Ross #define	GTT_HANDLE(x)	(x)->agpm_data.agpm_gtt.gtt_handle
69829150b0SGordon Ross /* Base address of GTT */
70829150b0SGordon Ross #define	GTT_ADDR(x)	(x)->agpm_data.agpm_gtt.gtt_addr
71829150b0SGordon Ross /* Graphics memory base address */
72829150b0SGordon Ross #define	APER_BASE(x)	(x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase
73829150b0SGordon Ross 
74829150b0SGordon Ross #define	AGPM_WRITE(x, off, val) \
75829150b0SGordon Ross     ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val));
76829150b0SGordon Ross 
77829150b0SGordon Ross #define	AGPM_READ(x, off) \
78829150b0SGordon Ross     ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)));
79829150b0SGordon Ross 
80829150b0SGordon Ross #ifdef DEBUG
81829150b0SGordon Ross #define	CONFIRM(value) ASSERT(value)
82829150b0SGordon Ross #else
83829150b0SGordon Ross #define	CONFIRM(value) if (!(value)) return (EINVAL)
84829150b0SGordon Ross #endif
85829150b0SGordon Ross 
86829150b0SGordon Ross int agpm_debug = 0;
87829150b0SGordon Ross #define	AGPM_DEBUG(args)	if (agpm_debug >= 1) cmn_err args
88829150b0SGordon Ross 
89829150b0SGordon Ross /*
90829150b0SGordon Ross  * Whether it is a Intel integrated graphics card
91829150b0SGordon Ross  */
92829150b0SGordon Ross #define	IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \
93829150b0SGordon Ross 	(agpmaster->agpm_dev_type == DEVICE_IS_I830))
94829150b0SGordon Ross 
95829150b0SGordon Ross static struct modlmisc modlmisc = {
96829150b0SGordon Ross 	&mod_miscops, "AGP master interfaces"
97829150b0SGordon Ross };
98829150b0SGordon Ross 
99829150b0SGordon Ross static struct modlinkage modlinkage = {
100829150b0SGordon Ross 	MODREV_1, (void *)&modlmisc, NULL
101829150b0SGordon Ross };
102829150b0SGordon Ross 
103829150b0SGordon Ross static ddi_device_acc_attr_t i8xx_dev_access = {
104829150b0SGordon Ross 	DDI_DEVICE_ATTR_V0,
105829150b0SGordon Ross 	DDI_NEVERSWAP_ACC,
106829150b0SGordon Ross 	DDI_STRICTORDER_ACC
107829150b0SGordon Ross };
108829150b0SGordon Ross 
109829150b0SGordon Ross static off_t agpmaster_cap_find(ddi_acc_handle_t);
110829150b0SGordon Ross static int detect_i8xx_device(agp_master_softc_t *);
111829150b0SGordon Ross static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t);
112829150b0SGordon Ross static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t);
113829150b0SGordon Ross static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t);
114*3db4bae9SGordon Ross static int i8xx_read_gtt(gtt_impl_t *, igd_gtt_seg_t);
115*3db4bae9SGordon Ross static int i8xx_write_gtt(gtt_impl_t *, igd_gtt_seg_t);
116829150b0SGordon Ross 
117829150b0SGordon Ross int
_init(void)118829150b0SGordon Ross _init(void)
119829150b0SGordon Ross {
120829150b0SGordon Ross 	int	err;
121829150b0SGordon Ross 
122829150b0SGordon Ross 	if ((err = mod_install(&modlinkage)) != 0)
123829150b0SGordon Ross 		return (err);
124829150b0SGordon Ross 
125829150b0SGordon Ross 	return (0);
126829150b0SGordon Ross }
127829150b0SGordon Ross 
128829150b0SGordon Ross int
_fini(void)129829150b0SGordon Ross _fini(void)
130829150b0SGordon Ross {
131829150b0SGordon Ross 	int	err;
132829150b0SGordon Ross 
133829150b0SGordon Ross 	if ((err = mod_remove(&modlinkage)) != 0)
134829150b0SGordon Ross 		return (err);
135829150b0SGordon Ross 
136829150b0SGordon Ross 	return (0);
137829150b0SGordon Ross }
138829150b0SGordon Ross 
139829150b0SGordon Ross int
_info(struct modinfo * modinfop)140829150b0SGordon Ross _info(struct modinfo *modinfop)
141829150b0SGordon Ross {
142829150b0SGordon Ross 	return (mod_info(&modlinkage, modinfop));
143829150b0SGordon Ross }
144829150b0SGordon Ross 
145829150b0SGordon Ross /*
146829150b0SGordon Ross  * Minor node is not removed here, since the caller (xx_attach) is
147829150b0SGordon Ross  * responsible for removing all nodes.
148829150b0SGordon Ross  */
149829150b0SGordon Ross void
agpmaster_detach(agp_master_softc_t ** master_softcp)150829150b0SGordon Ross agpmaster_detach(agp_master_softc_t **master_softcp)
151829150b0SGordon Ross {
152829150b0SGordon Ross 	agp_master_softc_t *master_softc;
153829150b0SGordon Ross 
154829150b0SGordon Ross 	ASSERT(master_softcp);
155829150b0SGordon Ross 	master_softc = *master_softcp;
156829150b0SGordon Ross 
157829150b0SGordon Ross 	/* intel integrated device */
158829150b0SGordon Ross 	if (IS_IGD(master_softc) &&
159829150b0SGordon Ross 	    ((MMIO_HANDLE(master_softc) != NULL) ||
160829150b0SGordon Ross 	    (GTT_HANDLE(master_softc) != NULL))) {
161829150b0SGordon Ross 		/*
162829150b0SGordon Ross 		 * for some chipsets, mmap handle is shared between both mmio
163829150b0SGordon Ross 		 * and GTT table.
164829150b0SGordon Ross 		 */
165829150b0SGordon Ross 		if ((GTT_HANDLE(master_softc) != MMIO_HANDLE(master_softc)) &&
166829150b0SGordon Ross 		    (GTT_HANDLE(master_softc) != NULL))
167829150b0SGordon Ross 			ddi_regs_map_free(&GTT_HANDLE(master_softc));
168829150b0SGordon Ross 		if (MMIO_HANDLE(master_softc) != NULL)
169829150b0SGordon Ross 			ddi_regs_map_free(&MMIO_HANDLE(master_softc));
170829150b0SGordon Ross 	}
171829150b0SGordon Ross 
172829150b0SGordon Ross 	kmem_free(master_softc, sizeof (agp_master_softc_t));
173829150b0SGordon Ross 	master_softc = NULL;
174829150b0SGordon Ross 
175829150b0SGordon Ross 	return;
176829150b0SGordon Ross 
177829150b0SGordon Ross }
178829150b0SGordon Ross 
179829150b0SGordon Ross /*
180829150b0SGordon Ross  * 965 has a fixed GTT table size (512KB), so check to see the actual aperture
181829150b0SGordon Ross  * size. Aperture size = GTT table size * 1024.
182829150b0SGordon Ross  */
183829150b0SGordon Ross static off_t
i965_apersize(agp_master_softc_t * agpmaster)184829150b0SGordon Ross i965_apersize(agp_master_softc_t *agpmaster)
185829150b0SGordon Ross {
186829150b0SGordon Ross 	off_t apersize;
187829150b0SGordon Ross 
188829150b0SGordon Ross 	apersize = AGPM_READ(agpmaster, PGTBL_CTL);
189829150b0SGordon Ross 	AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize));
190829150b0SGordon Ross 	switch (apersize & GTT_SIZE_MASK) {
191829150b0SGordon Ross 	case GTT_2MB:
192829150b0SGordon Ross 		apersize = 2048;
193829150b0SGordon Ross 		break;
194829150b0SGordon Ross 	case GTT_1_5MB:
195829150b0SGordon Ross 		apersize = 1536;
196829150b0SGordon Ross 		break;
197829150b0SGordon Ross 	case GTT_1MB:
198829150b0SGordon Ross 		apersize = 1024;
199829150b0SGordon Ross 		break;
200829150b0SGordon Ross 	case GTT_512KB:
201829150b0SGordon Ross 		apersize = 512;
202829150b0SGordon Ross 		break;
203829150b0SGordon Ross 	case GTT_256KB:
204829150b0SGordon Ross 		apersize = 256;
205829150b0SGordon Ross 		break;
206829150b0SGordon Ross 	case GTT_128KB:
207829150b0SGordon Ross 		apersize = 128;
208829150b0SGordon Ross 		break;
209829150b0SGordon Ross 	default:
210829150b0SGordon Ross 		apersize = 0;
211829150b0SGordon Ross 		AGPM_DEBUG((CE_WARN,
212829150b0SGordon Ross 		    "i965_apersize: invalid GTT size in PGTBL_CTL"));
213829150b0SGordon Ross 	}
214829150b0SGordon Ross 	return (apersize);
215829150b0SGordon Ross }
216829150b0SGordon Ross 
217829150b0SGordon Ross /*
218829150b0SGordon Ross  * For Intel 3 series, we need to get GTT size from the GGMS field in GMCH
219829150b0SGordon Ross  * Graphics Control Register. Return aperture size in MB.
220829150b0SGordon Ross  */
221829150b0SGordon Ross static off_t
i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)222829150b0SGordon Ross i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)
223829150b0SGordon Ross {
224829150b0SGordon Ross 	uint16_t value;
225829150b0SGordon Ross 	off_t apersize;
226829150b0SGordon Ross 
227829150b0SGordon Ross 	/*
228829150b0SGordon Ross 	 * Get the value of configuration register MGGC "Mirror of Dev0 GMCH
229829150b0SGordon Ross 	 * Graphics Control" from Internal Graphics #2 (Device2:Function0).
230829150b0SGordon Ross 	 */
231829150b0SGordon Ross 	value = pci_config_get16(pci_acc_hdl, I8XX_CONF_GC);
232829150b0SGordon Ross 	AGPM_DEBUG((CE_NOTE, "i3XX_apersize: MGGC = 0x%x", value));
233829150b0SGordon Ross 	/* computing aperture size using the pre-allocated GTT size */
234829150b0SGordon Ross 	switch (value & IX33_GGMS_MASK) {
235829150b0SGordon Ross 	case IX33_GGMS_1M:
236829150b0SGordon Ross 		apersize = 1024;
237829150b0SGordon Ross 		break;
238829150b0SGordon Ross 	case IX33_GGMS_2M:
239829150b0SGordon Ross 		apersize = 2048;
240829150b0SGordon Ross 		break;
241829150b0SGordon Ross 	default:
242829150b0SGordon Ross 		apersize = 0;	/* no memory pre-allocated */
243829150b0SGordon Ross 		AGPM_DEBUG((CE_WARN,
244829150b0SGordon Ross 		    "i3XX_apersize: no memory allocated for GTT"));
245829150b0SGordon Ross 	}
246829150b0SGordon Ross 	AGPM_DEBUG((CE_NOTE, "i3xx_apersize: apersize = %ldM", apersize));
247829150b0SGordon Ross 	return (apersize);
248829150b0SGordon Ross }
249829150b0SGordon Ross 
250829150b0SGordon Ross #define	CHECK_STATUS(status)	\
251829150b0SGordon Ross     if (status != DDI_SUCCESS) { \
252829150b0SGordon Ross 	    AGPM_DEBUG((CE_WARN, \
253829150b0SGordon Ross 		"set_gtt_mmio: regs_map_setup error")); \
254829150b0SGordon Ross 	    return (-1); \
255829150b0SGordon Ross }
256829150b0SGordon Ross /*
257829150b0SGordon Ross  * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid
258829150b0SGordon Ross  * according to chipset.
259829150b0SGordon Ross  */
260829150b0SGordon Ross static int
set_gtt_mmio(dev_info_t * devi,agp_master_softc_t * agpmaster,ddi_acc_handle_t pci_acc_hdl)261829150b0SGordon Ross set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster,
262829150b0SGordon Ross     ddi_acc_handle_t pci_acc_hdl)
263829150b0SGordon Ross {
264829150b0SGordon Ross 	off_t apersize;  /* size of graphics mem (MB) == GTT size (KB) */
265829150b0SGordon Ross 	uint32_t value;
266829150b0SGordon Ross 	off_t gmadr_off;  /* GMADR offset in PCI config space */
267829150b0SGordon Ross 	int status;
268829150b0SGordon Ross 
269829150b0SGordon Ross 	if (IS_INTEL_X33(agpmaster->agpm_id)) {
270829150b0SGordon Ross 		/* Intel 3 series are similar with 915/945 series */
271829150b0SGordon Ross 		status = ddi_regs_map_setup(devi, I915_GTTADDR,
272829150b0SGordon Ross 		    &GTT_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
273829150b0SGordon Ross 		    &GTT_HANDLE(agpmaster));
274829150b0SGordon Ross 		CHECK_STATUS(status);
275829150b0SGordon Ross 
276829150b0SGordon Ross 		status = ddi_regs_map_setup(devi, I915_MMADR,
277829150b0SGordon Ross 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
278829150b0SGordon Ross 		    &MMIO_HANDLE(agpmaster));
279829150b0SGordon Ross 		CHECK_STATUS(status);
280829150b0SGordon Ross 
281829150b0SGordon Ross 		gmadr_off = I915_CONF_GMADR;
282829150b0SGordon Ross 		/* Different computing method used in getting aperture size. */
283829150b0SGordon Ross 		apersize = i3XX_apersize(pci_acc_hdl);
284829150b0SGordon Ross 	} else if (IS_INTEL_965(agpmaster->agpm_id)) {
285829150b0SGordon Ross 		status = ddi_regs_map_setup(devi, I965_GTTMMADR,
286829150b0SGordon Ross 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
287829150b0SGordon Ross 		    &MMIO_HANDLE(agpmaster));
288829150b0SGordon Ross 		CHECK_STATUS(status);
289829150b0SGordon Ross 		if ((agpmaster->agpm_id == INTEL_IGD_GM45) ||
290829150b0SGordon Ross 		    IS_INTEL_G4X(agpmaster->agpm_id))
291829150b0SGordon Ross 			GTT_ADDR(agpmaster) =
292829150b0SGordon Ross 			    MMIO_BASE(agpmaster) + GM45_GTT_OFFSET;
293829150b0SGordon Ross 		else
294829150b0SGordon Ross 			GTT_ADDR(agpmaster) =
295829150b0SGordon Ross 			    MMIO_BASE(agpmaster) + I965_GTT_OFFSET;
296829150b0SGordon Ross 		GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
297829150b0SGordon Ross 
298829150b0SGordon Ross 		gmadr_off = I915_CONF_GMADR;
299829150b0SGordon Ross 		apersize = i965_apersize(agpmaster);
300829150b0SGordon Ross 	} else if (IS_INTEL_915(agpmaster->agpm_id)) {
301829150b0SGordon Ross 		/* I915/945 series */
302829150b0SGordon Ross 		status = ddi_regs_map_setup(devi, I915_GTTADDR,
303829150b0SGordon Ross 		    &GTT_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
304829150b0SGordon Ross 		    &GTT_HANDLE(agpmaster));
305829150b0SGordon Ross 		CHECK_STATUS(status);
306829150b0SGordon Ross 
307829150b0SGordon Ross 		status = ddi_regs_map_setup(devi, I915_MMADR,
308829150b0SGordon Ross 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
309829150b0SGordon Ross 		    &MMIO_HANDLE(agpmaster));
310829150b0SGordon Ross 		CHECK_STATUS(status);
311829150b0SGordon Ross 
312829150b0SGordon Ross 		gmadr_off = I915_CONF_GMADR;
313829150b0SGordon Ross 		status = ddi_dev_regsize(devi, I915_GMADR, &apersize);
314829150b0SGordon Ross 		apersize = BYTES2MB(apersize);
315829150b0SGordon Ross 	} else {
316829150b0SGordon Ross 		/* I8XX series */
317829150b0SGordon Ross 		status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR,
318829150b0SGordon Ross 		    &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
319829150b0SGordon Ross 		    &MMIO_HANDLE(agpmaster));
320829150b0SGordon Ross 		CHECK_STATUS(status);
321829150b0SGordon Ross 
322829150b0SGordon Ross 		GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET;
323829150b0SGordon Ross 		GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
324829150b0SGordon Ross 		gmadr_off = I8XX_CONF_GMADR;
325829150b0SGordon Ross 		status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize);
326829150b0SGordon Ross 		apersize = BYTES2MB(apersize);
327829150b0SGordon Ross 		CHECK_STATUS(status);
328829150b0SGordon Ross 	}
329829150b0SGordon Ross 
330829150b0SGordon Ross 	/*
331829150b0SGordon Ross 	 * If memory size is smaller than a certain value, it means
332829150b0SGordon Ross 	 * the register set number for graphics memory range might
333829150b0SGordon Ross 	 * be wrong
334829150b0SGordon Ross 	 */
335829150b0SGordon Ross 	if (status != DDI_SUCCESS || apersize < 4) {
336829150b0SGordon Ross 		AGPM_DEBUG((CE_WARN,
337829150b0SGordon Ross 		    "set_gtt_mmio: error in getting graphics memory"));
338829150b0SGordon Ross 		return (-1);
339829150b0SGordon Ross 	}
340829150b0SGordon Ross 
341829150b0SGordon Ross 	agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = apersize;
342829150b0SGordon Ross 
343829150b0SGordon Ross 	/* get graphics memory base address from GMADR */
344829150b0SGordon Ross 	value = pci_config_get32(pci_acc_hdl, gmadr_off);
345829150b0SGordon Ross 	APER_BASE(agpmaster) = value & GTT_BASE_MASK;
346829150b0SGordon Ross 	AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = 0x%x, apersize = %ldM, "
347829150b0SGordon Ross 	    "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize,
348829150b0SGordon Ross 	    (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster)));
349829150b0SGordon Ross 	return (0);
350829150b0SGordon Ross }
351829150b0SGordon Ross 
352829150b0SGordon Ross /*
353829150b0SGordon Ross  * Try to initialize agp master.
354829150b0SGordon Ross  * 0 is returned if the device is successfully initialized. AGP master soft
355829150b0SGordon Ross  * state is returned in master_softcp if needed.
356829150b0SGordon Ross  * Otherwise -1 is returned and *master_softcp is set to NULL.
357829150b0SGordon Ross  */
358829150b0SGordon Ross int
agpmaster_attach(dev_info_t * devi,agp_master_softc_t ** master_softcp,ddi_acc_handle_t pci_acc_hdl,minor_t minor)359829150b0SGordon Ross agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp,
360829150b0SGordon Ross     ddi_acc_handle_t pci_acc_hdl, minor_t minor)
361829150b0SGordon Ross {
362829150b0SGordon Ross 	int instance;
363829150b0SGordon Ross 	int status;
364829150b0SGordon Ross 	agp_master_softc_t *agpmaster;
365829150b0SGordon Ross 	char buf[80];
366829150b0SGordon Ross 
367829150b0SGordon Ross 
368829150b0SGordon Ross 	ASSERT(pci_acc_hdl);
369829150b0SGordon Ross 	*master_softcp = NULL;
370829150b0SGordon Ross 	agpmaster = (agp_master_softc_t *)
371829150b0SGordon Ross 	    kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP);
372829150b0SGordon Ross 
373829150b0SGordon Ross 	agpmaster->agpm_id =
374829150b0SGordon Ross 	    pci_config_get32(pci_acc_hdl, PCI_CONF_VENID);
375829150b0SGordon Ross 	agpmaster->agpm_acc_hdl = pci_acc_hdl;
376829150b0SGordon Ross 
377829150b0SGordon Ross 	if (!detect_i8xx_device(agpmaster)) {
378829150b0SGordon Ross 		/* Intel 8XX, 915, 945 and 965 series */
379829150b0SGordon Ross 		if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0)
380829150b0SGordon Ross 			goto fail;
381829150b0SGordon Ross 	} else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) {
382829150b0SGordon Ross 		/* non IGD or AGP devices, AMD64 gart */
383829150b0SGordon Ross 		AGPM_DEBUG((CE_WARN,
384829150b0SGordon Ross 		    "agpmaster_attach: neither IGD or AGP devices exists"));
385829150b0SGordon Ross 		agpmaster_detach(&agpmaster);
386829150b0SGordon Ross 		return (0);
387829150b0SGordon Ross 	}
388829150b0SGordon Ross 
389829150b0SGordon Ross 	agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid =
390829150b0SGordon Ross 	    agpmaster->agpm_id;
391829150b0SGordon Ross 
392829150b0SGordon Ross 	/* create minor node for IGD or AGP device */
393829150b0SGordon Ross 	instance = ddi_get_instance(devi);
394829150b0SGordon Ross 
395829150b0SGordon Ross 	(void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance);
396829150b0SGordon Ross 	status = ddi_create_minor_node(devi, buf, S_IFCHR, minor,
397829150b0SGordon Ross 	    DDI_NT_AGP_MASTER, 0);
398829150b0SGordon Ross 
399829150b0SGordon Ross 	if (status != DDI_SUCCESS) {
400829150b0SGordon Ross 		AGPM_DEBUG((CE_WARN,
401829150b0SGordon Ross 		    "agpmaster_attach: create agpmaster node failed"));
402829150b0SGordon Ross 		goto fail;
403829150b0SGordon Ross 	}
404829150b0SGordon Ross 
405829150b0SGordon Ross 	*master_softcp = agpmaster;
406829150b0SGordon Ross 	return (0);
407829150b0SGordon Ross fail:
408829150b0SGordon Ross 	agpmaster_detach(&agpmaster);
409829150b0SGordon Ross 	return (-1);
410829150b0SGordon Ross }
411829150b0SGordon Ross 
412829150b0SGordon Ross /*
413829150b0SGordon Ross  * Currently, it handles ioctl requests related with agp master device for
414829150b0SGordon Ross  * layered driver (agpgart) only.
415829150b0SGordon Ross  */
416829150b0SGordon Ross /*ARGSUSED*/
417829150b0SGordon Ross int
agpmaster_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval,agp_master_softc_t * softc)418829150b0SGordon Ross agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred,
419829150b0SGordon Ross     int *rval, agp_master_softc_t *softc)
420829150b0SGordon Ross {
421829150b0SGordon Ross 	uint32_t base;
422829150b0SGordon Ross 	uint32_t addr;
423829150b0SGordon Ross 	igd_gtt_seg_t seg;
424829150b0SGordon Ross 	agp_info_t info;
425829150b0SGordon Ross 	uint32_t value;
426829150b0SGordon Ross 	off_t cap;
427829150b0SGordon Ross 	uint32_t command;
428829150b0SGordon Ross 	static char kernel_only[] =
429829150b0SGordon Ross 	    "agpmaster_ioctl: %s is a kernel only ioctl";
430829150b0SGordon Ross 
431829150b0SGordon Ross 	CONFIRM(softc);
432829150b0SGordon Ross 
433829150b0SGordon Ross 	switch (cmd) {
434829150b0SGordon Ross 	case DEVICE_DETECT:
435829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
436829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT"));
437829150b0SGordon Ross 			return (ENXIO);
438829150b0SGordon Ross 		}
439829150b0SGordon Ross 
440829150b0SGordon Ross 		if (ddi_copyout(&softc->agpm_dev_type,
441829150b0SGordon Ross 		    (void *)data, sizeof (int), mode))
442829150b0SGordon Ross 			return (EFAULT);
443829150b0SGordon Ross 		break;
444*3db4bae9SGordon Ross 
445829150b0SGordon Ross 	case AGP_MASTER_SETCMD:
446829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
447829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD"));
448829150b0SGordon Ross 			return (ENXIO);
449829150b0SGordon Ross 		}
450829150b0SGordon Ross 
451829150b0SGordon Ross 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
452829150b0SGordon Ross 		CONFIRM(softc->agpm_data.agpm_acaptr);
453829150b0SGordon Ross 
454829150b0SGordon Ross 		if (ddi_copyin((void *)data, &command,
455829150b0SGordon Ross 		    sizeof (uint32_t), mode))
456829150b0SGordon Ross 			return (EFAULT);
457829150b0SGordon Ross 
458829150b0SGordon Ross 		pci_config_put32(softc->agpm_acc_hdl,
459829150b0SGordon Ross 		    softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND,
460829150b0SGordon Ross 		    command);
461829150b0SGordon Ross 		break;
462*3db4bae9SGordon Ross 
463829150b0SGordon Ross 	case AGP_MASTER_GETINFO:
464829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
465829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only,
466829150b0SGordon Ross 			    "AGP_MASTER_GETINFO"));
467829150b0SGordon Ross 			return (ENXIO);
468829150b0SGordon Ross 		}
469829150b0SGordon Ross 
470829150b0SGordon Ross 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
471829150b0SGordon Ross 		CONFIRM(softc->agpm_data.agpm_acaptr);
472829150b0SGordon Ross 
473829150b0SGordon Ross 		cap = softc->agpm_data.agpm_acaptr;
474829150b0SGordon Ross 		value = pci_config_get32(softc->agpm_acc_hdl, cap);
475829150b0SGordon Ross 		info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf);
476829150b0SGordon Ross 		info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf);
477829150b0SGordon Ross 		info.agpi_devid = softc->agpm_id;
478829150b0SGordon Ross 		info.agpi_mode = pci_config_get32(
479829150b0SGordon Ross 		    softc->agpm_acc_hdl, cap + AGP_CONF_STATUS);
480829150b0SGordon Ross 
481829150b0SGordon Ross 		if (ddi_copyout(&info, (void *)data,
482829150b0SGordon Ross 		    sizeof (agp_info_t), mode))
483829150b0SGordon Ross 			return (EFAULT);
484829150b0SGordon Ross 		break;
485*3db4bae9SGordon Ross 
486829150b0SGordon Ross 	case I810_SET_GTT_BASE:
487829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
488829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR"));
489829150b0SGordon Ross 			return (ENXIO);
490829150b0SGordon Ross 		}
491829150b0SGordon Ross 
492829150b0SGordon Ross 		CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810);
493829150b0SGordon Ross 
494829150b0SGordon Ross 		if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode))
495829150b0SGordon Ross 			return (EFAULT);
496829150b0SGordon Ross 
497829150b0SGordon Ross 		/* enables page table */
498829150b0SGordon Ross 		addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID;
499829150b0SGordon Ross 
500829150b0SGordon Ross 		AGPM_WRITE(softc, PGTBL_CTL, addr);
501829150b0SGordon Ross 		break;
502*3db4bae9SGordon Ross 
503829150b0SGordon Ross 	case I8XX_GET_INFO:
504829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
505829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO"));
506829150b0SGordon Ross 			return (ENXIO);
507829150b0SGordon Ross 		}
508829150b0SGordon Ross 
509829150b0SGordon Ross 		CONFIRM(IS_IGD(softc));
510829150b0SGordon Ross 
511829150b0SGordon Ross 		if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info,
512829150b0SGordon Ross 		    (void *)data, sizeof (igd_info_t), mode))
513829150b0SGordon Ross 			return (EFAULT);
514829150b0SGordon Ross 		break;
515*3db4bae9SGordon Ross 
516829150b0SGordon Ross 	case I8XX_ADD2GTT:
517829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
518829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT"));
519829150b0SGordon Ross 			return (ENXIO);
520829150b0SGordon Ross 		}
521829150b0SGordon Ross 
522829150b0SGordon Ross 		CONFIRM(IS_IGD(softc));
523829150b0SGordon Ross 
524829150b0SGordon Ross 		if (ddi_copyin((void *)data, &seg,
525829150b0SGordon Ross 		    sizeof (igd_gtt_seg_t), mode))
526829150b0SGordon Ross 			return (EFAULT);
527829150b0SGordon Ross 
528829150b0SGordon Ross 		if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg))
529829150b0SGordon Ross 			return (EINVAL);
530829150b0SGordon Ross 		break;
531*3db4bae9SGordon Ross 
532829150b0SGordon Ross 	case I8XX_REM_GTT:
533829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
534829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT"));
535829150b0SGordon Ross 			return (ENXIO);
536829150b0SGordon Ross 		}
537829150b0SGordon Ross 
538829150b0SGordon Ross 		CONFIRM(IS_IGD(softc));
539829150b0SGordon Ross 
540829150b0SGordon Ross 		if (ddi_copyin((void *)data, &seg,
541829150b0SGordon Ross 		    sizeof (igd_gtt_seg_t), mode))
542829150b0SGordon Ross 			return (EFAULT);
543829150b0SGordon Ross 
544829150b0SGordon Ross 		i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg);
545829150b0SGordon Ross 		break;
546*3db4bae9SGordon Ross 
547*3db4bae9SGordon Ross 	case I8XX_RW_GTT:
548*3db4bae9SGordon Ross 		if (!(mode & FKIOCTL)) {
549*3db4bae9SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_RW_GTT"));
550*3db4bae9SGordon Ross 			return (ENXIO);
551*3db4bae9SGordon Ross 		}
552*3db4bae9SGordon Ross 
553*3db4bae9SGordon Ross 		CONFIRM(IS_IGD(softc));
554*3db4bae9SGordon Ross 
555*3db4bae9SGordon Ross 		if (ddi_copyin((void *)data, &seg,
556*3db4bae9SGordon Ross 		    sizeof (igd_gtt_seg_t), mode))
557*3db4bae9SGordon Ross 			return (EFAULT);
558*3db4bae9SGordon Ross 
559*3db4bae9SGordon Ross 		/*
560*3db4bae9SGordon Ross 		 * Read or write based on flags set in
561*3db4bae9SGordon Ross 		 * ioctl_agpgart_rw_gtt()
562*3db4bae9SGordon Ross 		 * Used to save/restore GTT state.
563*3db4bae9SGordon Ross 		 */
564*3db4bae9SGordon Ross 		if (seg.igs_flags == 0) {
565*3db4bae9SGordon Ross 			if (i8xx_read_gtt(&softc->agpm_data.agpm_gtt, seg))
566*3db4bae9SGordon Ross 				return (EINVAL);
567*3db4bae9SGordon Ross 		} else {
568*3db4bae9SGordon Ross 			if (i8xx_write_gtt(&softc->agpm_data.agpm_gtt, seg))
569*3db4bae9SGordon Ross 				return (EINVAL);
570*3db4bae9SGordon Ross 		}
571*3db4bae9SGordon Ross 		break;
572*3db4bae9SGordon Ross 
573829150b0SGordon Ross 	case I8XX_UNCONFIG:
574829150b0SGordon Ross 		if (!(mode & FKIOCTL)) {
575829150b0SGordon Ross 			AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG"));
576829150b0SGordon Ross 			return (ENXIO);
577829150b0SGordon Ross 		}
578829150b0SGordon Ross 
579829150b0SGordon Ross 		CONFIRM(IS_IGD(softc));
580829150b0SGordon Ross 
581829150b0SGordon Ross 		if (softc->agpm_dev_type == DEVICE_IS_I810)
582829150b0SGordon Ross 			AGPM_WRITE(softc, PGTBL_CTL, 0);
583829150b0SGordon Ross 		/*
584829150b0SGordon Ross 		 * may need to clear all gtt entries here for i830 series,
585829150b0SGordon Ross 		 * but may not be necessary
586829150b0SGordon Ross 		 */
587829150b0SGordon Ross 		break;
588829150b0SGordon Ross 	}
589829150b0SGordon Ross 	return (0);
590829150b0SGordon Ross }
591829150b0SGordon Ross 
592829150b0SGordon Ross /*
593829150b0SGordon Ross  * If AGP cap pointer is successfully found, none-zero value is returned.
594829150b0SGordon Ross  * Otherwise 0 is returned.
595829150b0SGordon Ross  */
596829150b0SGordon Ross static off_t
agpmaster_cap_find(ddi_acc_handle_t acc_handle)597829150b0SGordon Ross agpmaster_cap_find(ddi_acc_handle_t acc_handle)
598829150b0SGordon Ross {
599829150b0SGordon Ross 	off_t		nextcap;
600829150b0SGordon Ross 	uint32_t	ncapid;
601829150b0SGordon Ross 	uint8_t		value;
602829150b0SGordon Ross 
603829150b0SGordon Ross 	/* check if this device supports capibility pointer */
604829150b0SGordon Ross 	value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT)
605829150b0SGordon Ross 	    & PCI_CONF_CAP_MASK);
606829150b0SGordon Ross 
607829150b0SGordon Ross 	if (!value)
608829150b0SGordon Ross 		return (0);
609829150b0SGordon Ross 	/* get the offset of the first capability pointer from CAPPTR */
610829150b0SGordon Ross 	nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR));
611829150b0SGordon Ross 
612829150b0SGordon Ross 	/* check AGP capability from the first capability pointer */
613829150b0SGordon Ross 	while (nextcap) {
614829150b0SGordon Ross 		ncapid = pci_config_get32(acc_handle, nextcap);
615829150b0SGordon Ross 		if ((ncapid & PCI_CONF_CAPID_MASK)
616829150b0SGordon Ross 		    == AGP_CAP_ID) /* find AGP cap */
617829150b0SGordon Ross 			break;
618829150b0SGordon Ross 
619829150b0SGordon Ross 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
620829150b0SGordon Ross 	}
621829150b0SGordon Ross 
622829150b0SGordon Ross 	return (nextcap);
623829150b0SGordon Ross 
624829150b0SGordon Ross }
625829150b0SGordon Ross 
626829150b0SGordon Ross /*
627829150b0SGordon Ross  * If i8xx device is successfully detected, 0 is returned.
628829150b0SGordon Ross  * Otherwise -1 is returned.
629829150b0SGordon Ross  */
630829150b0SGordon Ross static int
detect_i8xx_device(agp_master_softc_t * master_softc)631829150b0SGordon Ross detect_i8xx_device(agp_master_softc_t *master_softc)
632829150b0SGordon Ross {
633829150b0SGordon Ross 
634829150b0SGordon Ross 	switch (master_softc->agpm_id) {
635829150b0SGordon Ross 	case INTEL_IGD_810:
636829150b0SGordon Ross 	case INTEL_IGD_810DC:
637829150b0SGordon Ross 	case INTEL_IGD_810E:
638829150b0SGordon Ross 	case INTEL_IGD_815:
639829150b0SGordon Ross 		master_softc->agpm_dev_type = DEVICE_IS_I810;
640829150b0SGordon Ross 		break;
641829150b0SGordon Ross 	case INTEL_IGD_830M:
642829150b0SGordon Ross 	case INTEL_IGD_845G:
643829150b0SGordon Ross 	case INTEL_IGD_855GM:
644829150b0SGordon Ross 	case INTEL_IGD_865G:
645829150b0SGordon Ross 	case INTEL_IGD_915:
646829150b0SGordon Ross 	case INTEL_IGD_915GM:
647829150b0SGordon Ross 	case INTEL_IGD_945:
648829150b0SGordon Ross 	case INTEL_IGD_945GM:
649829150b0SGordon Ross 	case INTEL_IGD_945GME:
650829150b0SGordon Ross 	case INTEL_IGD_946GZ:
651829150b0SGordon Ross 	case INTEL_IGD_965G1:
652829150b0SGordon Ross 	case INTEL_IGD_965G2:
653829150b0SGordon Ross 	case INTEL_IGD_965GM:
654829150b0SGordon Ross 	case INTEL_IGD_965GME:
655829150b0SGordon Ross 	case INTEL_IGD_965Q:
656829150b0SGordon Ross 	case INTEL_IGD_Q35:
657829150b0SGordon Ross 	case INTEL_IGD_G33:
658829150b0SGordon Ross 	case INTEL_IGD_Q33:
659829150b0SGordon Ross 	case INTEL_IGD_GM45:
660829150b0SGordon Ross 	case INTEL_IGD_EL:
661829150b0SGordon Ross 	case INTEL_IGD_Q45:
662829150b0SGordon Ross 	case INTEL_IGD_G45:
663829150b0SGordon Ross 	case INTEL_IGD_G41:
664829150b0SGordon Ross 	case INTEL_IGD_IGDNG_D:
665829150b0SGordon Ross 	case INTEL_IGD_IGDNG_M:
666829150b0SGordon Ross 	case INTEL_IGD_B43:
667*3db4bae9SGordon Ross 		/*
668*3db4bae9SGordon Ross 		 * Note: This module is not used for Intel Gen6 or later
669*3db4bae9SGordon Ross 		 * devices (Sandy Bridge etc.) so no need to add any
670*3db4bae9SGordon Ross 		 * PCI IDs here for those devices.
671*3db4bae9SGordon Ross 		 */
672829150b0SGordon Ross 		master_softc->agpm_dev_type = DEVICE_IS_I830;
673829150b0SGordon Ross 		break;
674829150b0SGordon Ross 	default:		/* unknown id */
675*3db4bae9SGordon Ross 		AGPM_DEBUG((CE_CONT, "unknown i8xx_device 0x%x",
676*3db4bae9SGordon Ross 		    master_softc->agpm_id));
677829150b0SGordon Ross 		return (-1);
678829150b0SGordon Ross 	}
679829150b0SGordon Ross 
680829150b0SGordon Ross 	return (0);
681829150b0SGordon Ross }
682829150b0SGordon Ross 
683829150b0SGordon Ross /*
684829150b0SGordon Ross  * If agp master is successfully detected, 0 is returned.
685829150b0SGordon Ross  * Otherwise -1 is returned.
686829150b0SGordon Ross  */
687829150b0SGordon Ross static int
detect_agp_devcice(agp_master_softc_t * master_softc,ddi_acc_handle_t acc_handle)688829150b0SGordon Ross detect_agp_devcice(agp_master_softc_t *master_softc,
689829150b0SGordon Ross     ddi_acc_handle_t acc_handle)
690829150b0SGordon Ross {
691829150b0SGordon Ross 	off_t cap;
692829150b0SGordon Ross 
693829150b0SGordon Ross 	cap = agpmaster_cap_find(acc_handle);
694829150b0SGordon Ross 	if (cap) {
695829150b0SGordon Ross 		master_softc->agpm_dev_type = DEVICE_IS_AGP;
696829150b0SGordon Ross 		master_softc->agpm_data.agpm_acaptr = cap;
697829150b0SGordon Ross 		return (0);
698829150b0SGordon Ross 	} else {
699829150b0SGordon Ross 		return (-1);
700829150b0SGordon Ross 	}
701829150b0SGordon Ross 
702829150b0SGordon Ross }
703829150b0SGordon Ross 
704829150b0SGordon Ross /*
705829150b0SGordon Ross  * Please refer to GART and GTT entry format table in agpdefs.h for
706829150b0SGordon Ross  * intel GTT entry format.
707829150b0SGordon Ross  */
708829150b0SGordon Ross static int
phys2entry(uint32_t type,uint32_t physaddr,uint32_t * entry)709829150b0SGordon Ross phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry)
710829150b0SGordon Ross {
711829150b0SGordon Ross 	uint32_t value;
712829150b0SGordon Ross 
713829150b0SGordon Ross 	switch (type) {
714829150b0SGordon Ross 	case AGP_PHYSICAL:
715829150b0SGordon Ross 	case AGP_NORMAL:
716829150b0SGordon Ross 		value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID;
717829150b0SGordon Ross 		break;
718829150b0SGordon Ross 	default:
719*3db4bae9SGordon Ross 		AGPM_DEBUG((CE_WARN, "phys2entry type %d", type));
720829150b0SGordon Ross 		return (-1);
721829150b0SGordon Ross 	}
722829150b0SGordon Ross 
723829150b0SGordon Ross 	*entry = value;
724829150b0SGordon Ross 
725829150b0SGordon Ross 	return (0);
726829150b0SGordon Ross }
727829150b0SGordon Ross 
728829150b0SGordon Ross static int
i8xx_add_to_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)729829150b0SGordon Ross i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
730829150b0SGordon Ross {
731829150b0SGordon Ross 	int i;
732829150b0SGordon Ross 	uint32_t *paddr;
733829150b0SGordon Ross 	uint32_t entry;
734829150b0SGordon Ross 	uint32_t maxpages;
735829150b0SGordon Ross 
736829150b0SGordon Ross 	maxpages = gtt->gtt_info.igd_apersize;
737829150b0SGordon Ross 	maxpages = GTT_MB_TO_PAGES(maxpages);
738829150b0SGordon Ross 
739829150b0SGordon Ross 	/* check if gtt max page number is reached */
740829150b0SGordon Ross 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
741829150b0SGordon Ross 		return (-1);
742829150b0SGordon Ross 
743*3db4bae9SGordon Ross 	/*
744*3db4bae9SGordon Ross 	 * Note: Caller supplies a gtt address from which we
745*3db4bae9SGordon Ross 	 * extract a uint32_t gtt_pte_t to set in the GTT.
746*3db4bae9SGordon Ross 	 */
747829150b0SGordon Ross 	paddr = seg.igs_phyaddr;
748829150b0SGordon Ross 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
749829150b0SGordon Ross 	    i++, paddr++) {
750829150b0SGordon Ross 		if (phys2entry(seg.igs_type, *paddr, &entry))
751829150b0SGordon Ross 			return (-1);
752829150b0SGordon Ross 		ddi_put32(gtt->gtt_handle,
753829150b0SGordon Ross 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
754829150b0SGordon Ross 		    entry);
755829150b0SGordon Ross 	}
756829150b0SGordon Ross 
757829150b0SGordon Ross 	return (0);
758829150b0SGordon Ross }
759829150b0SGordon Ross 
760829150b0SGordon Ross static void
i8xx_remove_from_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)761829150b0SGordon Ross i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
762829150b0SGordon Ross {
763829150b0SGordon Ross 	int i;
764829150b0SGordon Ross 	uint32_t maxpages;
765*3db4bae9SGordon Ross 	uint32_t entry;
766829150b0SGordon Ross 
767829150b0SGordon Ross 	maxpages = gtt->gtt_info.igd_apersize;
768829150b0SGordon Ross 	maxpages = GTT_MB_TO_PAGES(maxpages);
769829150b0SGordon Ross 
770*3db4bae9SGordon Ross 	/*
771*3db4bae9SGordon Ross 	 * If non-zero, seg.igs_scratch is the pfn_t for a
772*3db4bae9SGordon Ross 	 * "scratch" page to use instead of zero.
773*3db4bae9SGordon Ross 	 */
774*3db4bae9SGordon Ross 	if (seg.igs_scratch == 0 ||
775*3db4bae9SGordon Ross 	    phys2entry(seg.igs_type, seg.igs_scratch, &entry) != 0) {
776*3db4bae9SGordon Ross 		entry = 0;
777*3db4bae9SGordon Ross 	}
778*3db4bae9SGordon Ross 
779829150b0SGordon Ross 	/* check if gtt max page number is reached */
780829150b0SGordon Ross 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
781829150b0SGordon Ross 		return;
782829150b0SGordon Ross 
783829150b0SGordon Ross 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) {
784829150b0SGordon Ross 		ddi_put32(gtt->gtt_handle,
785*3db4bae9SGordon Ross 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
786*3db4bae9SGordon Ross 		    entry);
787829150b0SGordon Ross 	}
788829150b0SGordon Ross }
789*3db4bae9SGordon Ross 
790*3db4bae9SGordon Ross /*
791*3db4bae9SGordon Ross  * Low-level read GTT
792*3db4bae9SGordon Ross  */
793*3db4bae9SGordon Ross static int
i8xx_read_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)794*3db4bae9SGordon Ross i8xx_read_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
795*3db4bae9SGordon Ross {
796*3db4bae9SGordon Ross 	int i;
797*3db4bae9SGordon Ross 	uint32_t *paddr;
798*3db4bae9SGordon Ross 	uint32_t maxpages;
799*3db4bae9SGordon Ross 
800*3db4bae9SGordon Ross 	maxpages = gtt->gtt_info.igd_apersize;
801*3db4bae9SGordon Ross 	maxpages = GTT_MB_TO_PAGES(maxpages);
802*3db4bae9SGordon Ross 
803*3db4bae9SGordon Ross 	/* Buffer into which we'll read. */
804*3db4bae9SGordon Ross 	paddr = seg.igs_phyaddr;
805*3db4bae9SGordon Ross 	if (paddr == NULL)
806*3db4bae9SGordon Ross 		return (-1);
807*3db4bae9SGordon Ross 
808*3db4bae9SGordon Ross 	/* check if gtt max page number is reached */
809*3db4bae9SGordon Ross 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
810*3db4bae9SGordon Ross 		return (-1);
811*3db4bae9SGordon Ross 
812*3db4bae9SGordon Ross 	paddr = seg.igs_phyaddr;
813*3db4bae9SGordon Ross 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
814*3db4bae9SGordon Ross 	    i++, paddr++) {
815*3db4bae9SGordon Ross 		*paddr = ddi_get32(gtt->gtt_handle,
816*3db4bae9SGordon Ross 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)));
817*3db4bae9SGordon Ross 	}
818*3db4bae9SGordon Ross 
819*3db4bae9SGordon Ross 	return (0);
820*3db4bae9SGordon Ross }
821*3db4bae9SGordon Ross 
822*3db4bae9SGordon Ross /*
823*3db4bae9SGordon Ross  * Low-level write GTT
824*3db4bae9SGordon Ross  */
825*3db4bae9SGordon Ross static int
i8xx_write_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)826*3db4bae9SGordon Ross i8xx_write_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
827*3db4bae9SGordon Ross {
828*3db4bae9SGordon Ross 	int i;
829*3db4bae9SGordon Ross 	uint32_t *paddr;
830*3db4bae9SGordon Ross 	uint32_t maxpages;
831*3db4bae9SGordon Ross 
832*3db4bae9SGordon Ross 	maxpages = gtt->gtt_info.igd_apersize;
833*3db4bae9SGordon Ross 	maxpages = GTT_MB_TO_PAGES(maxpages);
834*3db4bae9SGordon Ross 
835*3db4bae9SGordon Ross 	/* Buffer from which we'll write. */
836*3db4bae9SGordon Ross 	paddr = seg.igs_phyaddr;
837*3db4bae9SGordon Ross 	if (paddr == NULL)
838*3db4bae9SGordon Ross 		return (-1);
839*3db4bae9SGordon Ross 
840*3db4bae9SGordon Ross 	/* check if gtt max page number is reached */
841*3db4bae9SGordon Ross 	if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
842*3db4bae9SGordon Ross 		return (-1);
843*3db4bae9SGordon Ross 
844*3db4bae9SGordon Ross 	paddr = seg.igs_phyaddr;
845*3db4bae9SGordon Ross 	for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
846*3db4bae9SGordon Ross 	    i++, paddr++) {
847*3db4bae9SGordon Ross 		ddi_put32(gtt->gtt_handle,
848*3db4bae9SGordon Ross 		    (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
849*3db4bae9SGordon Ross 		    *paddr);
850*3db4bae9SGordon Ross 	}
851*3db4bae9SGordon Ross 
852*3db4bae9SGordon Ross 	return (0);
853*3db4bae9SGordon Ross }
854