4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2009, Intel Corporation.
24 * All Rights Reserved.
28 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
33 * Misc module for AGP master device support
36 #include <sys/modctl.h>
40 #include <sys/types.h>
41 #include <sys/dditypes.h>
42 #include <sys/sunddi.h>
43 #include <sys/agpgart.h>
44 #include <sys/agp/agpdefs.h>
45 #include <sys/agp/agpmaster_io.h>
47 #define PGTBL_CTL 0x2020 /* Page table control register */
49 #define I8XX_MMIO_BAR 2
50 #define I8XX_PTE_OFFSET 0x10000
51 #define I915_MMADR 1 /* mem-mapped registers BAR */
52 #define I915_GMADR 3 /* graphics mem BAR */
53 #define I915_GTTADDR 4 /* GTT BAR */
54 #define I965_GTTMMADR 1 /* mem-mapped registers BAR + GTT */
55 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */
56 #define I965_GTT_OFFSET 0x80000
57 #define GM45_GTT_OFFSET 0x200000
58 #define GTT_SIZE_MASK 0xe
59 #define GTT_512KB (0 << 1)
60 #define GTT_256KB (1 << 1)
61 #define GTT_128KB (2 << 1)
62 #define GTT_1MB (3 << 1)
63 #define GTT_2MB (4 << 1)
64 #define GTT_1_5MB (5 << 1)
66 #define MMIO_BASE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_base
67 #define MMIO_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_handle
68 #define GTT_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_handle
69 /* Base address of GTT */
70 #define GTT_ADDR(x) (x)->agpm_data.agpm_gtt.gtt_addr
71 /* Graphics memory base address */
72 #define APER_BASE(x) (x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase
74 #define AGPM_WRITE(x, off, val) \
75 ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val));
77 #define AGPM_READ(x, off) \
78 ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)));
81 #define CONFIRM(value) ASSERT(value)
83 #define CONFIRM(value) if (!(value)) return (EINVAL)
87 #define AGPM_DEBUG(args) if (agpm_debug >= 1) cmn_err args
90 * Whether it is a Intel integrated graphics card
92 #define IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \
93 (agpmaster->agpm_dev_type == DEVICE_IS_I830))
95 static struct modlmisc modlmisc
= {
96 &mod_miscops
, "AGP master interfaces"
99 static struct modlinkage modlinkage
= {
100 MODREV_1
, (void *)&modlmisc
, NULL
103 static ddi_device_acc_attr_t i8xx_dev_access
= {
109 static off_t
agpmaster_cap_find(ddi_acc_handle_t
);
110 static int detect_i8xx_device(agp_master_softc_t
*);
111 static int detect_agp_devcice(agp_master_softc_t
*, ddi_acc_handle_t
);
112 static int i8xx_add_to_gtt(gtt_impl_t
*, igd_gtt_seg_t
);
113 static void i8xx_remove_from_gtt(gtt_impl_t
*, igd_gtt_seg_t
);
120 if ((err
= mod_install(&modlinkage
)) != 0)
131 if ((err
= mod_remove(&modlinkage
)) != 0)
138 _info(struct modinfo
*modinfop
)
140 return (mod_info(&modlinkage
, modinfop
));
144 * Minor node is not removed here, since the caller (xx_attach) is
145 * responsible for removing all nodes.
148 agpmaster_detach(agp_master_softc_t
**master_softcp
)
150 agp_master_softc_t
*master_softc
;
152 ASSERT(master_softcp
);
153 master_softc
= *master_softcp
;
155 /* intel integrated device */
156 if (IS_IGD(master_softc
) &&
157 ((MMIO_HANDLE(master_softc
) != NULL
) ||
158 (GTT_HANDLE(master_softc
) != NULL
))) {
160 * for some chipsets, mmap handle is shared between both mmio
163 if ((GTT_HANDLE(master_softc
) != MMIO_HANDLE(master_softc
)) &&
164 (GTT_HANDLE(master_softc
) != NULL
))
165 ddi_regs_map_free(>T_HANDLE(master_softc
));
166 if (MMIO_HANDLE(master_softc
) != NULL
)
167 ddi_regs_map_free(&MMIO_HANDLE(master_softc
));
170 kmem_free(master_softc
, sizeof (agp_master_softc_t
));
178 * 965 has a fixed GTT table size (512KB), so check to see the actual aperture
179 * size. Aperture size = GTT table size * 1024.
182 i965_apersize(agp_master_softc_t
*agpmaster
)
186 apersize
= AGPM_READ(agpmaster
, PGTBL_CTL
);
187 AGPM_DEBUG((CE_NOTE
, "i965_apersize: PGTBL_CTL = %lx", apersize
));
188 switch (apersize
& GTT_SIZE_MASK
) {
210 "i965_apersize: invalid GTT size in PGTBL_CTL"));
216 * For Intel 3 series, we need to get GTT size from the GGMS field in GMCH
217 * Graphics Control Register. Return aperture size in MB.
220 i3XX_apersize(ddi_acc_handle_t pci_acc_hdl
)
226 * Get the value of configuration register MGGC "Mirror of Dev0 GMCH
227 * Graphics Control" from Internal Graphics #2 (Device2:Function0).
229 value
= pci_config_get16(pci_acc_hdl
, I8XX_CONF_GC
);
230 AGPM_DEBUG((CE_NOTE
, "i3XX_apersize: MGGC = 0x%x", value
));
231 /* computing aperture size using the pre-allocated GTT size */
232 switch (value
& IX33_GGMS_MASK
) {
240 apersize
= 0; /* no memory pre-allocated */
242 "i3XX_apersize: no memory allocated for GTT"));
244 AGPM_DEBUG((CE_NOTE
, "i3xx_apersize: apersize = %ldM", apersize
));
248 #define CHECK_STATUS(status) \
249 if (status != DDI_SUCCESS) { \
250 AGPM_DEBUG((CE_WARN, \
251 "set_gtt_mmio: regs_map_setup error")); \
255 * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid
256 * according to chipset.
259 set_gtt_mmio(dev_info_t
*devi
, agp_master_softc_t
*agpmaster
,
260 ddi_acc_handle_t pci_acc_hdl
)
262 off_t apersize
; /* size of graphics mem (MB) == GTT size (KB) */
264 off_t gmadr_off
; /* GMADR offset in PCI config space */
267 if (IS_INTEL_X33(agpmaster
->agpm_id
)) {
268 /* Intel 3 series are similar with 915/945 series */
269 status
= ddi_regs_map_setup(devi
, I915_GTTADDR
,
270 >T_ADDR(agpmaster
), 0, 0, &i8xx_dev_access
,
271 >T_HANDLE(agpmaster
));
272 CHECK_STATUS(status
);
274 status
= ddi_regs_map_setup(devi
, I915_MMADR
,
275 &MMIO_BASE(agpmaster
), 0, 0, &i8xx_dev_access
,
276 &MMIO_HANDLE(agpmaster
));
277 CHECK_STATUS(status
);
279 gmadr_off
= I915_CONF_GMADR
;
280 /* Different computing method used in getting aperture size. */
281 apersize
= i3XX_apersize(pci_acc_hdl
);
282 } else if (IS_INTEL_965(agpmaster
->agpm_id
)) {
283 status
= ddi_regs_map_setup(devi
, I965_GTTMMADR
,
284 &MMIO_BASE(agpmaster
), 0, 0, &i8xx_dev_access
,
285 &MMIO_HANDLE(agpmaster
));
286 CHECK_STATUS(status
);
287 if ((agpmaster
->agpm_id
== INTEL_IGD_GM45
) ||
288 IS_INTEL_G4X(agpmaster
->agpm_id
))
289 GTT_ADDR(agpmaster
) =
290 MMIO_BASE(agpmaster
) + GM45_GTT_OFFSET
;
292 GTT_ADDR(agpmaster
) =
293 MMIO_BASE(agpmaster
) + I965_GTT_OFFSET
;
294 GTT_HANDLE(agpmaster
) = MMIO_HANDLE(agpmaster
);
296 gmadr_off
= I915_CONF_GMADR
;
297 apersize
= i965_apersize(agpmaster
);
298 } else if (IS_INTEL_915(agpmaster
->agpm_id
)) {
299 /* I915/945 series */
300 status
= ddi_regs_map_setup(devi
, I915_GTTADDR
,
301 >T_ADDR(agpmaster
), 0, 0, &i8xx_dev_access
,
302 >T_HANDLE(agpmaster
));
303 CHECK_STATUS(status
);
305 status
= ddi_regs_map_setup(devi
, I915_MMADR
,
306 &MMIO_BASE(agpmaster
), 0, 0, &i8xx_dev_access
,
307 &MMIO_HANDLE(agpmaster
));
308 CHECK_STATUS(status
);
310 gmadr_off
= I915_CONF_GMADR
;
311 status
= ddi_dev_regsize(devi
, I915_GMADR
, &apersize
);
312 apersize
= BYTES2MB(apersize
);
315 status
= ddi_regs_map_setup(devi
, I8XX_MMIO_BAR
,
316 &MMIO_BASE(agpmaster
), 0, 0, &i8xx_dev_access
,
317 &MMIO_HANDLE(agpmaster
));
318 CHECK_STATUS(status
);
320 GTT_ADDR(agpmaster
) = MMIO_BASE(agpmaster
) + I8XX_PTE_OFFSET
;
321 GTT_HANDLE(agpmaster
) = MMIO_HANDLE(agpmaster
);
322 gmadr_off
= I8XX_CONF_GMADR
;
323 status
= ddi_dev_regsize(devi
, I8XX_FB_BAR
, &apersize
);
324 apersize
= BYTES2MB(apersize
);
325 CHECK_STATUS(status
);
329 * If memory size is smaller than a certain value, it means
330 * the register set number for graphics memory range might
333 if (status
!= DDI_SUCCESS
|| apersize
< 4) {
335 "set_gtt_mmio: error in getting graphics memory"));
339 agpmaster
->agpm_data
.agpm_gtt
.gtt_info
.igd_apersize
= apersize
;
341 /* get graphics memory base address from GMADR */
342 value
= pci_config_get32(pci_acc_hdl
, gmadr_off
);
343 APER_BASE(agpmaster
) = value
& GTT_BASE_MASK
;
344 AGPM_DEBUG((CE_NOTE
, "set_gtt_mmio: aperbase = 0x%x, apersize = %ldM, "
345 "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster
), apersize
,
346 (void *)GTT_ADDR(agpmaster
), (void *)MMIO_BASE(agpmaster
)));
351 * Try to initialize agp master.
352 * 0 is returned if the device is successfully initialized. AGP master soft
353 * state is returned in master_softcp if needed.
354 * Otherwise -1 is returned and *master_softcp is set to NULL.
357 agpmaster_attach(dev_info_t
*devi
, agp_master_softc_t
**master_softcp
,
358 ddi_acc_handle_t pci_acc_hdl
, minor_t minor
)
362 agp_master_softc_t
*agpmaster
;
367 *master_softcp
= NULL
;
368 agpmaster
= (agp_master_softc_t
*)
369 kmem_zalloc(sizeof (agp_master_softc_t
), KM_SLEEP
);
372 pci_config_get32(pci_acc_hdl
, PCI_CONF_VENID
);
373 agpmaster
->agpm_acc_hdl
= pci_acc_hdl
;
375 if (!detect_i8xx_device(agpmaster
)) {
376 /* Intel 8XX, 915, 945 and 965 series */
377 if (set_gtt_mmio(devi
, agpmaster
, pci_acc_hdl
) != 0)
379 } else if (detect_agp_devcice(agpmaster
, pci_acc_hdl
)) {
380 /* non IGD or AGP devices, AMD64 gart */
382 "agpmaster_attach: neither IGD or AGP devices exists"));
383 agpmaster_detach(&agpmaster
);
387 agpmaster
->agpm_data
.agpm_gtt
.gtt_info
.igd_devid
=
390 /* create minor node for IGD or AGP device */
391 instance
= ddi_get_instance(devi
);
393 (void) sprintf(buf
, "%s%d", AGPMASTER_NAME
, instance
);
394 status
= ddi_create_minor_node(devi
, buf
, S_IFCHR
, minor
,
395 DDI_NT_AGP_MASTER
, 0);
397 if (status
!= DDI_SUCCESS
) {
399 "agpmaster_attach: create agpmaster node failed"));
403 *master_softcp
= agpmaster
;
406 agpmaster_detach(&agpmaster
);
411 * Currently, it handles ioctl requests related with agp master device for
412 * layered driver (agpgart) only.
416 agpmaster_ioctl(dev_t dev
, int cmd
, intptr_t data
, int mode
, cred_t
*cred
,
417 int *rval
, agp_master_softc_t
*softc
)
426 static char kernel_only
[] =
427 "agpmaster_ioctl: %s is a kernel only ioctl";
433 if (!(mode
& FKIOCTL
)) {
434 AGPM_DEBUG((CE_CONT
, kernel_only
, "DEVICE_DETECT"));
438 if (ddi_copyout(&softc
->agpm_dev_type
,
439 (void *)data
, sizeof (int), mode
))
442 case AGP_MASTER_SETCMD
:
443 if (!(mode
& FKIOCTL
)) {
444 AGPM_DEBUG((CE_CONT
, kernel_only
, "AGP_MASTER_SETCMD"));
448 CONFIRM(softc
->agpm_dev_type
== DEVICE_IS_AGP
);
449 CONFIRM(softc
->agpm_data
.agpm_acaptr
);
451 if (ddi_copyin((void *)data
, &command
,
452 sizeof (uint32_t), mode
))
455 pci_config_put32(softc
->agpm_acc_hdl
,
456 softc
->agpm_data
.agpm_acaptr
+ AGP_CONF_COMMAND
,
459 case AGP_MASTER_GETINFO
:
460 if (!(mode
& FKIOCTL
)) {
461 AGPM_DEBUG((CE_CONT
, kernel_only
,
462 "AGP_MASTER_GETINFO"));
466 CONFIRM(softc
->agpm_dev_type
== DEVICE_IS_AGP
);
467 CONFIRM(softc
->agpm_data
.agpm_acaptr
);
469 cap
= softc
->agpm_data
.agpm_acaptr
;
470 value
= pci_config_get32(softc
->agpm_acc_hdl
, cap
);
471 info
.agpi_version
.agpv_major
= (uint16_t)((value
>> 20) & 0xf);
472 info
.agpi_version
.agpv_minor
= (uint16_t)((value
>> 16) & 0xf);
473 info
.agpi_devid
= softc
->agpm_id
;
474 info
.agpi_mode
= pci_config_get32(
475 softc
->agpm_acc_hdl
, cap
+ AGP_CONF_STATUS
);
477 if (ddi_copyout(&info
, (void *)data
,
478 sizeof (agp_info_t
), mode
))
481 case I810_SET_GTT_BASE
:
482 if (!(mode
& FKIOCTL
)) {
483 AGPM_DEBUG((CE_CONT
, kernel_only
, "I810_SET_GTT_ADDR"));
487 CONFIRM(softc
->agpm_dev_type
== DEVICE_IS_I810
);
489 if (ddi_copyin((void *)data
, &base
, sizeof (uint32_t), mode
))
492 /* enables page table */
493 addr
= (base
& GTT_BASE_MASK
) | GTT_TABLE_VALID
;
495 AGPM_WRITE(softc
, PGTBL_CTL
, addr
);
498 if (!(mode
& FKIOCTL
)) {
499 AGPM_DEBUG((CE_CONT
, kernel_only
, "I8XX_GET_INFO"));
503 CONFIRM(IS_IGD(softc
));
505 if (ddi_copyout(&softc
->agpm_data
.agpm_gtt
.gtt_info
,
506 (void *)data
, sizeof (igd_info_t
), mode
))
510 if (!(mode
& FKIOCTL
)) {
511 AGPM_DEBUG((CE_CONT
, kernel_only
, "I8XX_ADD2GTT"));
515 CONFIRM(IS_IGD(softc
));
517 if (ddi_copyin((void *)data
, &seg
,
518 sizeof (igd_gtt_seg_t
), mode
))
521 if (i8xx_add_to_gtt(&softc
->agpm_data
.agpm_gtt
, seg
))
525 if (!(mode
& FKIOCTL
)) {
526 AGPM_DEBUG((CE_CONT
, kernel_only
, "I8XX_REM_GTT"));
530 CONFIRM(IS_IGD(softc
));
532 if (ddi_copyin((void *)data
, &seg
,
533 sizeof (igd_gtt_seg_t
), mode
))
536 i8xx_remove_from_gtt(&softc
->agpm_data
.agpm_gtt
, seg
);
539 if (!(mode
& FKIOCTL
)) {
540 AGPM_DEBUG((CE_CONT
, kernel_only
, "I8XX_UNCONFIG"));
544 CONFIRM(IS_IGD(softc
));
546 if (softc
->agpm_dev_type
== DEVICE_IS_I810
)
547 AGPM_WRITE(softc
, PGTBL_CTL
, 0);
549 * may need to clear all gtt entries here for i830 series,
550 * but may not be necessary
558 * If AGP cap pointer is successfully found, none-zero value is returned.
559 * Otherwise 0 is returned.
562 agpmaster_cap_find(ddi_acc_handle_t acc_handle
)
568 /* check if this device supports capibility pointer */
569 value
= (uint8_t)(pci_config_get16(acc_handle
, PCI_CONF_STAT
)
570 & PCI_CONF_CAP_MASK
);
574 /* get the offset of the first capability pointer from CAPPTR */
575 nextcap
= (off_t
)(pci_config_get8(acc_handle
, AGP_CONF_CAPPTR
));
577 /* check AGP capability from the first capability pointer */
579 ncapid
= pci_config_get32(acc_handle
, nextcap
);
580 if ((ncapid
& PCI_CONF_CAPID_MASK
)
581 == AGP_CAP_ID
) /* find AGP cap */
584 nextcap
= (off_t
)((ncapid
& PCI_CONF_NCAPID_MASK
) >> 8);
592 * If i8xx device is successfully detected, 0 is returned.
593 * Otherwise -1 is returned.
596 detect_i8xx_device(agp_master_softc_t
*master_softc
)
599 switch (master_softc
->agpm_id
) {
601 case INTEL_IGD_810DC
:
604 master_softc
->agpm_dev_type
= DEVICE_IS_I810
;
608 case INTEL_IGD_855GM
:
611 case INTEL_IGD_915GM
:
613 case INTEL_IGD_945GM
:
614 case INTEL_IGD_945GME
:
615 case INTEL_IGD_946GZ
:
616 case INTEL_IGD_965G1
:
617 case INTEL_IGD_965G2
:
618 case INTEL_IGD_965GM
:
619 case INTEL_IGD_965GME
:
629 case INTEL_IGD_IGDNG_D
:
630 case INTEL_IGD_IGDNG_M
:
632 master_softc
->agpm_dev_type
= DEVICE_IS_I830
;
634 default: /* unknown id */
642 * If agp master is successfully detected, 0 is returned.
643 * Otherwise -1 is returned.
646 detect_agp_devcice(agp_master_softc_t
*master_softc
,
647 ddi_acc_handle_t acc_handle
)
651 cap
= agpmaster_cap_find(acc_handle
);
653 master_softc
->agpm_dev_type
= DEVICE_IS_AGP
;
654 master_softc
->agpm_data
.agpm_acaptr
= cap
;
663 * Please refer to GART and GTT entry format table in agpdefs.h for
664 * intel GTT entry format.
667 phys2entry(uint32_t type
, uint32_t physaddr
, uint32_t *entry
)
674 value
= (physaddr
& GTT_PTE_MASK
) | GTT_PTE_VALID
;
686 i8xx_add_to_gtt(gtt_impl_t
*gtt
, igd_gtt_seg_t seg
)
693 maxpages
= gtt
->gtt_info
.igd_apersize
;
694 maxpages
= GTT_MB_TO_PAGES(maxpages
);
696 paddr
= seg
.igs_phyaddr
;
698 /* check if gtt max page number is reached */
699 if ((seg
.igs_pgstart
+ seg
.igs_npage
) > maxpages
)
702 paddr
= seg
.igs_phyaddr
;
703 for (i
= seg
.igs_pgstart
; i
< (seg
.igs_pgstart
+ seg
.igs_npage
);
705 if (phys2entry(seg
.igs_type
, *paddr
, &entry
))
707 ddi_put32(gtt
->gtt_handle
,
708 (uint32_t *)(gtt
->gtt_addr
+ i
* sizeof (uint32_t)),
716 i8xx_remove_from_gtt(gtt_impl_t
*gtt
, igd_gtt_seg_t seg
)
721 maxpages
= gtt
->gtt_info
.igd_apersize
;
722 maxpages
= GTT_MB_TO_PAGES(maxpages
);
724 /* check if gtt max page number is reached */
725 if ((seg
.igs_pgstart
+ seg
.igs_npage
) > maxpages
)
728 for (i
= seg
.igs_pgstart
; i
< (seg
.igs_pgstart
+ seg
.igs_npage
); i
++) {
729 ddi_put32(gtt
->gtt_handle
,
730 (uint32_t *)(gtt
->gtt_addr
+ i
* sizeof (uint32_t)), 0);