1ae115bc7Smrj /*
2ae115bc7Smrj * CDDL HEADER START
3ae115bc7Smrj *
4ae115bc7Smrj * The contents of this file are subject to the terms of the
5ae115bc7Smrj * Common Development and Distribution License (the "License").
6ae115bc7Smrj * You may not use this file except in compliance with the License.
7ae115bc7Smrj *
8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj * See the License for the specific language governing permissions
11ae115bc7Smrj * and limitations under the License.
12ae115bc7Smrj *
13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj *
19ae115bc7Smrj * CDDL HEADER END
20ae115bc7Smrj */
21ae115bc7Smrj
22ae115bc7Smrj /*
230035d21cSmiao chen - Sun Microsystems - Beijing China * Copyright (c) 2009, Intel Corporation.
240035d21cSmiao chen - Sun Microsystems - Beijing China * All Rights Reserved.
250035d21cSmiao chen - Sun Microsystems - Beijing China */
260035d21cSmiao chen - Sun Microsystems - Beijing China
270035d21cSmiao chen - Sun Microsystems - Beijing China /*
28d0231070Smiao chen - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
29ae115bc7Smrj * Use is subject to license terms.
30ae115bc7Smrj */
31ae115bc7Smrj
32ae115bc7Smrj /*
33ae115bc7Smrj * Misc module for AGP master device support
34ae115bc7Smrj */
35ae115bc7Smrj
36ae115bc7Smrj #include <sys/modctl.h>
37ae115bc7Smrj #include <sys/pci.h>
38ae115bc7Smrj #include <sys/stat.h>
39ae115bc7Smrj #include <sys/file.h>
40ae115bc7Smrj #include <sys/types.h>
41ae115bc7Smrj #include <sys/dditypes.h>
42ae115bc7Smrj #include <sys/sunddi.h>
43ae115bc7Smrj #include <sys/agpgart.h>
44ae115bc7Smrj #include <sys/agp/agpdefs.h>
45ae115bc7Smrj #include <sys/agp/agpmaster_io.h>
46ae115bc7Smrj
47543414e0Skz151634 #define PGTBL_CTL 0x2020 /* Page table control register */
48543414e0Skz151634 #define I8XX_FB_BAR 1
49543414e0Skz151634 #define I8XX_MMIO_BAR 2
50ae115bc7Smrj #define I8XX_PTE_OFFSET 0x10000
51543414e0Skz151634 #define I915_MMADR 1 /* mem-mapped registers BAR */
52543414e0Skz151634 #define I915_GMADR 3 /* graphics mem BAR */
53543414e0Skz151634 #define I915_GTTADDR 4 /* GTT BAR */
54543414e0Skz151634 #define I965_GTTMMADR 1 /* mem-mapped registers BAR + GTT */
55543414e0Skz151634 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */
56543414e0Skz151634 #define I965_GTT_OFFSET 0x80000
57219cee99Smc196098 #define GM45_GTT_OFFSET 0x200000
58543414e0Skz151634 #define GTT_SIZE_MASK 0xe
59543414e0Skz151634 #define GTT_512KB (0 << 1)
60543414e0Skz151634 #define GTT_256KB (1 << 1)
61543414e0Skz151634 #define GTT_128KB (2 << 1)
62219cee99Smc196098 #define GTT_1MB (3 << 1)
63219cee99Smc196098 #define GTT_2MB (4 << 1)
64219cee99Smc196098 #define GTT_1_5MB (5 << 1)
65543414e0Skz151634
66543414e0Skz151634 #define MMIO_BASE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_base
67543414e0Skz151634 #define MMIO_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_handle
68c4f91784Skz151634 #define GTT_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_handle
69c4f91784Skz151634 /* Base address of GTT */
70543414e0Skz151634 #define GTT_ADDR(x) (x)->agpm_data.agpm_gtt.gtt_addr
71c4f91784Skz151634 /* Graphics memory base address */
72543414e0Skz151634 #define APER_BASE(x) (x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase
73543414e0Skz151634
74543414e0Skz151634 #define AGPM_WRITE(x, off, val) \
75543414e0Skz151634 ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val));
76543414e0Skz151634
77543414e0Skz151634 #define AGPM_READ(x, off) \
78543414e0Skz151634 ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)));
79ae115bc7Smrj
80ae115bc7Smrj #ifdef DEBUG
81ae115bc7Smrj #define CONFIRM(value) ASSERT(value)
82ae115bc7Smrj #else
83ae115bc7Smrj #define CONFIRM(value) if (!(value)) return (EINVAL)
84ae115bc7Smrj #endif
85ae115bc7Smrj
86ae115bc7Smrj int agpm_debug = 0;
87ae115bc7Smrj #define AGPM_DEBUG(args) if (agpm_debug >= 1) cmn_err args
88ae115bc7Smrj
89ae115bc7Smrj /*
90ae115bc7Smrj * Whether it is a Intel integrated graphics card
91ae115bc7Smrj */
92ae115bc7Smrj #define IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \
93ae115bc7Smrj (agpmaster->agpm_dev_type == DEVICE_IS_I830))
94ae115bc7Smrj
95ae115bc7Smrj static struct modlmisc modlmisc = {
96613b2871SRichard Bean &mod_miscops, "AGP master interfaces"
97ae115bc7Smrj };
98ae115bc7Smrj
99ae115bc7Smrj static struct modlinkage modlinkage = {
100ae115bc7Smrj MODREV_1, (void *)&modlmisc, NULL
101ae115bc7Smrj };
102ae115bc7Smrj
103ae115bc7Smrj static ddi_device_acc_attr_t i8xx_dev_access = {
104ae115bc7Smrj DDI_DEVICE_ATTR_V0,
105ae115bc7Smrj DDI_NEVERSWAP_ACC,
106ae115bc7Smrj DDI_STRICTORDER_ACC
107ae115bc7Smrj };
108ae115bc7Smrj
109ae115bc7Smrj static off_t agpmaster_cap_find(ddi_acc_handle_t);
110ae115bc7Smrj static int detect_i8xx_device(agp_master_softc_t *);
111ae115bc7Smrj static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t);
112ae115bc7Smrj static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t);
113ae115bc7Smrj static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t);
114ae115bc7Smrj
115ae115bc7Smrj int
_init(void)116ae115bc7Smrj _init(void)
117ae115bc7Smrj {
118ae115bc7Smrj int err;
119ae115bc7Smrj
120ae115bc7Smrj if ((err = mod_install(&modlinkage)) != 0)
121ae115bc7Smrj return (err);
122ae115bc7Smrj
123ae115bc7Smrj return (0);
124ae115bc7Smrj }
125ae115bc7Smrj
126ae115bc7Smrj int
_fini(void)127ae115bc7Smrj _fini(void)
128ae115bc7Smrj {
129ae115bc7Smrj int err;
130ae115bc7Smrj
131ae115bc7Smrj if ((err = mod_remove(&modlinkage)) != 0)
132ae115bc7Smrj return (err);
133ae115bc7Smrj
134ae115bc7Smrj return (0);
135ae115bc7Smrj }
136ae115bc7Smrj
137ae115bc7Smrj int
_info(struct modinfo * modinfop)138ae115bc7Smrj _info(struct modinfo *modinfop)
139ae115bc7Smrj {
140ae115bc7Smrj return (mod_info(&modlinkage, modinfop));
141ae115bc7Smrj }
142ae115bc7Smrj
143ae115bc7Smrj /*
144ae115bc7Smrj * Minor node is not removed here, since the caller (xx_attach) is
145ae115bc7Smrj * responsible for removing all nodes.
146ae115bc7Smrj */
147ae115bc7Smrj void
agpmaster_detach(agp_master_softc_t ** master_softcp)148ae115bc7Smrj agpmaster_detach(agp_master_softc_t **master_softcp)
149ae115bc7Smrj {
150ae115bc7Smrj agp_master_softc_t *master_softc;
151ae115bc7Smrj
152ae115bc7Smrj ASSERT(master_softcp);
153ae115bc7Smrj master_softc = *master_softcp;
154ae115bc7Smrj
155ae115bc7Smrj /* intel integrated device */
156c4f91784Skz151634 if (IS_IGD(master_softc) &&
157c4f91784Skz151634 ((MMIO_HANDLE(master_softc) != NULL) ||
158c4f91784Skz151634 (GTT_HANDLE(master_softc) != NULL))) {
159c4f91784Skz151634 /*
160c4f91784Skz151634 * for some chipsets, mmap handle is shared between both mmio
161c4f91784Skz151634 * and GTT table.
162c4f91784Skz151634 */
163c4f91784Skz151634 if ((GTT_HANDLE(master_softc) != MMIO_HANDLE(master_softc)) &&
164c4f91784Skz151634 (GTT_HANDLE(master_softc) != NULL))
165c4f91784Skz151634 ddi_regs_map_free(>T_HANDLE(master_softc));
166c4f91784Skz151634 if (MMIO_HANDLE(master_softc) != NULL)
167543414e0Skz151634 ddi_regs_map_free(&MMIO_HANDLE(master_softc));
168ae115bc7Smrj }
169ae115bc7Smrj
170ae115bc7Smrj kmem_free(master_softc, sizeof (agp_master_softc_t));
171ae115bc7Smrj master_softc = NULL;
172ae115bc7Smrj
173ae115bc7Smrj return;
174ae115bc7Smrj
175ae115bc7Smrj }
176ae115bc7Smrj
177ae115bc7Smrj /*
178543414e0Skz151634 * 965 has a fixed GTT table size (512KB), so check to see the actual aperture
179543414e0Skz151634 * size. Aperture size = GTT table size * 1024.
180543414e0Skz151634 */
181543414e0Skz151634 static off_t
i965_apersize(agp_master_softc_t * agpmaster)182543414e0Skz151634 i965_apersize(agp_master_softc_t *agpmaster)
183543414e0Skz151634 {
184543414e0Skz151634 off_t apersize;
185543414e0Skz151634
186543414e0Skz151634 apersize = AGPM_READ(agpmaster, PGTBL_CTL);
187543414e0Skz151634 AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize));
188543414e0Skz151634 switch (apersize & GTT_SIZE_MASK) {
189219cee99Smc196098 case GTT_2MB:
190219cee99Smc196098 apersize = 2048;
191219cee99Smc196098 break;
192219cee99Smc196098 case GTT_1_5MB:
193219cee99Smc196098 apersize = 1536;
194219cee99Smc196098 break;
195219cee99Smc196098 case GTT_1MB:
196219cee99Smc196098 apersize = 1024;
197219cee99Smc196098 break;
198543414e0Skz151634 case GTT_512KB:
199543414e0Skz151634 apersize = 512;
200543414e0Skz151634 break;
201543414e0Skz151634 case GTT_256KB:
202543414e0Skz151634 apersize = 256;
203543414e0Skz151634 break;
204543414e0Skz151634 case GTT_128KB:
205543414e0Skz151634 apersize = 128;
206543414e0Skz151634 break;
207543414e0Skz151634 default:
208c4f91784Skz151634 apersize = 0;
209543414e0Skz151634 AGPM_DEBUG((CE_WARN,
210543414e0Skz151634 "i965_apersize: invalid GTT size in PGTBL_CTL"));
211543414e0Skz151634 }
212c4f91784Skz151634 return (apersize);
213c4f91784Skz151634 }
214c4f91784Skz151634
215c4f91784Skz151634 /*
216c4f91784Skz151634 * For Intel 3 series, we need to get GTT size from the GGMS field in GMCH
217c4f91784Skz151634 * Graphics Control Register. Return aperture size in MB.
218c4f91784Skz151634 */
219c4f91784Skz151634 static off_t
i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)220c4f91784Skz151634 i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)
221c4f91784Skz151634 {
222c4f91784Skz151634 uint16_t value;
223c4f91784Skz151634 off_t apersize;
224c4f91784Skz151634
225c4f91784Skz151634 /*
226c4f91784Skz151634 * Get the value of configuration register MGGC "Mirror of Dev0 GMCH
227c4f91784Skz151634 * Graphics Control" from Internal Graphics #2 (Device2:Function0).
228c4f91784Skz151634 */
229c4f91784Skz151634 value = pci_config_get16(pci_acc_hdl, I8XX_CONF_GC);
230c4f91784Skz151634 AGPM_DEBUG((CE_NOTE, "i3XX_apersize: MGGC = 0x%x", value));
231c4f91784Skz151634 /* computing aperture size using the pre-allocated GTT size */
232c4f91784Skz151634 switch (value & IX33_GGMS_MASK) {
233c4f91784Skz151634 case IX33_GGMS_1M:
234c4f91784Skz151634 apersize = 1024;
235c4f91784Skz151634 break;
236c4f91784Skz151634 case IX33_GGMS_2M:
237c4f91784Skz151634 apersize = 2048;
238c4f91784Skz151634 break;
239c4f91784Skz151634 default:
240c4f91784Skz151634 apersize = 0; /* no memory pre-allocated */
241c4f91784Skz151634 AGPM_DEBUG((CE_WARN,
242c4f91784Skz151634 "i3XX_apersize: no memory allocated for GTT"));
243c4f91784Skz151634 }
244c4f91784Skz151634 AGPM_DEBUG((CE_NOTE, "i3xx_apersize: apersize = %ldM", apersize));
245543414e0Skz151634 return (apersize);
246543414e0Skz151634 }
247543414e0Skz151634
248543414e0Skz151634 #define CHECK_STATUS(status) \
249543414e0Skz151634 if (status != DDI_SUCCESS) { \
250543414e0Skz151634 AGPM_DEBUG((CE_WARN, \
251543414e0Skz151634 "set_gtt_mmio: regs_map_setup error")); \
252543414e0Skz151634 return (-1); \
253543414e0Skz151634 }
254543414e0Skz151634 /*
255543414e0Skz151634 * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid
256543414e0Skz151634 * according to chipset.
257543414e0Skz151634 */
258543414e0Skz151634 static int
set_gtt_mmio(dev_info_t * devi,agp_master_softc_t * agpmaster,ddi_acc_handle_t pci_acc_hdl)259c4f91784Skz151634 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster,
260c4f91784Skz151634 ddi_acc_handle_t pci_acc_hdl)
261543414e0Skz151634 {
262c4f91784Skz151634 off_t apersize; /* size of graphics mem (MB) == GTT size (KB) */
263543414e0Skz151634 uint32_t value;
264c4f91784Skz151634 off_t gmadr_off; /* GMADR offset in PCI config space */
265543414e0Skz151634 int status;
266543414e0Skz151634
2670035d21cSmiao chen - Sun Microsystems - Beijing China if (IS_INTEL_X33(agpmaster->agpm_id)) {
268c4f91784Skz151634 /* Intel 3 series are similar with 915/945 series */
269543414e0Skz151634 status = ddi_regs_map_setup(devi, I915_GTTADDR,
270543414e0Skz151634 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
271c4f91784Skz151634 >T_HANDLE(agpmaster));
272543414e0Skz151634 CHECK_STATUS(status);
273543414e0Skz151634
274543414e0Skz151634 status = ddi_regs_map_setup(devi, I915_MMADR,
275543414e0Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
276543414e0Skz151634 &MMIO_HANDLE(agpmaster));
277543414e0Skz151634 CHECK_STATUS(status);
278543414e0Skz151634
279dc8c6b69Sms148562 gmadr_off = I915_CONF_GMADR;
280dc8c6b69Sms148562 /* Different computing method used in getting aperture size. */
281c4f91784Skz151634 apersize = i3XX_apersize(pci_acc_hdl);
2820035d21cSmiao chen - Sun Microsystems - Beijing China } else if (IS_INTEL_965(agpmaster->agpm_id)) {
283c4f91784Skz151634 status = ddi_regs_map_setup(devi, I965_GTTMMADR,
284c4f91784Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
285c4f91784Skz151634 &MMIO_HANDLE(agpmaster));
286c4f91784Skz151634 CHECK_STATUS(status);
287fc6df3bdSmiao chen - Sun Microsystems - Beijing China if ((agpmaster->agpm_id == INTEL_IGD_GM45) ||
2880035d21cSmiao chen - Sun Microsystems - Beijing China IS_INTEL_G4X(agpmaster->agpm_id))
289219cee99Smc196098 GTT_ADDR(agpmaster) =
290219cee99Smc196098 MMIO_BASE(agpmaster) + GM45_GTT_OFFSET;
291219cee99Smc196098 else
292219cee99Smc196098 GTT_ADDR(agpmaster) =
293219cee99Smc196098 MMIO_BASE(agpmaster) + I965_GTT_OFFSET;
294c4f91784Skz151634 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
295c4f91784Skz151634
296c4f91784Skz151634 gmadr_off = I915_CONF_GMADR;
297c4f91784Skz151634 apersize = i965_apersize(agpmaster);
2980035d21cSmiao chen - Sun Microsystems - Beijing China } else if (IS_INTEL_915(agpmaster->agpm_id)) {
299c4f91784Skz151634 /* I915/945 series */
300c4f91784Skz151634 status = ddi_regs_map_setup(devi, I915_GTTADDR,
301c4f91784Skz151634 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
302c4f91784Skz151634 >T_HANDLE(agpmaster));
303c4f91784Skz151634 CHECK_STATUS(status);
304c4f91784Skz151634
305c4f91784Skz151634 status = ddi_regs_map_setup(devi, I915_MMADR,
306c4f91784Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
307c4f91784Skz151634 &MMIO_HANDLE(agpmaster));
308c4f91784Skz151634 CHECK_STATUS(status);
309c4f91784Skz151634
310c4f91784Skz151634 gmadr_off = I915_CONF_GMADR;
311543414e0Skz151634 status = ddi_dev_regsize(devi, I915_GMADR, &apersize);
312c4f91784Skz151634 apersize = BYTES2MB(apersize);
313543414e0Skz151634 } else {
314543414e0Skz151634 /* I8XX series */
315543414e0Skz151634 status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR,
316543414e0Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
317543414e0Skz151634 &MMIO_HANDLE(agpmaster));
318543414e0Skz151634 CHECK_STATUS(status);
319543414e0Skz151634
320543414e0Skz151634 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET;
321c4f91784Skz151634 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
322c4f91784Skz151634 gmadr_off = I8XX_CONF_GMADR;
323543414e0Skz151634 status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize);
324c4f91784Skz151634 apersize = BYTES2MB(apersize);
325543414e0Skz151634 CHECK_STATUS(status);
326543414e0Skz151634 }
327543414e0Skz151634
328543414e0Skz151634 /*
329c4f91784Skz151634 * If memory size is smaller than a certain value, it means
330543414e0Skz151634 * the register set number for graphics memory range might
331543414e0Skz151634 * be wrong
332543414e0Skz151634 */
333c4f91784Skz151634 if (status != DDI_SUCCESS || apersize < 4) {
334543414e0Skz151634 AGPM_DEBUG((CE_WARN,
335c4f91784Skz151634 "set_gtt_mmio: error in getting graphics memory"));
336543414e0Skz151634 return (-1);
337543414e0Skz151634 }
338543414e0Skz151634
339c4f91784Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = apersize;
340543414e0Skz151634
341c4f91784Skz151634 /* get graphics memory base address from GMADR */
342c4f91784Skz151634 value = pci_config_get32(pci_acc_hdl, gmadr_off);
343543414e0Skz151634 APER_BASE(agpmaster) = value & GTT_BASE_MASK;
344c4f91784Skz151634 AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = 0x%x, apersize = %ldM, "
345543414e0Skz151634 "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize,
346543414e0Skz151634 (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster)));
347543414e0Skz151634 return (0);
348543414e0Skz151634 }
349543414e0Skz151634
350543414e0Skz151634 /*
351ae115bc7Smrj * Try to initialize agp master.
352ae115bc7Smrj * 0 is returned if the device is successfully initialized. AGP master soft
353ae115bc7Smrj * state is returned in master_softcp if needed.
354ae115bc7Smrj * Otherwise -1 is returned and *master_softcp is set to NULL.
355ae115bc7Smrj */
356ae115bc7Smrj int
agpmaster_attach(dev_info_t * devi,agp_master_softc_t ** master_softcp,ddi_acc_handle_t pci_acc_hdl,minor_t minor)357ae115bc7Smrj agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp,
358ae115bc7Smrj ddi_acc_handle_t pci_acc_hdl, minor_t minor)
359ae115bc7Smrj {
360ae115bc7Smrj int instance;
361ae115bc7Smrj int status;
362ae115bc7Smrj agp_master_softc_t *agpmaster;
363ae115bc7Smrj char buf[80];
364ae115bc7Smrj
365ae115bc7Smrj
366ae115bc7Smrj ASSERT(pci_acc_hdl);
367ae115bc7Smrj *master_softcp = NULL;
368ae115bc7Smrj agpmaster = (agp_master_softc_t *)
369ae115bc7Smrj kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP);
370ae115bc7Smrj
371ae115bc7Smrj agpmaster->agpm_id =
372ae115bc7Smrj pci_config_get32(pci_acc_hdl, PCI_CONF_VENID);
373ae115bc7Smrj agpmaster->agpm_acc_hdl = pci_acc_hdl;
374ae115bc7Smrj
375ae115bc7Smrj if (!detect_i8xx_device(agpmaster)) {
376543414e0Skz151634 /* Intel 8XX, 915, 945 and 965 series */
377543414e0Skz151634 if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0)
378ae115bc7Smrj goto fail;
379ae115bc7Smrj } else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) {
380543414e0Skz151634 /* non IGD or AGP devices, AMD64 gart */
381ae115bc7Smrj AGPM_DEBUG((CE_WARN,
382ae115bc7Smrj "agpmaster_attach: neither IGD or AGP devices exists"));
383ae115bc7Smrj agpmaster_detach(&agpmaster);
384ae115bc7Smrj return (0);
385ae115bc7Smrj }
386ae115bc7Smrj
387c4f91784Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid =
388c4f91784Skz151634 agpmaster->agpm_id;
389c4f91784Skz151634
390ae115bc7Smrj /* create minor node for IGD or AGP device */
391ae115bc7Smrj instance = ddi_get_instance(devi);
392ae115bc7Smrj
393ae115bc7Smrj (void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance);
394ae115bc7Smrj status = ddi_create_minor_node(devi, buf, S_IFCHR, minor,
395ae115bc7Smrj DDI_NT_AGP_MASTER, 0);
396ae115bc7Smrj
397ae115bc7Smrj if (status != DDI_SUCCESS) {
398ae115bc7Smrj AGPM_DEBUG((CE_WARN,
399ae115bc7Smrj "agpmaster_attach: create agpmaster node failed"));
400ae115bc7Smrj goto fail;
401ae115bc7Smrj }
402ae115bc7Smrj
403ae115bc7Smrj *master_softcp = agpmaster;
404ae115bc7Smrj return (0);
405ae115bc7Smrj fail:
406ae115bc7Smrj agpmaster_detach(&agpmaster);
407ae115bc7Smrj return (-1);
408ae115bc7Smrj }
409ae115bc7Smrj
410ae115bc7Smrj /*
411ae115bc7Smrj * Currently, it handles ioctl requests related with agp master device for
412ae115bc7Smrj * layered driver (agpgart) only.
413ae115bc7Smrj */
414ae115bc7Smrj /*ARGSUSED*/
415ae115bc7Smrj int
agpmaster_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval,agp_master_softc_t * softc)416ae115bc7Smrj agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred,
417ae115bc7Smrj int *rval, agp_master_softc_t *softc)
418ae115bc7Smrj {
419ae115bc7Smrj uint32_t base;
420ae115bc7Smrj uint32_t addr;
421ae115bc7Smrj igd_gtt_seg_t seg;
422ae115bc7Smrj agp_info_t info;
423ae115bc7Smrj uint32_t value;
424ae115bc7Smrj off_t cap;
425ae115bc7Smrj uint32_t command;
426ae115bc7Smrj static char kernel_only[] =
427ae115bc7Smrj "agpmaster_ioctl: %s is a kernel only ioctl";
428ae115bc7Smrj
429ae115bc7Smrj CONFIRM(softc);
430ae115bc7Smrj
431ae115bc7Smrj switch (cmd) {
432ae115bc7Smrj case DEVICE_DETECT:
433ae115bc7Smrj if (!(mode & FKIOCTL)) {
434ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT"));
435ae115bc7Smrj return (ENXIO);
436ae115bc7Smrj }
437ae115bc7Smrj
438ae115bc7Smrj if (ddi_copyout(&softc->agpm_dev_type,
439ae115bc7Smrj (void *)data, sizeof (int), mode))
440ae115bc7Smrj return (EFAULT);
441ae115bc7Smrj break;
442ae115bc7Smrj case AGP_MASTER_SETCMD:
443ae115bc7Smrj if (!(mode & FKIOCTL)) {
444ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD"));
445ae115bc7Smrj return (ENXIO);
446ae115bc7Smrj }
447ae115bc7Smrj
448ae115bc7Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
449ae115bc7Smrj CONFIRM(softc->agpm_data.agpm_acaptr);
450ae115bc7Smrj
451ae115bc7Smrj if (ddi_copyin((void *)data, &command,
452ae115bc7Smrj sizeof (uint32_t), mode))
453ae115bc7Smrj return (EFAULT);
454ae115bc7Smrj
455ae115bc7Smrj pci_config_put32(softc->agpm_acc_hdl,
456ae115bc7Smrj softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND,
457ae115bc7Smrj command);
458ae115bc7Smrj break;
459ae115bc7Smrj case AGP_MASTER_GETINFO:
460ae115bc7Smrj if (!(mode & FKIOCTL)) {
461ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only,
462ae115bc7Smrj "AGP_MASTER_GETINFO"));
463ae115bc7Smrj return (ENXIO);
464ae115bc7Smrj }
465ae115bc7Smrj
466ae115bc7Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
467ae115bc7Smrj CONFIRM(softc->agpm_data.agpm_acaptr);
468ae115bc7Smrj
469ae115bc7Smrj cap = softc->agpm_data.agpm_acaptr;
470ae115bc7Smrj value = pci_config_get32(softc->agpm_acc_hdl, cap);
471ae115bc7Smrj info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf);
472ae115bc7Smrj info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf);
473ae115bc7Smrj info.agpi_devid = softc->agpm_id;
474ae115bc7Smrj info.agpi_mode = pci_config_get32(
475ae115bc7Smrj softc->agpm_acc_hdl, cap + AGP_CONF_STATUS);
476ae115bc7Smrj
477ae115bc7Smrj if (ddi_copyout(&info, (void *)data,
478ae115bc7Smrj sizeof (agp_info_t), mode))
479ae115bc7Smrj return (EFAULT);
480ae115bc7Smrj break;
481ae115bc7Smrj case I810_SET_GTT_BASE:
482ae115bc7Smrj if (!(mode & FKIOCTL)) {
483ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR"));
484ae115bc7Smrj return (ENXIO);
485ae115bc7Smrj }
486ae115bc7Smrj
487ae115bc7Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810);
488ae115bc7Smrj
489ae115bc7Smrj if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode))
490ae115bc7Smrj return (EFAULT);
491ae115bc7Smrj
492ae115bc7Smrj /* enables page table */
493ae115bc7Smrj addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID;
494ae115bc7Smrj
495543414e0Skz151634 AGPM_WRITE(softc, PGTBL_CTL, addr);
496ae115bc7Smrj break;
497ae115bc7Smrj case I8XX_GET_INFO:
498ae115bc7Smrj if (!(mode & FKIOCTL)) {
499ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO"));
500ae115bc7Smrj return (ENXIO);
501ae115bc7Smrj }
502ae115bc7Smrj
503ae115bc7Smrj CONFIRM(IS_IGD(softc));
504ae115bc7Smrj
505ae115bc7Smrj if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info,
506ae115bc7Smrj (void *)data, sizeof (igd_info_t), mode))
507ae115bc7Smrj return (EFAULT);
508ae115bc7Smrj break;
509ae115bc7Smrj case I8XX_ADD2GTT:
510ae115bc7Smrj if (!(mode & FKIOCTL)) {
511ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT"));
512ae115bc7Smrj return (ENXIO);
513ae115bc7Smrj }
514ae115bc7Smrj
515ae115bc7Smrj CONFIRM(IS_IGD(softc));
516ae115bc7Smrj
517ae115bc7Smrj if (ddi_copyin((void *)data, &seg,
518ae115bc7Smrj sizeof (igd_gtt_seg_t), mode))
519ae115bc7Smrj return (EFAULT);
520ae115bc7Smrj
521ae115bc7Smrj if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg))
522ae115bc7Smrj return (EINVAL);
523ae115bc7Smrj break;
524ae115bc7Smrj case I8XX_REM_GTT:
525ae115bc7Smrj if (!(mode & FKIOCTL)) {
526ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT"));
527ae115bc7Smrj return (ENXIO);
528ae115bc7Smrj }
529ae115bc7Smrj
530ae115bc7Smrj CONFIRM(IS_IGD(softc));
531ae115bc7Smrj
532ae115bc7Smrj if (ddi_copyin((void *)data, &seg,
533ae115bc7Smrj sizeof (igd_gtt_seg_t), mode))
534ae115bc7Smrj return (EFAULT);
535ae115bc7Smrj
536ae115bc7Smrj i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg);
537ae115bc7Smrj break;
538ae115bc7Smrj case I8XX_UNCONFIG:
539ae115bc7Smrj if (!(mode & FKIOCTL)) {
540ae115bc7Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG"));
541ae115bc7Smrj return (ENXIO);
542ae115bc7Smrj }
543ae115bc7Smrj
544ae115bc7Smrj CONFIRM(IS_IGD(softc));
545ae115bc7Smrj
546ae115bc7Smrj if (softc->agpm_dev_type == DEVICE_IS_I810)
547543414e0Skz151634 AGPM_WRITE(softc, PGTBL_CTL, 0);
548ae115bc7Smrj /*
549ae115bc7Smrj * may need to clear all gtt entries here for i830 series,
550ae115bc7Smrj * but may not be necessary
551ae115bc7Smrj */
552ae115bc7Smrj break;
553ae115bc7Smrj }
554ae115bc7Smrj return (0);
555ae115bc7Smrj }
556ae115bc7Smrj
557ae115bc7Smrj /*
558ae115bc7Smrj * If AGP cap pointer is successfully found, none-zero value is returned.
559ae115bc7Smrj * Otherwise 0 is returned.
560ae115bc7Smrj */
561ae115bc7Smrj static off_t
agpmaster_cap_find(ddi_acc_handle_t acc_handle)562ae115bc7Smrj agpmaster_cap_find(ddi_acc_handle_t acc_handle)
563ae115bc7Smrj {
564ae115bc7Smrj off_t nextcap;
565ae115bc7Smrj uint32_t ncapid;
566ae115bc7Smrj uint8_t value;
567ae115bc7Smrj
568ae115bc7Smrj /* check if this device supports capibility pointer */
569ae115bc7Smrj value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT)
570ae115bc7Smrj & PCI_CONF_CAP_MASK);
571ae115bc7Smrj
572ae115bc7Smrj if (!value)
573ae115bc7Smrj return (0);
574ae115bc7Smrj /* get the offset of the first capability pointer from CAPPTR */
575ae115bc7Smrj nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR));
576ae115bc7Smrj
577ae115bc7Smrj /* check AGP capability from the first capability pointer */
578ae115bc7Smrj while (nextcap) {
579ae115bc7Smrj ncapid = pci_config_get32(acc_handle, nextcap);
580ae115bc7Smrj if ((ncapid & PCI_CONF_CAPID_MASK)
581ae115bc7Smrj == AGP_CAP_ID) /* find AGP cap */
582ae115bc7Smrj break;
583ae115bc7Smrj
584ae115bc7Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
585ae115bc7Smrj }
586ae115bc7Smrj
587ae115bc7Smrj return (nextcap);
588ae115bc7Smrj
589ae115bc7Smrj }
590ae115bc7Smrj
591ae115bc7Smrj /*
592ae115bc7Smrj * If i8xx device is successfully detected, 0 is returned.
593ae115bc7Smrj * Otherwise -1 is returned.
594ae115bc7Smrj */
595ae115bc7Smrj static int
detect_i8xx_device(agp_master_softc_t * master_softc)596ae115bc7Smrj detect_i8xx_device(agp_master_softc_t *master_softc)
597ae115bc7Smrj {
598ae115bc7Smrj
599ae115bc7Smrj switch (master_softc->agpm_id) {
600ae115bc7Smrj case INTEL_IGD_810:
601ae115bc7Smrj case INTEL_IGD_810DC:
602ae115bc7Smrj case INTEL_IGD_810E:
603ae115bc7Smrj case INTEL_IGD_815:
604ae115bc7Smrj master_softc->agpm_dev_type = DEVICE_IS_I810;
605ae115bc7Smrj break;
606ae115bc7Smrj case INTEL_IGD_830M:
607ae115bc7Smrj case INTEL_IGD_845G:
608ae115bc7Smrj case INTEL_IGD_855GM:
609ae115bc7Smrj case INTEL_IGD_865G:
610543414e0Skz151634 case INTEL_IGD_915:
611543414e0Skz151634 case INTEL_IGD_915GM:
612ae115bc7Smrj case INTEL_IGD_945:
6135dbcb2a2Skz151634 case INTEL_IGD_945GM:
61412db04d3Smiao chen - Sun Microsystems - Beijing China case INTEL_IGD_945GME:
615543414e0Skz151634 case INTEL_IGD_946GZ:
616543414e0Skz151634 case INTEL_IGD_965G1:
617543414e0Skz151634 case INTEL_IGD_965G2:
618543414e0Skz151634 case INTEL_IGD_965GM:
619f7b793feSkz151634 case INTEL_IGD_965GME:
620543414e0Skz151634 case INTEL_IGD_965Q:
621c4f91784Skz151634 case INTEL_IGD_Q35:
622c4f91784Skz151634 case INTEL_IGD_G33:
623c4f91784Skz151634 case INTEL_IGD_Q33:
624219cee99Smc196098 case INTEL_IGD_GM45:
625fc6df3bdSmiao chen - Sun Microsystems - Beijing China case INTEL_IGD_EL:
626fc6df3bdSmiao chen - Sun Microsystems - Beijing China case INTEL_IGD_Q45:
627fc6df3bdSmiao chen - Sun Microsystems - Beijing China case INTEL_IGD_G45:
628d0231070Smiao chen - Sun Microsystems - Beijing China case INTEL_IGD_G41:
6292e6e901dSmiao chen - Sun Microsystems - Beijing China case INTEL_IGD_IGDNG_D:
6302e6e901dSmiao chen - Sun Microsystems - Beijing China case INTEL_IGD_IGDNG_M:
6310035d21cSmiao chen - Sun Microsystems - Beijing China case INTEL_IGD_B43:
632ae115bc7Smrj master_softc->agpm_dev_type = DEVICE_IS_I830;
633ae115bc7Smrj break;
634ae115bc7Smrj default: /* unknown id */
635ae115bc7Smrj return (-1);
636ae115bc7Smrj }
637ae115bc7Smrj
638ae115bc7Smrj return (0);
639ae115bc7Smrj }
640ae115bc7Smrj
641ae115bc7Smrj /*
642*fe7cd8aaSCyril Plisko * If agp master is successfully detected, 0 is returned.
643ae115bc7Smrj * Otherwise -1 is returned.
644ae115bc7Smrj */
645ae115bc7Smrj static int
detect_agp_devcice(agp_master_softc_t * master_softc,ddi_acc_handle_t acc_handle)646ae115bc7Smrj detect_agp_devcice(agp_master_softc_t *master_softc,
647ae115bc7Smrj ddi_acc_handle_t acc_handle)
648ae115bc7Smrj {
649ae115bc7Smrj off_t cap;
650ae115bc7Smrj
651ae115bc7Smrj cap = agpmaster_cap_find(acc_handle);
652ae115bc7Smrj if (cap) {
653ae115bc7Smrj master_softc->agpm_dev_type = DEVICE_IS_AGP;
654ae115bc7Smrj master_softc->agpm_data.agpm_acaptr = cap;
655ae115bc7Smrj return (0);
656ae115bc7Smrj } else {
657ae115bc7Smrj return (-1);
658ae115bc7Smrj }
659ae115bc7Smrj
660ae115bc7Smrj }
661ae115bc7Smrj
662ae115bc7Smrj /*
663ae115bc7Smrj * Please refer to GART and GTT entry format table in agpdefs.h for
664ae115bc7Smrj * intel GTT entry format.
665ae115bc7Smrj */
666ae115bc7Smrj static int
phys2entry(uint32_t type,uint32_t physaddr,uint32_t * entry)667ae115bc7Smrj phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry)
668ae115bc7Smrj {
669ae115bc7Smrj uint32_t value;
670ae115bc7Smrj
671ae115bc7Smrj switch (type) {
672ae115bc7Smrj case AGP_PHYSICAL:
673ae115bc7Smrj case AGP_NORMAL:
674ae115bc7Smrj value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID;
675ae115bc7Smrj break;
676ae115bc7Smrj default:
677ae115bc7Smrj return (-1);
678ae115bc7Smrj }
679ae115bc7Smrj
680ae115bc7Smrj *entry = value;
681ae115bc7Smrj
682ae115bc7Smrj return (0);
683ae115bc7Smrj }
684ae115bc7Smrj
685ae115bc7Smrj static int
i8xx_add_to_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)686ae115bc7Smrj i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
687ae115bc7Smrj {
688ae115bc7Smrj int i;
689ae115bc7Smrj uint32_t *paddr;
690ae115bc7Smrj uint32_t entry;
691ae115bc7Smrj uint32_t maxpages;
692ae115bc7Smrj
693ae115bc7Smrj maxpages = gtt->gtt_info.igd_apersize;
694ae115bc7Smrj maxpages = GTT_MB_TO_PAGES(maxpages);
695ae115bc7Smrj
696ae115bc7Smrj paddr = seg.igs_phyaddr;
697ae115bc7Smrj
698ae115bc7Smrj /* check if gtt max page number is reached */
699ae115bc7Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
700ae115bc7Smrj return (-1);
701ae115bc7Smrj
702ae115bc7Smrj paddr = seg.igs_phyaddr;
703ae115bc7Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
704ae115bc7Smrj i++, paddr++) {
705ae115bc7Smrj if (phys2entry(seg.igs_type, *paddr, &entry))
706ae115bc7Smrj return (-1);
707c4f91784Skz151634 ddi_put32(gtt->gtt_handle,
708ae115bc7Smrj (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
709ae115bc7Smrj entry);
710ae115bc7Smrj }
711ae115bc7Smrj
712ae115bc7Smrj return (0);
713ae115bc7Smrj }
714ae115bc7Smrj
715ae115bc7Smrj static void
i8xx_remove_from_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)716ae115bc7Smrj i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
717ae115bc7Smrj {
718ae115bc7Smrj int i;
719ae115bc7Smrj uint32_t maxpages;
720ae115bc7Smrj
721ae115bc7Smrj maxpages = gtt->gtt_info.igd_apersize;
722ae115bc7Smrj maxpages = GTT_MB_TO_PAGES(maxpages);
723ae115bc7Smrj
724ae115bc7Smrj /* check if gtt max page number is reached */
725ae115bc7Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
726ae115bc7Smrj return;
727ae115bc7Smrj
728ae115bc7Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) {
729c4f91784Skz151634 ddi_put32(gtt->gtt_handle,
730543414e0Skz151634 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 0);
731ae115bc7Smrj }
732ae115bc7Smrj }
733