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 /*
2311260SMiao.Chen@Sun.COM * Copyright (c) 2009, Intel Corporation.
2411260SMiao.Chen@Sun.COM * All Rights Reserved.
2511260SMiao.Chen@Sun.COM */
2611260SMiao.Chen@Sun.COM
2711260SMiao.Chen@Sun.COM /*
288832SMiao.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
293446Smrj * Use is subject to license terms.
303446Smrj */
313446Smrj
323446Smrj /*
333446Smrj * Misc module for AGP master device support
343446Smrj */
353446Smrj
363446Smrj #include <sys/modctl.h>
373446Smrj #include <sys/pci.h>
383446Smrj #include <sys/stat.h>
393446Smrj #include <sys/file.h>
403446Smrj #include <sys/types.h>
413446Smrj #include <sys/dditypes.h>
423446Smrj #include <sys/sunddi.h>
433446Smrj #include <sys/agpgart.h>
443446Smrj #include <sys/agp/agpdefs.h>
453446Smrj #include <sys/agp/agpmaster_io.h>
463446Smrj
474478Skz151634 #define PGTBL_CTL 0x2020 /* Page table control register */
484478Skz151634 #define I8XX_FB_BAR 1
494478Skz151634 #define I8XX_MMIO_BAR 2
504478Skz151634 #define I8XX_PTE_OFFSET 0x10000
514478Skz151634 #define I915_MMADR 1 /* mem-mapped registers BAR */
524478Skz151634 #define I915_GMADR 3 /* graphics mem BAR */
534478Skz151634 #define I915_GTTADDR 4 /* GTT BAR */
544478Skz151634 #define I965_GTTMMADR 1 /* mem-mapped registers BAR + GTT */
554478Skz151634 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */
564478Skz151634 #define I965_GTT_OFFSET 0x80000
576778Smc196098 #define GM45_GTT_OFFSET 0x200000
584478Skz151634 #define GTT_SIZE_MASK 0xe
594478Skz151634 #define GTT_512KB (0 << 1)
604478Skz151634 #define GTT_256KB (1 << 1)
614478Skz151634 #define GTT_128KB (2 << 1)
626778Smc196098 #define GTT_1MB (3 << 1)
636778Smc196098 #define GTT_2MB (4 << 1)
646778Smc196098 #define GTT_1_5MB (5 << 1)
654478Skz151634
664478Skz151634 #define MMIO_BASE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_base
674478Skz151634 #define MMIO_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_handle
685036Skz151634 #define GTT_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_handle
695036Skz151634 /* Base address of GTT */
704478Skz151634 #define GTT_ADDR(x) (x)->agpm_data.agpm_gtt.gtt_addr
715036Skz151634 /* Graphics memory base address */
724478Skz151634 #define APER_BASE(x) (x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase
734478Skz151634
744478Skz151634 #define AGPM_WRITE(x, off, val) \
754478Skz151634 ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val));
764478Skz151634
774478Skz151634 #define AGPM_READ(x, off) \
784478Skz151634 ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)));
793446Smrj
803446Smrj #ifdef DEBUG
813446Smrj #define CONFIRM(value) ASSERT(value)
823446Smrj #else
833446Smrj #define CONFIRM(value) if (!(value)) return (EINVAL)
843446Smrj #endif
853446Smrj
863446Smrj int agpm_debug = 0;
873446Smrj #define AGPM_DEBUG(args) if (agpm_debug >= 1) cmn_err args
883446Smrj
893446Smrj /*
903446Smrj * Whether it is a Intel integrated graphics card
913446Smrj */
923446Smrj #define IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \
934478Skz151634 (agpmaster->agpm_dev_type == DEVICE_IS_I830))
943446Smrj
953446Smrj static struct modlmisc modlmisc = {
967542SRichard.Bean@Sun.COM &mod_miscops, "AGP master interfaces"
973446Smrj };
983446Smrj
993446Smrj static struct modlinkage modlinkage = {
1003446Smrj MODREV_1, (void *)&modlmisc, NULL
1013446Smrj };
1023446Smrj
1033446Smrj static ddi_device_acc_attr_t i8xx_dev_access = {
1043446Smrj DDI_DEVICE_ATTR_V0,
1053446Smrj DDI_NEVERSWAP_ACC,
1063446Smrj DDI_STRICTORDER_ACC
1073446Smrj };
1083446Smrj
1093446Smrj static off_t agpmaster_cap_find(ddi_acc_handle_t);
1103446Smrj static int detect_i8xx_device(agp_master_softc_t *);
1113446Smrj static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t);
1123446Smrj static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t);
1133446Smrj static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t);
1143446Smrj
1153446Smrj int
_init(void)1163446Smrj _init(void)
1173446Smrj {
1183446Smrj int err;
1193446Smrj
1203446Smrj if ((err = mod_install(&modlinkage)) != 0)
1213446Smrj return (err);
1223446Smrj
1233446Smrj return (0);
1243446Smrj }
1253446Smrj
1263446Smrj int
_fini(void)1273446Smrj _fini(void)
1283446Smrj {
1293446Smrj int err;
1303446Smrj
1313446Smrj if ((err = mod_remove(&modlinkage)) != 0)
1323446Smrj return (err);
1333446Smrj
1343446Smrj return (0);
1353446Smrj }
1363446Smrj
1373446Smrj int
_info(struct modinfo * modinfop)1383446Smrj _info(struct modinfo *modinfop)
1393446Smrj {
1403446Smrj return (mod_info(&modlinkage, modinfop));
1413446Smrj }
1423446Smrj
1433446Smrj /*
1443446Smrj * Minor node is not removed here, since the caller (xx_attach) is
1453446Smrj * responsible for removing all nodes.
1463446Smrj */
1473446Smrj void
agpmaster_detach(agp_master_softc_t ** master_softcp)1483446Smrj agpmaster_detach(agp_master_softc_t **master_softcp)
1493446Smrj {
1503446Smrj agp_master_softc_t *master_softc;
1513446Smrj
1523446Smrj ASSERT(master_softcp);
1533446Smrj master_softc = *master_softcp;
1543446Smrj
1553446Smrj /* intel integrated device */
1565036Skz151634 if (IS_IGD(master_softc) &&
1575036Skz151634 ((MMIO_HANDLE(master_softc) != NULL) ||
1585036Skz151634 (GTT_HANDLE(master_softc) != NULL))) {
1595036Skz151634 /*
1605036Skz151634 * for some chipsets, mmap handle is shared between both mmio
1615036Skz151634 * and GTT table.
1625036Skz151634 */
1635036Skz151634 if ((GTT_HANDLE(master_softc) != MMIO_HANDLE(master_softc)) &&
1645036Skz151634 (GTT_HANDLE(master_softc) != NULL))
1655036Skz151634 ddi_regs_map_free(>T_HANDLE(master_softc));
1665036Skz151634 if (MMIO_HANDLE(master_softc) != NULL)
1674478Skz151634 ddi_regs_map_free(&MMIO_HANDLE(master_softc));
1683446Smrj }
1693446Smrj
1703446Smrj kmem_free(master_softc, sizeof (agp_master_softc_t));
1713446Smrj master_softc = NULL;
1723446Smrj
1733446Smrj return;
1743446Smrj
1753446Smrj }
1763446Smrj
1773446Smrj /*
1784478Skz151634 * 965 has a fixed GTT table size (512KB), so check to see the actual aperture
1794478Skz151634 * size. Aperture size = GTT table size * 1024.
1804478Skz151634 */
1814478Skz151634 static off_t
i965_apersize(agp_master_softc_t * agpmaster)1824478Skz151634 i965_apersize(agp_master_softc_t *agpmaster)
1834478Skz151634 {
1844478Skz151634 off_t apersize;
1854478Skz151634
1864478Skz151634 apersize = AGPM_READ(agpmaster, PGTBL_CTL);
1874478Skz151634 AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize));
1884478Skz151634 switch (apersize & GTT_SIZE_MASK) {
1896778Smc196098 case GTT_2MB:
1906778Smc196098 apersize = 2048;
1916778Smc196098 break;
1926778Smc196098 case GTT_1_5MB:
1936778Smc196098 apersize = 1536;
1946778Smc196098 break;
1956778Smc196098 case GTT_1MB:
1966778Smc196098 apersize = 1024;
1976778Smc196098 break;
1984478Skz151634 case GTT_512KB:
1994478Skz151634 apersize = 512;
2004478Skz151634 break;
2014478Skz151634 case GTT_256KB:
2024478Skz151634 apersize = 256;
2034478Skz151634 break;
2044478Skz151634 case GTT_128KB:
2054478Skz151634 apersize = 128;
2064478Skz151634 break;
2074478Skz151634 default:
2085036Skz151634 apersize = 0;
2094478Skz151634 AGPM_DEBUG((CE_WARN,
2104478Skz151634 "i965_apersize: invalid GTT size in PGTBL_CTL"));
2114478Skz151634 }
2125036Skz151634 return (apersize);
2135036Skz151634 }
2145036Skz151634
2155036Skz151634 /*
2165036Skz151634 * For Intel 3 series, we need to get GTT size from the GGMS field in GMCH
2175036Skz151634 * Graphics Control Register. Return aperture size in MB.
2185036Skz151634 */
2195036Skz151634 static off_t
i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)2205036Skz151634 i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)
2215036Skz151634 {
2225036Skz151634 uint16_t value;
2235036Skz151634 off_t apersize;
2245036Skz151634
2255036Skz151634 /*
2265036Skz151634 * Get the value of configuration register MGGC "Mirror of Dev0 GMCH
2275036Skz151634 * Graphics Control" from Internal Graphics #2 (Device2:Function0).
2285036Skz151634 */
2295036Skz151634 value = pci_config_get16(pci_acc_hdl, I8XX_CONF_GC);
2305036Skz151634 AGPM_DEBUG((CE_NOTE, "i3XX_apersize: MGGC = 0x%x", value));
2315036Skz151634 /* computing aperture size using the pre-allocated GTT size */
2325036Skz151634 switch (value & IX33_GGMS_MASK) {
2335036Skz151634 case IX33_GGMS_1M:
2345036Skz151634 apersize = 1024;
2355036Skz151634 break;
2365036Skz151634 case IX33_GGMS_2M:
2375036Skz151634 apersize = 2048;
2385036Skz151634 break;
2395036Skz151634 default:
2405036Skz151634 apersize = 0; /* no memory pre-allocated */
2415036Skz151634 AGPM_DEBUG((CE_WARN,
2425036Skz151634 "i3XX_apersize: no memory allocated for GTT"));
2435036Skz151634 }
2445036Skz151634 AGPM_DEBUG((CE_NOTE, "i3xx_apersize: apersize = %ldM", apersize));
2454478Skz151634 return (apersize);
2464478Skz151634 }
2474478Skz151634
2484478Skz151634 #define CHECK_STATUS(status) \
2494478Skz151634 if (status != DDI_SUCCESS) { \
2504478Skz151634 AGPM_DEBUG((CE_WARN, \
2514478Skz151634 "set_gtt_mmio: regs_map_setup error")); \
2524478Skz151634 return (-1); \
2534478Skz151634 }
2544478Skz151634 /*
2554478Skz151634 * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid
2564478Skz151634 * according to chipset.
2574478Skz151634 */
2584478Skz151634 static int
set_gtt_mmio(dev_info_t * devi,agp_master_softc_t * agpmaster,ddi_acc_handle_t pci_acc_hdl)2595036Skz151634 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster,
2605036Skz151634 ddi_acc_handle_t pci_acc_hdl)
2614478Skz151634 {
2625036Skz151634 off_t apersize; /* size of graphics mem (MB) == GTT size (KB) */
2634478Skz151634 uint32_t value;
2645036Skz151634 off_t gmadr_off; /* GMADR offset in PCI config space */
2654478Skz151634 int status;
2664478Skz151634
26711260SMiao.Chen@Sun.COM if (IS_INTEL_X33(agpmaster->agpm_id)) {
2685036Skz151634 /* Intel 3 series are similar with 915/945 series */
2694478Skz151634 status = ddi_regs_map_setup(devi, I915_GTTADDR,
2704478Skz151634 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
2715036Skz151634 >T_HANDLE(agpmaster));
2724478Skz151634 CHECK_STATUS(status);
2734478Skz151634
2744478Skz151634 status = ddi_regs_map_setup(devi, I915_MMADR,
2754478Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
2764478Skz151634 &MMIO_HANDLE(agpmaster));
2774478Skz151634 CHECK_STATUS(status);
2784478Skz151634
2796110Sms148562 gmadr_off = I915_CONF_GMADR;
2806110Sms148562 /* Different computing method used in getting aperture size. */
2815036Skz151634 apersize = i3XX_apersize(pci_acc_hdl);
28211260SMiao.Chen@Sun.COM } else if (IS_INTEL_965(agpmaster->agpm_id)) {
2835036Skz151634 status = ddi_regs_map_setup(devi, I965_GTTMMADR,
2845036Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
2855036Skz151634 &MMIO_HANDLE(agpmaster));
2865036Skz151634 CHECK_STATUS(status);
2877662SMiao.Chen@Sun.COM if ((agpmaster->agpm_id == INTEL_IGD_GM45) ||
28811260SMiao.Chen@Sun.COM IS_INTEL_G4X(agpmaster->agpm_id))
2896778Smc196098 GTT_ADDR(agpmaster) =
2906778Smc196098 MMIO_BASE(agpmaster) + GM45_GTT_OFFSET;
2916778Smc196098 else
2926778Smc196098 GTT_ADDR(agpmaster) =
2936778Smc196098 MMIO_BASE(agpmaster) + I965_GTT_OFFSET;
2945036Skz151634 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
2955036Skz151634
2965036Skz151634 gmadr_off = I915_CONF_GMADR;
2975036Skz151634 apersize = i965_apersize(agpmaster);
29811260SMiao.Chen@Sun.COM } else if (IS_INTEL_915(agpmaster->agpm_id)) {
2995036Skz151634 /* I915/945 series */
3005036Skz151634 status = ddi_regs_map_setup(devi, I915_GTTADDR,
3015036Skz151634 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
3025036Skz151634 >T_HANDLE(agpmaster));
3035036Skz151634 CHECK_STATUS(status);
3045036Skz151634
3055036Skz151634 status = ddi_regs_map_setup(devi, I915_MMADR,
3065036Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
3075036Skz151634 &MMIO_HANDLE(agpmaster));
3085036Skz151634 CHECK_STATUS(status);
3095036Skz151634
3105036Skz151634 gmadr_off = I915_CONF_GMADR;
3114478Skz151634 status = ddi_dev_regsize(devi, I915_GMADR, &apersize);
3125036Skz151634 apersize = BYTES2MB(apersize);
3134478Skz151634 } else {
3144478Skz151634 /* I8XX series */
3154478Skz151634 status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR,
3164478Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
3174478Skz151634 &MMIO_HANDLE(agpmaster));
3184478Skz151634 CHECK_STATUS(status);
3194478Skz151634
3204478Skz151634 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET;
3215036Skz151634 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
3225036Skz151634 gmadr_off = I8XX_CONF_GMADR;
3234478Skz151634 status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize);
3245036Skz151634 apersize = BYTES2MB(apersize);
3254478Skz151634 CHECK_STATUS(status);
3264478Skz151634 }
3274478Skz151634
3284478Skz151634 /*
3295036Skz151634 * If memory size is smaller than a certain value, it means
3304478Skz151634 * the register set number for graphics memory range might
3314478Skz151634 * be wrong
3324478Skz151634 */
3335036Skz151634 if (status != DDI_SUCCESS || apersize < 4) {
3344478Skz151634 AGPM_DEBUG((CE_WARN,
3355036Skz151634 "set_gtt_mmio: error in getting graphics memory"));
3364478Skz151634 return (-1);
3374478Skz151634 }
3384478Skz151634
3395036Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = apersize;
3404478Skz151634
3415036Skz151634 /* get graphics memory base address from GMADR */
3425036Skz151634 value = pci_config_get32(pci_acc_hdl, gmadr_off);
3434478Skz151634 APER_BASE(agpmaster) = value & GTT_BASE_MASK;
3445036Skz151634 AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = 0x%x, apersize = %ldM, "
3454478Skz151634 "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize,
3464478Skz151634 (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster)));
3474478Skz151634 return (0);
3484478Skz151634 }
3494478Skz151634
3504478Skz151634 /*
3513446Smrj * Try to initialize agp master.
3523446Smrj * 0 is returned if the device is successfully initialized. AGP master soft
3533446Smrj * state is returned in master_softcp if needed.
3543446Smrj * Otherwise -1 is returned and *master_softcp is set to NULL.
3553446Smrj */
3563446Smrj int
agpmaster_attach(dev_info_t * devi,agp_master_softc_t ** master_softcp,ddi_acc_handle_t pci_acc_hdl,minor_t minor)3573446Smrj agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp,
3583446Smrj ddi_acc_handle_t pci_acc_hdl, minor_t minor)
3593446Smrj {
3603446Smrj int instance;
3613446Smrj int status;
3623446Smrj agp_master_softc_t *agpmaster;
3633446Smrj char buf[80];
3643446Smrj
3653446Smrj
3663446Smrj ASSERT(pci_acc_hdl);
3673446Smrj *master_softcp = NULL;
3683446Smrj agpmaster = (agp_master_softc_t *)
3693446Smrj kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP);
3703446Smrj
3713446Smrj agpmaster->agpm_id =
3723446Smrj pci_config_get32(pci_acc_hdl, PCI_CONF_VENID);
3733446Smrj agpmaster->agpm_acc_hdl = pci_acc_hdl;
3743446Smrj
3753446Smrj if (!detect_i8xx_device(agpmaster)) {
3764478Skz151634 /* Intel 8XX, 915, 945 and 965 series */
3774478Skz151634 if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0)
3783446Smrj goto fail;
3793446Smrj } else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) {
3804478Skz151634 /* non IGD or AGP devices, AMD64 gart */
3813446Smrj AGPM_DEBUG((CE_WARN,
3823446Smrj "agpmaster_attach: neither IGD or AGP devices exists"));
3833446Smrj agpmaster_detach(&agpmaster);
3843446Smrj return (0);
3853446Smrj }
3863446Smrj
3875036Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid =
3885036Skz151634 agpmaster->agpm_id;
3895036Skz151634
3903446Smrj /* create minor node for IGD or AGP device */
3913446Smrj instance = ddi_get_instance(devi);
3923446Smrj
3933446Smrj (void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance);
3943446Smrj status = ddi_create_minor_node(devi, buf, S_IFCHR, minor,
3953446Smrj DDI_NT_AGP_MASTER, 0);
3963446Smrj
3973446Smrj if (status != DDI_SUCCESS) {
3983446Smrj AGPM_DEBUG((CE_WARN,
3993446Smrj "agpmaster_attach: create agpmaster node failed"));
4003446Smrj goto fail;
4013446Smrj }
4023446Smrj
4033446Smrj *master_softcp = agpmaster;
4043446Smrj return (0);
4053446Smrj fail:
4063446Smrj agpmaster_detach(&agpmaster);
4073446Smrj return (-1);
4083446Smrj }
4093446Smrj
4103446Smrj /*
4113446Smrj * Currently, it handles ioctl requests related with agp master device for
4123446Smrj * layered driver (agpgart) only.
4133446Smrj */
4143446Smrj /*ARGSUSED*/
4153446Smrj int
agpmaster_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval,agp_master_softc_t * softc)4163446Smrj agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred,
4173446Smrj int *rval, agp_master_softc_t *softc)
4183446Smrj {
4193446Smrj uint32_t base;
4203446Smrj uint32_t addr;
4213446Smrj igd_gtt_seg_t seg;
4223446Smrj agp_info_t info;
4233446Smrj uint32_t value;
4243446Smrj off_t cap;
4253446Smrj uint32_t command;
4263446Smrj static char kernel_only[] =
4273446Smrj "agpmaster_ioctl: %s is a kernel only ioctl";
4283446Smrj
4293446Smrj CONFIRM(softc);
4303446Smrj
4313446Smrj switch (cmd) {
4323446Smrj case DEVICE_DETECT:
4333446Smrj if (!(mode & FKIOCTL)) {
4343446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT"));
4353446Smrj return (ENXIO);
4363446Smrj }
4373446Smrj
4383446Smrj if (ddi_copyout(&softc->agpm_dev_type,
4393446Smrj (void *)data, sizeof (int), mode))
4403446Smrj return (EFAULT);
4413446Smrj break;
4423446Smrj case AGP_MASTER_SETCMD:
4433446Smrj if (!(mode & FKIOCTL)) {
4443446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD"));
4453446Smrj return (ENXIO);
4463446Smrj }
4473446Smrj
4483446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
4493446Smrj CONFIRM(softc->agpm_data.agpm_acaptr);
4503446Smrj
4513446Smrj if (ddi_copyin((void *)data, &command,
4523446Smrj sizeof (uint32_t), mode))
4533446Smrj return (EFAULT);
4543446Smrj
4553446Smrj pci_config_put32(softc->agpm_acc_hdl,
4563446Smrj softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND,
4573446Smrj command);
4583446Smrj break;
4593446Smrj case AGP_MASTER_GETINFO:
4603446Smrj if (!(mode & FKIOCTL)) {
4613446Smrj AGPM_DEBUG((CE_CONT, kernel_only,
4623446Smrj "AGP_MASTER_GETINFO"));
4633446Smrj return (ENXIO);
4643446Smrj }
4653446Smrj
4663446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
4673446Smrj CONFIRM(softc->agpm_data.agpm_acaptr);
4683446Smrj
4693446Smrj cap = softc->agpm_data.agpm_acaptr;
4703446Smrj value = pci_config_get32(softc->agpm_acc_hdl, cap);
4713446Smrj info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf);
4723446Smrj info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf);
4733446Smrj info.agpi_devid = softc->agpm_id;
4743446Smrj info.agpi_mode = pci_config_get32(
4753446Smrj softc->agpm_acc_hdl, cap + AGP_CONF_STATUS);
4763446Smrj
4773446Smrj if (ddi_copyout(&info, (void *)data,
4783446Smrj sizeof (agp_info_t), mode))
4793446Smrj return (EFAULT);
4803446Smrj break;
4813446Smrj case I810_SET_GTT_BASE:
4823446Smrj if (!(mode & FKIOCTL)) {
4833446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR"));
4843446Smrj return (ENXIO);
4853446Smrj }
4863446Smrj
4873446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810);
4883446Smrj
4893446Smrj if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode))
4903446Smrj return (EFAULT);
4913446Smrj
4923446Smrj /* enables page table */
4933446Smrj addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID;
4943446Smrj
4954478Skz151634 AGPM_WRITE(softc, PGTBL_CTL, addr);
4963446Smrj break;
4973446Smrj case I8XX_GET_INFO:
4983446Smrj if (!(mode & FKIOCTL)) {
4993446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO"));
5003446Smrj return (ENXIO);
5013446Smrj }
5023446Smrj
5033446Smrj CONFIRM(IS_IGD(softc));
5043446Smrj
5053446Smrj if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info,
5063446Smrj (void *)data, sizeof (igd_info_t), mode))
5073446Smrj return (EFAULT);
5083446Smrj break;
5093446Smrj case I8XX_ADD2GTT:
5103446Smrj if (!(mode & FKIOCTL)) {
5113446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT"));
5123446Smrj return (ENXIO);
5133446Smrj }
5143446Smrj
5153446Smrj CONFIRM(IS_IGD(softc));
5163446Smrj
5173446Smrj if (ddi_copyin((void *)data, &seg,
5183446Smrj sizeof (igd_gtt_seg_t), mode))
5193446Smrj return (EFAULT);
5203446Smrj
5213446Smrj if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg))
5223446Smrj return (EINVAL);
5233446Smrj break;
5243446Smrj case I8XX_REM_GTT:
5253446Smrj if (!(mode & FKIOCTL)) {
5263446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT"));
5273446Smrj return (ENXIO);
5283446Smrj }
5293446Smrj
5303446Smrj CONFIRM(IS_IGD(softc));
5313446Smrj
5323446Smrj if (ddi_copyin((void *)data, &seg,
5333446Smrj sizeof (igd_gtt_seg_t), mode))
5343446Smrj return (EFAULT);
5353446Smrj
5363446Smrj i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg);
5373446Smrj break;
5383446Smrj case I8XX_UNCONFIG:
5393446Smrj if (!(mode & FKIOCTL)) {
5403446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG"));
5413446Smrj return (ENXIO);
5423446Smrj }
5433446Smrj
5443446Smrj CONFIRM(IS_IGD(softc));
5453446Smrj
5463446Smrj if (softc->agpm_dev_type == DEVICE_IS_I810)
5474478Skz151634 AGPM_WRITE(softc, PGTBL_CTL, 0);
5483446Smrj /*
5493446Smrj * may need to clear all gtt entries here for i830 series,
5503446Smrj * but may not be necessary
5513446Smrj */
5523446Smrj break;
5533446Smrj }
5543446Smrj return (0);
5553446Smrj }
5563446Smrj
5573446Smrj /*
5583446Smrj * If AGP cap pointer is successfully found, none-zero value is returned.
5593446Smrj * Otherwise 0 is returned.
5603446Smrj */
5613446Smrj static off_t
agpmaster_cap_find(ddi_acc_handle_t acc_handle)5623446Smrj agpmaster_cap_find(ddi_acc_handle_t acc_handle)
5633446Smrj {
5643446Smrj off_t nextcap;
5653446Smrj uint32_t ncapid;
5663446Smrj uint8_t value;
5673446Smrj
5683446Smrj /* check if this device supports capibility pointer */
5693446Smrj value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT)
5704303Skz151634 & PCI_CONF_CAP_MASK);
5713446Smrj
5723446Smrj if (!value)
5733446Smrj return (0);
5743446Smrj /* get the offset of the first capability pointer from CAPPTR */
5753446Smrj nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR));
5763446Smrj
5773446Smrj /* check AGP capability from the first capability pointer */
5783446Smrj while (nextcap) {
5793446Smrj ncapid = pci_config_get32(acc_handle, nextcap);
5803446Smrj if ((ncapid & PCI_CONF_CAPID_MASK)
5813446Smrj == AGP_CAP_ID) /* find AGP cap */
5823446Smrj break;
5833446Smrj
5843446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
5853446Smrj }
5863446Smrj
5873446Smrj return (nextcap);
5883446Smrj
5893446Smrj }
5903446Smrj
5913446Smrj /*
5923446Smrj * If i8xx device is successfully detected, 0 is returned.
5933446Smrj * Otherwise -1 is returned.
5943446Smrj */
5953446Smrj static int
detect_i8xx_device(agp_master_softc_t * master_softc)5963446Smrj detect_i8xx_device(agp_master_softc_t *master_softc)
5973446Smrj {
5983446Smrj
5993446Smrj switch (master_softc->agpm_id) {
6003446Smrj case INTEL_IGD_810:
6013446Smrj case INTEL_IGD_810DC:
6023446Smrj case INTEL_IGD_810E:
6033446Smrj case INTEL_IGD_815:
6043446Smrj master_softc->agpm_dev_type = DEVICE_IS_I810;
6053446Smrj break;
6063446Smrj case INTEL_IGD_830M:
6073446Smrj case INTEL_IGD_845G:
6083446Smrj case INTEL_IGD_855GM:
6093446Smrj case INTEL_IGD_865G:
6104478Skz151634 case INTEL_IGD_915:
6114478Skz151634 case INTEL_IGD_915GM:
6123446Smrj case INTEL_IGD_945:
6134303Skz151634 case INTEL_IGD_945GM:
6148020SMiao.Chen@Sun.COM case INTEL_IGD_945GME:
6154478Skz151634 case INTEL_IGD_946GZ:
6164478Skz151634 case INTEL_IGD_965G1:
6174478Skz151634 case INTEL_IGD_965G2:
6184478Skz151634 case INTEL_IGD_965GM:
6194618Skz151634 case INTEL_IGD_965GME:
6204478Skz151634 case INTEL_IGD_965Q:
6215036Skz151634 case INTEL_IGD_Q35:
6225036Skz151634 case INTEL_IGD_G33:
6235036Skz151634 case INTEL_IGD_Q33:
6246778Smc196098 case INTEL_IGD_GM45:
6257662SMiao.Chen@Sun.COM case INTEL_IGD_EL:
6267662SMiao.Chen@Sun.COM case INTEL_IGD_Q45:
6277662SMiao.Chen@Sun.COM case INTEL_IGD_G45:
6288832SMiao.Chen@Sun.COM case INTEL_IGD_G41:
629*11359SMiao.Chen@Sun.COM case INTEL_IGD_IGDNG_D:
630*11359SMiao.Chen@Sun.COM case INTEL_IGD_IGDNG_M:
63111260SMiao.Chen@Sun.COM case INTEL_IGD_B43:
6323446Smrj master_softc->agpm_dev_type = DEVICE_IS_I830;
6333446Smrj break;
6343446Smrj default: /* unknown id */
6353446Smrj return (-1);
6363446Smrj }
6373446Smrj
6383446Smrj return (0);
6393446Smrj }
6403446Smrj
6413446Smrj /*
6423446Smrj * If agp master is succssfully detected, 0 is returned.
6433446Smrj * Otherwise -1 is returned.
6443446Smrj */
6453446Smrj static int
detect_agp_devcice(agp_master_softc_t * master_softc,ddi_acc_handle_t acc_handle)6463446Smrj detect_agp_devcice(agp_master_softc_t *master_softc,
6473446Smrj ddi_acc_handle_t acc_handle)
6483446Smrj {
6493446Smrj off_t cap;
6503446Smrj
6513446Smrj cap = agpmaster_cap_find(acc_handle);
6523446Smrj if (cap) {
6533446Smrj master_softc->agpm_dev_type = DEVICE_IS_AGP;
6543446Smrj master_softc->agpm_data.agpm_acaptr = cap;
6553446Smrj return (0);
6563446Smrj } else {
6573446Smrj return (-1);
6583446Smrj }
6593446Smrj
6603446Smrj }
6613446Smrj
6623446Smrj /*
6633446Smrj * Please refer to GART and GTT entry format table in agpdefs.h for
6643446Smrj * intel GTT entry format.
6653446Smrj */
6663446Smrj static int
phys2entry(uint32_t type,uint32_t physaddr,uint32_t * entry)6673446Smrj phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry)
6683446Smrj {
6693446Smrj uint32_t value;
6703446Smrj
6713446Smrj switch (type) {
6723446Smrj case AGP_PHYSICAL:
6733446Smrj case AGP_NORMAL:
6743446Smrj value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID;
6753446Smrj break;
6763446Smrj default:
6773446Smrj return (-1);
6783446Smrj }
6793446Smrj
6803446Smrj *entry = value;
6813446Smrj
6823446Smrj return (0);
6833446Smrj }
6843446Smrj
6853446Smrj static int
i8xx_add_to_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)6863446Smrj i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
6873446Smrj {
6883446Smrj int i;
6893446Smrj uint32_t *paddr;
6903446Smrj uint32_t entry;
6913446Smrj uint32_t maxpages;
6923446Smrj
6933446Smrj maxpages = gtt->gtt_info.igd_apersize;
6943446Smrj maxpages = GTT_MB_TO_PAGES(maxpages);
6953446Smrj
6963446Smrj paddr = seg.igs_phyaddr;
6973446Smrj
6983446Smrj /* check if gtt max page number is reached */
6993446Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
7003446Smrj return (-1);
7013446Smrj
7023446Smrj paddr = seg.igs_phyaddr;
7033446Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
7043446Smrj i++, paddr++) {
7053446Smrj if (phys2entry(seg.igs_type, *paddr, &entry))
7063446Smrj return (-1);
7075036Skz151634 ddi_put32(gtt->gtt_handle,
7083446Smrj (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
7093446Smrj entry);
7103446Smrj }
7113446Smrj
7123446Smrj return (0);
7133446Smrj }
7143446Smrj
7153446Smrj static void
i8xx_remove_from_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)7163446Smrj i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
7173446Smrj {
7183446Smrj int i;
7193446Smrj uint32_t maxpages;
7203446Smrj
7213446Smrj maxpages = gtt->gtt_info.igd_apersize;
7223446Smrj maxpages = GTT_MB_TO_PAGES(maxpages);
7233446Smrj
7243446Smrj /* check if gtt max page number is reached */
7253446Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
7263446Smrj return;
7273446Smrj
7283446Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) {
7295036Skz151634 ddi_put32(gtt->gtt_handle,
7304478Skz151634 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 0);
7313446Smrj }
7323446Smrj }
733