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 /* 23*8832SMiao.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 243446Smrj * Use is subject to license terms. 253446Smrj */ 263446Smrj 273446Smrj /* 283446Smrj * Misc module for AGP master device support 293446Smrj */ 303446Smrj 313446Smrj #include <sys/modctl.h> 323446Smrj #include <sys/pci.h> 333446Smrj #include <sys/stat.h> 343446Smrj #include <sys/file.h> 353446Smrj #include <sys/types.h> 363446Smrj #include <sys/dditypes.h> 373446Smrj #include <sys/sunddi.h> 383446Smrj #include <sys/agpgart.h> 393446Smrj #include <sys/agp/agpdefs.h> 403446Smrj #include <sys/agp/agpmaster_io.h> 413446Smrj 424478Skz151634 #define PGTBL_CTL 0x2020 /* Page table control register */ 434478Skz151634 #define I8XX_FB_BAR 1 444478Skz151634 #define I8XX_MMIO_BAR 2 454478Skz151634 #define I8XX_PTE_OFFSET 0x10000 464478Skz151634 #define I915_MMADR 1 /* mem-mapped registers BAR */ 474478Skz151634 #define I915_GMADR 3 /* graphics mem BAR */ 484478Skz151634 #define I915_GTTADDR 4 /* GTT BAR */ 494478Skz151634 #define I965_GTTMMADR 1 /* mem-mapped registers BAR + GTT */ 504478Skz151634 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */ 514478Skz151634 #define I965_GTT_OFFSET 0x80000 526778Smc196098 #define GM45_GTT_OFFSET 0x200000 534478Skz151634 #define GTT_SIZE_MASK 0xe 544478Skz151634 #define GTT_512KB (0 << 1) 554478Skz151634 #define GTT_256KB (1 << 1) 564478Skz151634 #define GTT_128KB (2 << 1) 576778Smc196098 #define GTT_1MB (3 << 1) 586778Smc196098 #define GTT_2MB (4 << 1) 596778Smc196098 #define GTT_1_5MB (5 << 1) 604478Skz151634 614478Skz151634 #define MMIO_BASE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_base 624478Skz151634 #define MMIO_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_handle 635036Skz151634 #define GTT_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_handle 645036Skz151634 /* Base address of GTT */ 654478Skz151634 #define GTT_ADDR(x) (x)->agpm_data.agpm_gtt.gtt_addr 665036Skz151634 /* Graphics memory base address */ 674478Skz151634 #define APER_BASE(x) (x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase 684478Skz151634 694478Skz151634 #define AGPM_WRITE(x, off, val) \ 704478Skz151634 ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val)); 714478Skz151634 724478Skz151634 #define AGPM_READ(x, off) \ 734478Skz151634 ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off))); 743446Smrj 753446Smrj #ifdef DEBUG 763446Smrj #define CONFIRM(value) ASSERT(value) 773446Smrj #else 783446Smrj #define CONFIRM(value) if (!(value)) return (EINVAL) 793446Smrj #endif 803446Smrj 813446Smrj int agpm_debug = 0; 823446Smrj #define AGPM_DEBUG(args) if (agpm_debug >= 1) cmn_err args 833446Smrj 843446Smrj /* 853446Smrj * Whether it is a Intel integrated graphics card 863446Smrj */ 873446Smrj #define IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \ 884478Skz151634 (agpmaster->agpm_dev_type == DEVICE_IS_I830)) 893446Smrj 903446Smrj 914478Skz151634 /* Intel 915 and 945 series */ 924478Skz151634 #define IS_INTEL_915(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_915) || \ 934478Skz151634 (agpmaster->agpm_id == INTEL_IGD_915GM) || \ 944478Skz151634 (agpmaster->agpm_id == INTEL_IGD_945) || \ 958020SMiao.Chen@Sun.COM (agpmaster->agpm_id == INTEL_IGD_945GM) || \ 968020SMiao.Chen@Sun.COM (agpmaster->agpm_id == INTEL_IGD_945GME)) 974478Skz151634 984478Skz151634 /* Intel 965 series */ 994478Skz151634 #define IS_INTEL_965(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_946GZ) || \ 1004478Skz151634 (agpmaster->agpm_id == INTEL_IGD_965G1) || \ 1014478Skz151634 (agpmaster->agpm_id == INTEL_IGD_965Q) || \ 1024478Skz151634 (agpmaster->agpm_id == INTEL_IGD_965G2) || \ 1034618Skz151634 (agpmaster->agpm_id == INTEL_IGD_965GM) || \ 1046778Smc196098 (agpmaster->agpm_id == INTEL_IGD_965GME) || \ 1057662SMiao.Chen@Sun.COM (agpmaster->agpm_id == INTEL_IGD_GM45) || \ 1067662SMiao.Chen@Sun.COM IS_INTEL_G4X(agpmaster)) 1073446Smrj 1085036Skz151634 /* Intel G33 series */ 1095036Skz151634 #define IS_INTEL_X33(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_Q35) || \ 1105036Skz151634 (agpmaster->agpm_id == INTEL_IGD_G33) || \ 1115036Skz151634 (agpmaster->agpm_id == INTEL_IGD_Q33)) 1125036Skz151634 1137662SMiao.Chen@Sun.COM /* Intel G4X series */ 1147662SMiao.Chen@Sun.COM #define IS_INTEL_G4X(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_EL) || \ 1157662SMiao.Chen@Sun.COM (agpmaster->agpm_id == INTEL_IGD_Q45) || \ 116*8832SMiao.Chen@Sun.COM (agpmaster->agpm_id == INTEL_IGD_G45) || \ 117*8832SMiao.Chen@Sun.COM (agpmaster->agpm_id == INTEL_IGD_G41)) 1185036Skz151634 1193446Smrj static struct modlmisc modlmisc = { 1207542SRichard.Bean@Sun.COM &mod_miscops, "AGP master interfaces" 1213446Smrj }; 1223446Smrj 1233446Smrj static struct modlinkage modlinkage = { 1243446Smrj MODREV_1, (void *)&modlmisc, NULL 1253446Smrj }; 1263446Smrj 1273446Smrj static ddi_device_acc_attr_t i8xx_dev_access = { 1283446Smrj DDI_DEVICE_ATTR_V0, 1293446Smrj DDI_NEVERSWAP_ACC, 1303446Smrj DDI_STRICTORDER_ACC 1313446Smrj }; 1323446Smrj 1333446Smrj static off_t agpmaster_cap_find(ddi_acc_handle_t); 1343446Smrj static int detect_i8xx_device(agp_master_softc_t *); 1353446Smrj static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t); 1363446Smrj static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t); 1373446Smrj static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t); 1383446Smrj 1393446Smrj int 1403446Smrj _init(void) 1413446Smrj { 1423446Smrj int err; 1433446Smrj 1443446Smrj if ((err = mod_install(&modlinkage)) != 0) 1453446Smrj return (err); 1463446Smrj 1473446Smrj return (0); 1483446Smrj } 1493446Smrj 1503446Smrj int 1513446Smrj _fini(void) 1523446Smrj { 1533446Smrj int err; 1543446Smrj 1553446Smrj if ((err = mod_remove(&modlinkage)) != 0) 1563446Smrj return (err); 1573446Smrj 1583446Smrj return (0); 1593446Smrj } 1603446Smrj 1613446Smrj int 1623446Smrj _info(struct modinfo *modinfop) 1633446Smrj { 1643446Smrj return (mod_info(&modlinkage, modinfop)); 1653446Smrj } 1663446Smrj 1673446Smrj /* 1683446Smrj * Minor node is not removed here, since the caller (xx_attach) is 1693446Smrj * responsible for removing all nodes. 1703446Smrj */ 1713446Smrj void 1723446Smrj agpmaster_detach(agp_master_softc_t **master_softcp) 1733446Smrj { 1743446Smrj agp_master_softc_t *master_softc; 1753446Smrj 1763446Smrj ASSERT(master_softcp); 1773446Smrj master_softc = *master_softcp; 1783446Smrj 1793446Smrj /* intel integrated device */ 1805036Skz151634 if (IS_IGD(master_softc) && 1815036Skz151634 ((MMIO_HANDLE(master_softc) != NULL) || 1825036Skz151634 (GTT_HANDLE(master_softc) != NULL))) { 1835036Skz151634 /* 1845036Skz151634 * for some chipsets, mmap handle is shared between both mmio 1855036Skz151634 * and GTT table. 1865036Skz151634 */ 1875036Skz151634 if ((GTT_HANDLE(master_softc) != MMIO_HANDLE(master_softc)) && 1885036Skz151634 (GTT_HANDLE(master_softc) != NULL)) 1895036Skz151634 ddi_regs_map_free(>T_HANDLE(master_softc)); 1905036Skz151634 if (MMIO_HANDLE(master_softc) != NULL) 1914478Skz151634 ddi_regs_map_free(&MMIO_HANDLE(master_softc)); 1923446Smrj } 1933446Smrj 1943446Smrj kmem_free(master_softc, sizeof (agp_master_softc_t)); 1953446Smrj master_softc = NULL; 1963446Smrj 1973446Smrj return; 1983446Smrj 1993446Smrj } 2003446Smrj 2013446Smrj /* 2024478Skz151634 * 965 has a fixed GTT table size (512KB), so check to see the actual aperture 2034478Skz151634 * size. Aperture size = GTT table size * 1024. 2044478Skz151634 */ 2054478Skz151634 static off_t 2064478Skz151634 i965_apersize(agp_master_softc_t *agpmaster) 2074478Skz151634 { 2084478Skz151634 off_t apersize; 2094478Skz151634 2104478Skz151634 apersize = AGPM_READ(agpmaster, PGTBL_CTL); 2114478Skz151634 AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize)); 2124478Skz151634 switch (apersize & GTT_SIZE_MASK) { 2136778Smc196098 case GTT_2MB: 2146778Smc196098 apersize = 2048; 2156778Smc196098 break; 2166778Smc196098 case GTT_1_5MB: 2176778Smc196098 apersize = 1536; 2186778Smc196098 break; 2196778Smc196098 case GTT_1MB: 2206778Smc196098 apersize = 1024; 2216778Smc196098 break; 2224478Skz151634 case GTT_512KB: 2234478Skz151634 apersize = 512; 2244478Skz151634 break; 2254478Skz151634 case GTT_256KB: 2264478Skz151634 apersize = 256; 2274478Skz151634 break; 2284478Skz151634 case GTT_128KB: 2294478Skz151634 apersize = 128; 2304478Skz151634 break; 2314478Skz151634 default: 2325036Skz151634 apersize = 0; 2334478Skz151634 AGPM_DEBUG((CE_WARN, 2344478Skz151634 "i965_apersize: invalid GTT size in PGTBL_CTL")); 2354478Skz151634 } 2365036Skz151634 return (apersize); 2375036Skz151634 } 2385036Skz151634 2395036Skz151634 /* 2405036Skz151634 * For Intel 3 series, we need to get GTT size from the GGMS field in GMCH 2415036Skz151634 * Graphics Control Register. Return aperture size in MB. 2425036Skz151634 */ 2435036Skz151634 static off_t 2445036Skz151634 i3XX_apersize(ddi_acc_handle_t pci_acc_hdl) 2455036Skz151634 { 2465036Skz151634 uint16_t value; 2475036Skz151634 off_t apersize; 2485036Skz151634 2495036Skz151634 /* 2505036Skz151634 * Get the value of configuration register MGGC "Mirror of Dev0 GMCH 2515036Skz151634 * Graphics Control" from Internal Graphics #2 (Device2:Function0). 2525036Skz151634 */ 2535036Skz151634 value = pci_config_get16(pci_acc_hdl, I8XX_CONF_GC); 2545036Skz151634 AGPM_DEBUG((CE_NOTE, "i3XX_apersize: MGGC = 0x%x", value)); 2555036Skz151634 /* computing aperture size using the pre-allocated GTT size */ 2565036Skz151634 switch (value & IX33_GGMS_MASK) { 2575036Skz151634 case IX33_GGMS_1M: 2585036Skz151634 apersize = 1024; 2595036Skz151634 break; 2605036Skz151634 case IX33_GGMS_2M: 2615036Skz151634 apersize = 2048; 2625036Skz151634 break; 2635036Skz151634 default: 2645036Skz151634 apersize = 0; /* no memory pre-allocated */ 2655036Skz151634 AGPM_DEBUG((CE_WARN, 2665036Skz151634 "i3XX_apersize: no memory allocated for GTT")); 2675036Skz151634 } 2685036Skz151634 AGPM_DEBUG((CE_NOTE, "i3xx_apersize: apersize = %ldM", apersize)); 2694478Skz151634 return (apersize); 2704478Skz151634 } 2714478Skz151634 2724478Skz151634 #define CHECK_STATUS(status) \ 2734478Skz151634 if (status != DDI_SUCCESS) { \ 2744478Skz151634 AGPM_DEBUG((CE_WARN, \ 2754478Skz151634 "set_gtt_mmio: regs_map_setup error")); \ 2764478Skz151634 return (-1); \ 2774478Skz151634 } 2784478Skz151634 /* 2794478Skz151634 * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid 2804478Skz151634 * according to chipset. 2814478Skz151634 */ 2824478Skz151634 static int 2835036Skz151634 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster, 2845036Skz151634 ddi_acc_handle_t pci_acc_hdl) 2854478Skz151634 { 2865036Skz151634 off_t apersize; /* size of graphics mem (MB) == GTT size (KB) */ 2874478Skz151634 uint32_t value; 2885036Skz151634 off_t gmadr_off; /* GMADR offset in PCI config space */ 2894478Skz151634 int status; 2904478Skz151634 2915036Skz151634 if (IS_INTEL_X33(agpmaster)) { 2925036Skz151634 /* Intel 3 series are similar with 915/945 series */ 2934478Skz151634 status = ddi_regs_map_setup(devi, I915_GTTADDR, 2944478Skz151634 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access, 2955036Skz151634 >T_HANDLE(agpmaster)); 2964478Skz151634 CHECK_STATUS(status); 2974478Skz151634 2984478Skz151634 status = ddi_regs_map_setup(devi, I915_MMADR, 2994478Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 3004478Skz151634 &MMIO_HANDLE(agpmaster)); 3014478Skz151634 CHECK_STATUS(status); 3024478Skz151634 3036110Sms148562 gmadr_off = I915_CONF_GMADR; 3046110Sms148562 /* Different computing method used in getting aperture size. */ 3055036Skz151634 apersize = i3XX_apersize(pci_acc_hdl); 3065036Skz151634 } else if (IS_INTEL_965(agpmaster)) { 3075036Skz151634 status = ddi_regs_map_setup(devi, I965_GTTMMADR, 3085036Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 3095036Skz151634 &MMIO_HANDLE(agpmaster)); 3105036Skz151634 CHECK_STATUS(status); 3117662SMiao.Chen@Sun.COM if ((agpmaster->agpm_id == INTEL_IGD_GM45) || 3127662SMiao.Chen@Sun.COM IS_INTEL_G4X(agpmaster)) 3136778Smc196098 GTT_ADDR(agpmaster) = 3146778Smc196098 MMIO_BASE(agpmaster) + GM45_GTT_OFFSET; 3156778Smc196098 else 3166778Smc196098 GTT_ADDR(agpmaster) = 3176778Smc196098 MMIO_BASE(agpmaster) + I965_GTT_OFFSET; 3185036Skz151634 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster); 3195036Skz151634 3205036Skz151634 gmadr_off = I915_CONF_GMADR; 3215036Skz151634 apersize = i965_apersize(agpmaster); 3225036Skz151634 } else if (IS_INTEL_915(agpmaster)) { 3235036Skz151634 /* I915/945 series */ 3245036Skz151634 status = ddi_regs_map_setup(devi, I915_GTTADDR, 3255036Skz151634 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access, 3265036Skz151634 >T_HANDLE(agpmaster)); 3275036Skz151634 CHECK_STATUS(status); 3285036Skz151634 3295036Skz151634 status = ddi_regs_map_setup(devi, I915_MMADR, 3305036Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 3315036Skz151634 &MMIO_HANDLE(agpmaster)); 3325036Skz151634 CHECK_STATUS(status); 3335036Skz151634 3345036Skz151634 gmadr_off = I915_CONF_GMADR; 3354478Skz151634 status = ddi_dev_regsize(devi, I915_GMADR, &apersize); 3365036Skz151634 apersize = BYTES2MB(apersize); 3374478Skz151634 } else { 3384478Skz151634 /* I8XX series */ 3394478Skz151634 status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR, 3404478Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 3414478Skz151634 &MMIO_HANDLE(agpmaster)); 3424478Skz151634 CHECK_STATUS(status); 3434478Skz151634 3444478Skz151634 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET; 3455036Skz151634 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster); 3465036Skz151634 gmadr_off = I8XX_CONF_GMADR; 3474478Skz151634 status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize); 3485036Skz151634 apersize = BYTES2MB(apersize); 3494478Skz151634 CHECK_STATUS(status); 3504478Skz151634 } 3514478Skz151634 3524478Skz151634 /* 3535036Skz151634 * If memory size is smaller than a certain value, it means 3544478Skz151634 * the register set number for graphics memory range might 3554478Skz151634 * be wrong 3564478Skz151634 */ 3575036Skz151634 if (status != DDI_SUCCESS || apersize < 4) { 3584478Skz151634 AGPM_DEBUG((CE_WARN, 3595036Skz151634 "set_gtt_mmio: error in getting graphics memory")); 3604478Skz151634 return (-1); 3614478Skz151634 } 3624478Skz151634 3635036Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = apersize; 3644478Skz151634 3655036Skz151634 /* get graphics memory base address from GMADR */ 3665036Skz151634 value = pci_config_get32(pci_acc_hdl, gmadr_off); 3674478Skz151634 APER_BASE(agpmaster) = value & GTT_BASE_MASK; 3685036Skz151634 AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = 0x%x, apersize = %ldM, " 3694478Skz151634 "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize, 3704478Skz151634 (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster))); 3714478Skz151634 return (0); 3724478Skz151634 } 3734478Skz151634 3744478Skz151634 /* 3753446Smrj * Try to initialize agp master. 3763446Smrj * 0 is returned if the device is successfully initialized. AGP master soft 3773446Smrj * state is returned in master_softcp if needed. 3783446Smrj * Otherwise -1 is returned and *master_softcp is set to NULL. 3793446Smrj */ 3803446Smrj int 3813446Smrj agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp, 3823446Smrj ddi_acc_handle_t pci_acc_hdl, minor_t minor) 3833446Smrj { 3843446Smrj int instance; 3853446Smrj int status; 3863446Smrj agp_master_softc_t *agpmaster; 3873446Smrj char buf[80]; 3883446Smrj 3893446Smrj 3903446Smrj ASSERT(pci_acc_hdl); 3913446Smrj *master_softcp = NULL; 3923446Smrj agpmaster = (agp_master_softc_t *) 3933446Smrj kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP); 3943446Smrj 3953446Smrj agpmaster->agpm_id = 3963446Smrj pci_config_get32(pci_acc_hdl, PCI_CONF_VENID); 3973446Smrj agpmaster->agpm_acc_hdl = pci_acc_hdl; 3983446Smrj 3993446Smrj if (!detect_i8xx_device(agpmaster)) { 4004478Skz151634 /* Intel 8XX, 915, 945 and 965 series */ 4014478Skz151634 if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0) 4023446Smrj goto fail; 4033446Smrj } else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) { 4044478Skz151634 /* non IGD or AGP devices, AMD64 gart */ 4053446Smrj AGPM_DEBUG((CE_WARN, 4063446Smrj "agpmaster_attach: neither IGD or AGP devices exists")); 4073446Smrj agpmaster_detach(&agpmaster); 4083446Smrj return (0); 4093446Smrj } 4103446Smrj 4115036Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid = 4125036Skz151634 agpmaster->agpm_id; 4135036Skz151634 4143446Smrj /* create minor node for IGD or AGP device */ 4153446Smrj instance = ddi_get_instance(devi); 4163446Smrj 4173446Smrj (void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance); 4183446Smrj status = ddi_create_minor_node(devi, buf, S_IFCHR, minor, 4193446Smrj DDI_NT_AGP_MASTER, 0); 4203446Smrj 4213446Smrj if (status != DDI_SUCCESS) { 4223446Smrj AGPM_DEBUG((CE_WARN, 4233446Smrj "agpmaster_attach: create agpmaster node failed")); 4243446Smrj goto fail; 4253446Smrj } 4263446Smrj 4273446Smrj *master_softcp = agpmaster; 4283446Smrj return (0); 4293446Smrj fail: 4303446Smrj agpmaster_detach(&agpmaster); 4313446Smrj return (-1); 4323446Smrj } 4333446Smrj 4343446Smrj /* 4353446Smrj * Currently, it handles ioctl requests related with agp master device for 4363446Smrj * layered driver (agpgart) only. 4373446Smrj */ 4383446Smrj /*ARGSUSED*/ 4393446Smrj int 4403446Smrj agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred, 4413446Smrj int *rval, agp_master_softc_t *softc) 4423446Smrj { 4433446Smrj uint32_t base; 4443446Smrj uint32_t addr; 4453446Smrj igd_gtt_seg_t seg; 4463446Smrj agp_info_t info; 4473446Smrj uint32_t value; 4483446Smrj off_t cap; 4493446Smrj uint32_t command; 4503446Smrj static char kernel_only[] = 4513446Smrj "agpmaster_ioctl: %s is a kernel only ioctl"; 4523446Smrj 4533446Smrj CONFIRM(softc); 4543446Smrj 4553446Smrj switch (cmd) { 4563446Smrj case DEVICE_DETECT: 4573446Smrj if (!(mode & FKIOCTL)) { 4583446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT")); 4593446Smrj return (ENXIO); 4603446Smrj } 4613446Smrj 4623446Smrj if (ddi_copyout(&softc->agpm_dev_type, 4633446Smrj (void *)data, sizeof (int), mode)) 4643446Smrj return (EFAULT); 4653446Smrj break; 4663446Smrj case AGP_MASTER_SETCMD: 4673446Smrj if (!(mode & FKIOCTL)) { 4683446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD")); 4693446Smrj return (ENXIO); 4703446Smrj } 4713446Smrj 4723446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP); 4733446Smrj CONFIRM(softc->agpm_data.agpm_acaptr); 4743446Smrj 4753446Smrj if (ddi_copyin((void *)data, &command, 4763446Smrj sizeof (uint32_t), mode)) 4773446Smrj return (EFAULT); 4783446Smrj 4793446Smrj pci_config_put32(softc->agpm_acc_hdl, 4803446Smrj softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND, 4813446Smrj command); 4823446Smrj break; 4833446Smrj case AGP_MASTER_GETINFO: 4843446Smrj if (!(mode & FKIOCTL)) { 4853446Smrj AGPM_DEBUG((CE_CONT, kernel_only, 4863446Smrj "AGP_MASTER_GETINFO")); 4873446Smrj return (ENXIO); 4883446Smrj } 4893446Smrj 4903446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP); 4913446Smrj CONFIRM(softc->agpm_data.agpm_acaptr); 4923446Smrj 4933446Smrj cap = softc->agpm_data.agpm_acaptr; 4943446Smrj value = pci_config_get32(softc->agpm_acc_hdl, cap); 4953446Smrj info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf); 4963446Smrj info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf); 4973446Smrj info.agpi_devid = softc->agpm_id; 4983446Smrj info.agpi_mode = pci_config_get32( 4993446Smrj softc->agpm_acc_hdl, cap + AGP_CONF_STATUS); 5003446Smrj 5013446Smrj if (ddi_copyout(&info, (void *)data, 5023446Smrj sizeof (agp_info_t), mode)) 5033446Smrj return (EFAULT); 5043446Smrj break; 5053446Smrj case I810_SET_GTT_BASE: 5063446Smrj if (!(mode & FKIOCTL)) { 5073446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR")); 5083446Smrj return (ENXIO); 5093446Smrj } 5103446Smrj 5113446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810); 5123446Smrj 5133446Smrj if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode)) 5143446Smrj return (EFAULT); 5153446Smrj 5163446Smrj /* enables page table */ 5173446Smrj addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID; 5183446Smrj 5194478Skz151634 AGPM_WRITE(softc, PGTBL_CTL, addr); 5203446Smrj break; 5213446Smrj case I8XX_GET_INFO: 5223446Smrj if (!(mode & FKIOCTL)) { 5233446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO")); 5243446Smrj return (ENXIO); 5253446Smrj } 5263446Smrj 5273446Smrj CONFIRM(IS_IGD(softc)); 5283446Smrj 5293446Smrj if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info, 5303446Smrj (void *)data, sizeof (igd_info_t), mode)) 5313446Smrj return (EFAULT); 5323446Smrj break; 5333446Smrj case I8XX_ADD2GTT: 5343446Smrj if (!(mode & FKIOCTL)) { 5353446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT")); 5363446Smrj return (ENXIO); 5373446Smrj } 5383446Smrj 5393446Smrj CONFIRM(IS_IGD(softc)); 5403446Smrj 5413446Smrj if (ddi_copyin((void *)data, &seg, 5423446Smrj sizeof (igd_gtt_seg_t), mode)) 5433446Smrj return (EFAULT); 5443446Smrj 5453446Smrj if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg)) 5463446Smrj return (EINVAL); 5473446Smrj break; 5483446Smrj case I8XX_REM_GTT: 5493446Smrj if (!(mode & FKIOCTL)) { 5503446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT")); 5513446Smrj return (ENXIO); 5523446Smrj } 5533446Smrj 5543446Smrj CONFIRM(IS_IGD(softc)); 5553446Smrj 5563446Smrj if (ddi_copyin((void *)data, &seg, 5573446Smrj sizeof (igd_gtt_seg_t), mode)) 5583446Smrj return (EFAULT); 5593446Smrj 5603446Smrj i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg); 5613446Smrj break; 5623446Smrj case I8XX_UNCONFIG: 5633446Smrj if (!(mode & FKIOCTL)) { 5643446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG")); 5653446Smrj return (ENXIO); 5663446Smrj } 5673446Smrj 5683446Smrj CONFIRM(IS_IGD(softc)); 5693446Smrj 5703446Smrj if (softc->agpm_dev_type == DEVICE_IS_I810) 5714478Skz151634 AGPM_WRITE(softc, PGTBL_CTL, 0); 5723446Smrj /* 5733446Smrj * may need to clear all gtt entries here for i830 series, 5743446Smrj * but may not be necessary 5753446Smrj */ 5763446Smrj break; 5773446Smrj } 5783446Smrj return (0); 5793446Smrj } 5803446Smrj 5813446Smrj /* 5823446Smrj * If AGP cap pointer is successfully found, none-zero value is returned. 5833446Smrj * Otherwise 0 is returned. 5843446Smrj */ 5853446Smrj static off_t 5863446Smrj agpmaster_cap_find(ddi_acc_handle_t acc_handle) 5873446Smrj { 5883446Smrj off_t nextcap; 5893446Smrj uint32_t ncapid; 5903446Smrj uint8_t value; 5913446Smrj 5923446Smrj /* check if this device supports capibility pointer */ 5933446Smrj value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT) 5944303Skz151634 & PCI_CONF_CAP_MASK); 5953446Smrj 5963446Smrj if (!value) 5973446Smrj return (0); 5983446Smrj /* get the offset of the first capability pointer from CAPPTR */ 5993446Smrj nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR)); 6003446Smrj 6013446Smrj /* check AGP capability from the first capability pointer */ 6023446Smrj while (nextcap) { 6033446Smrj ncapid = pci_config_get32(acc_handle, nextcap); 6043446Smrj if ((ncapid & PCI_CONF_CAPID_MASK) 6053446Smrj == AGP_CAP_ID) /* find AGP cap */ 6063446Smrj break; 6073446Smrj 6083446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 6093446Smrj } 6103446Smrj 6113446Smrj return (nextcap); 6123446Smrj 6133446Smrj } 6143446Smrj 6153446Smrj /* 6163446Smrj * If i8xx device is successfully detected, 0 is returned. 6173446Smrj * Otherwise -1 is returned. 6183446Smrj */ 6193446Smrj static int 6203446Smrj detect_i8xx_device(agp_master_softc_t *master_softc) 6213446Smrj { 6223446Smrj 6233446Smrj switch (master_softc->agpm_id) { 6243446Smrj case INTEL_IGD_810: 6253446Smrj case INTEL_IGD_810DC: 6263446Smrj case INTEL_IGD_810E: 6273446Smrj case INTEL_IGD_815: 6283446Smrj master_softc->agpm_dev_type = DEVICE_IS_I810; 6293446Smrj break; 6303446Smrj case INTEL_IGD_830M: 6313446Smrj case INTEL_IGD_845G: 6323446Smrj case INTEL_IGD_855GM: 6333446Smrj case INTEL_IGD_865G: 6344478Skz151634 case INTEL_IGD_915: 6354478Skz151634 case INTEL_IGD_915GM: 6363446Smrj case INTEL_IGD_945: 6374303Skz151634 case INTEL_IGD_945GM: 6388020SMiao.Chen@Sun.COM case INTEL_IGD_945GME: 6394478Skz151634 case INTEL_IGD_946GZ: 6404478Skz151634 case INTEL_IGD_965G1: 6414478Skz151634 case INTEL_IGD_965G2: 6424478Skz151634 case INTEL_IGD_965GM: 6434618Skz151634 case INTEL_IGD_965GME: 6444478Skz151634 case INTEL_IGD_965Q: 6455036Skz151634 case INTEL_IGD_Q35: 6465036Skz151634 case INTEL_IGD_G33: 6475036Skz151634 case INTEL_IGD_Q33: 6486778Smc196098 case INTEL_IGD_GM45: 6497662SMiao.Chen@Sun.COM case INTEL_IGD_EL: 6507662SMiao.Chen@Sun.COM case INTEL_IGD_Q45: 6517662SMiao.Chen@Sun.COM case INTEL_IGD_G45: 652*8832SMiao.Chen@Sun.COM case INTEL_IGD_G41: 6533446Smrj master_softc->agpm_dev_type = DEVICE_IS_I830; 6543446Smrj break; 6553446Smrj default: /* unknown id */ 6563446Smrj return (-1); 6573446Smrj } 6583446Smrj 6593446Smrj return (0); 6603446Smrj } 6613446Smrj 6623446Smrj /* 6633446Smrj * If agp master is succssfully detected, 0 is returned. 6643446Smrj * Otherwise -1 is returned. 6653446Smrj */ 6663446Smrj static int 6673446Smrj detect_agp_devcice(agp_master_softc_t *master_softc, 6683446Smrj ddi_acc_handle_t acc_handle) 6693446Smrj { 6703446Smrj off_t cap; 6713446Smrj 6723446Smrj cap = agpmaster_cap_find(acc_handle); 6733446Smrj if (cap) { 6743446Smrj master_softc->agpm_dev_type = DEVICE_IS_AGP; 6753446Smrj master_softc->agpm_data.agpm_acaptr = cap; 6763446Smrj return (0); 6773446Smrj } else { 6783446Smrj return (-1); 6793446Smrj } 6803446Smrj 6813446Smrj } 6823446Smrj 6833446Smrj /* 6843446Smrj * Please refer to GART and GTT entry format table in agpdefs.h for 6853446Smrj * intel GTT entry format. 6863446Smrj */ 6873446Smrj static int 6883446Smrj phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry) 6893446Smrj { 6903446Smrj uint32_t value; 6913446Smrj 6923446Smrj switch (type) { 6933446Smrj case AGP_PHYSICAL: 6943446Smrj case AGP_NORMAL: 6953446Smrj value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID; 6963446Smrj break; 6973446Smrj default: 6983446Smrj return (-1); 6993446Smrj } 7003446Smrj 7013446Smrj *entry = value; 7023446Smrj 7033446Smrj return (0); 7043446Smrj } 7053446Smrj 7063446Smrj static int 7073446Smrj i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 7083446Smrj { 7093446Smrj int i; 7103446Smrj uint32_t *paddr; 7113446Smrj uint32_t entry; 7123446Smrj uint32_t maxpages; 7133446Smrj 7143446Smrj maxpages = gtt->gtt_info.igd_apersize; 7153446Smrj maxpages = GTT_MB_TO_PAGES(maxpages); 7163446Smrj 7173446Smrj paddr = seg.igs_phyaddr; 7183446Smrj 7193446Smrj /* check if gtt max page number is reached */ 7203446Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 7213446Smrj return (-1); 7223446Smrj 7233446Smrj paddr = seg.igs_phyaddr; 7243446Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); 7253446Smrj i++, paddr++) { 7263446Smrj if (phys2entry(seg.igs_type, *paddr, &entry)) 7273446Smrj return (-1); 7285036Skz151634 ddi_put32(gtt->gtt_handle, 7293446Smrj (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 7303446Smrj entry); 7313446Smrj } 7323446Smrj 7333446Smrj return (0); 7343446Smrj } 7353446Smrj 7363446Smrj static void 7373446Smrj i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 7383446Smrj { 7393446Smrj int i; 7403446Smrj uint32_t maxpages; 7413446Smrj 7423446Smrj maxpages = gtt->gtt_info.igd_apersize; 7433446Smrj maxpages = GTT_MB_TO_PAGES(maxpages); 7443446Smrj 7453446Smrj /* check if gtt max page number is reached */ 7463446Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 7473446Smrj return; 7483446Smrj 7493446Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) { 7505036Skz151634 ddi_put32(gtt->gtt_handle, 7514478Skz151634 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 0); 7523446Smrj } 7533446Smrj } 754