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 /* 234303Skz151634 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243446Smrj * Use is subject to license terms. 253446Smrj */ 263446Smrj 273446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 283446Smrj 293446Smrj /* 303446Smrj * Misc module for AGP master device support 313446Smrj */ 323446Smrj 333446Smrj #include <sys/modctl.h> 343446Smrj #include <sys/pci.h> 353446Smrj #include <sys/stat.h> 363446Smrj #include <sys/file.h> 373446Smrj #include <sys/types.h> 383446Smrj #include <sys/dditypes.h> 393446Smrj #include <sys/sunddi.h> 403446Smrj #include <sys/agpgart.h> 413446Smrj #include <sys/agp/agpdefs.h> 423446Smrj #include <sys/agp/agpmaster_io.h> 433446Smrj 44*4478Skz151634 #define PGTBL_CTL 0x2020 /* Page table control register */ 45*4478Skz151634 #define I8XX_FB_BAR 1 46*4478Skz151634 #define I8XX_MMIO_BAR 2 47*4478Skz151634 #define I8XX_PTE_OFFSET 0x10000 48*4478Skz151634 #define I915_MMADR 1 /* mem-mapped registers BAR */ 49*4478Skz151634 #define I915_GMADR 3 /* graphics mem BAR */ 50*4478Skz151634 #define I915_GTTADDR 4 /* GTT BAR */ 51*4478Skz151634 #define I965_GTTMMADR 1 /* mem-mapped registers BAR + GTT */ 52*4478Skz151634 #define I965_GMADR 2 /* graphics mem BAR */ 53*4478Skz151634 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */ 54*4478Skz151634 #define I965_GTT_OFFSET 0x80000 55*4478Skz151634 #define GTT_SIZE_MASK 0xe 56*4478Skz151634 #define GTT_512KB (0 << 1) 57*4478Skz151634 #define GTT_256KB (1 << 1) 58*4478Skz151634 #define GTT_128KB (2 << 1) 59*4478Skz151634 60*4478Skz151634 #define MMIO_BASE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_base 61*4478Skz151634 #define MMIO_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_handle 62*4478Skz151634 #define GTT_ADDR(x) (x)->agpm_data.agpm_gtt.gtt_addr 63*4478Skz151634 #define APER_BASE(x) (x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase 64*4478Skz151634 65*4478Skz151634 #define AGPM_WRITE(x, off, val) \ 66*4478Skz151634 ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val)); 67*4478Skz151634 68*4478Skz151634 #define AGPM_READ(x, off) \ 69*4478Skz151634 ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off))); 703446Smrj 713446Smrj #ifdef DEBUG 723446Smrj #define CONFIRM(value) ASSERT(value) 733446Smrj #else 743446Smrj #define CONFIRM(value) if (!(value)) return (EINVAL) 753446Smrj #endif 763446Smrj 773446Smrj int agpm_debug = 0; 783446Smrj #define AGPM_DEBUG(args) if (agpm_debug >= 1) cmn_err args 793446Smrj 803446Smrj /* 813446Smrj * Whether it is a Intel integrated graphics card 823446Smrj */ 833446Smrj #define IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \ 84*4478Skz151634 (agpmaster->agpm_dev_type == DEVICE_IS_I830)) 853446Smrj 863446Smrj 87*4478Skz151634 /* Intel 915 and 945 series */ 88*4478Skz151634 #define IS_INTEL_915(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_915) || \ 89*4478Skz151634 (agpmaster->agpm_id == INTEL_IGD_915GM) || \ 90*4478Skz151634 (agpmaster->agpm_id == INTEL_IGD_945) || \ 91*4478Skz151634 (agpmaster->agpm_id == INTEL_IGD_945GM)) 92*4478Skz151634 93*4478Skz151634 /* Intel 965 series */ 94*4478Skz151634 #define IS_INTEL_965(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_946GZ) || \ 95*4478Skz151634 (agpmaster->agpm_id == INTEL_IGD_965G1) || \ 96*4478Skz151634 (agpmaster->agpm_id == INTEL_IGD_965Q) || \ 97*4478Skz151634 (agpmaster->agpm_id == INTEL_IGD_965G2) || \ 98*4478Skz151634 (agpmaster->agpm_id == INTEL_IGD_965GM)) 993446Smrj 1003446Smrj static struct modlmisc modlmisc = { 1013446Smrj &mod_miscops, "AGP master interfaces v%I%" 1023446Smrj }; 1033446Smrj 1043446Smrj static struct modlinkage modlinkage = { 1053446Smrj MODREV_1, (void *)&modlmisc, NULL 1063446Smrj }; 1073446Smrj 1083446Smrj static ddi_device_acc_attr_t i8xx_dev_access = { 1093446Smrj DDI_DEVICE_ATTR_V0, 1103446Smrj DDI_NEVERSWAP_ACC, 1113446Smrj DDI_STRICTORDER_ACC 1123446Smrj }; 1133446Smrj 1143446Smrj static off_t agpmaster_cap_find(ddi_acc_handle_t); 1153446Smrj static int detect_i8xx_device(agp_master_softc_t *); 1163446Smrj static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t); 1173446Smrj static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t); 1183446Smrj static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t); 1193446Smrj 1203446Smrj int 1213446Smrj _init(void) 1223446Smrj { 1233446Smrj int err; 1243446Smrj 1253446Smrj if ((err = mod_install(&modlinkage)) != 0) 1263446Smrj return (err); 1273446Smrj 1283446Smrj return (0); 1293446Smrj } 1303446Smrj 1313446Smrj int 1323446Smrj _fini(void) 1333446Smrj { 1343446Smrj int err; 1353446Smrj 1363446Smrj if ((err = mod_remove(&modlinkage)) != 0) 1373446Smrj return (err); 1383446Smrj 1393446Smrj return (0); 1403446Smrj } 1413446Smrj 1423446Smrj int 1433446Smrj _info(struct modinfo *modinfop) 1443446Smrj { 1453446Smrj return (mod_info(&modlinkage, modinfop)); 1463446Smrj } 1473446Smrj 1483446Smrj /* 1493446Smrj * Minor node is not removed here, since the caller (xx_attach) is 1503446Smrj * responsible for removing all nodes. 1513446Smrj */ 1523446Smrj void 1533446Smrj agpmaster_detach(agp_master_softc_t **master_softcp) 1543446Smrj { 1553446Smrj agp_master_softc_t *master_softc; 1563446Smrj 1573446Smrj ASSERT(master_softcp); 1583446Smrj master_softc = *master_softcp; 1593446Smrj 1603446Smrj /* intel integrated device */ 1613446Smrj if (IS_IGD(master_softc)) { 162*4478Skz151634 if (MMIO_HANDLE(master_softc) != NULL) { 163*4478Skz151634 ddi_regs_map_free(&MMIO_HANDLE(master_softc)); 1643446Smrj } 1653446Smrj } 1663446Smrj 1673446Smrj kmem_free(master_softc, sizeof (agp_master_softc_t)); 1683446Smrj master_softc = NULL; 1693446Smrj 1703446Smrj return; 1713446Smrj 1723446Smrj } 1733446Smrj 1743446Smrj /* 175*4478Skz151634 * 965 has a fixed GTT table size (512KB), so check to see the actual aperture 176*4478Skz151634 * size. Aperture size = GTT table size * 1024. 177*4478Skz151634 */ 178*4478Skz151634 static off_t 179*4478Skz151634 i965_apersize(agp_master_softc_t *agpmaster) 180*4478Skz151634 { 181*4478Skz151634 off_t apersize; 182*4478Skz151634 183*4478Skz151634 apersize = AGPM_READ(agpmaster, PGTBL_CTL); 184*4478Skz151634 AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize)); 185*4478Skz151634 switch (apersize & GTT_SIZE_MASK) { 186*4478Skz151634 case GTT_512KB: 187*4478Skz151634 apersize = 512; 188*4478Skz151634 break; 189*4478Skz151634 case GTT_256KB: 190*4478Skz151634 apersize = 256; 191*4478Skz151634 break; 192*4478Skz151634 case GTT_128KB: 193*4478Skz151634 apersize = 128; 194*4478Skz151634 break; 195*4478Skz151634 default: 196*4478Skz151634 AGPM_DEBUG((CE_WARN, 197*4478Skz151634 "i965_apersize: invalid GTT size in PGTBL_CTL")); 198*4478Skz151634 } 199*4478Skz151634 apersize = MB2BYTES(apersize); 200*4478Skz151634 return (apersize); 201*4478Skz151634 } 202*4478Skz151634 203*4478Skz151634 #define CHECK_STATUS(status) \ 204*4478Skz151634 if (status != DDI_SUCCESS) { \ 205*4478Skz151634 AGPM_DEBUG((CE_WARN, \ 206*4478Skz151634 "set_gtt_mmio: regs_map_setup error")); \ 207*4478Skz151634 return (-1); \ 208*4478Skz151634 } 209*4478Skz151634 /* 210*4478Skz151634 * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid 211*4478Skz151634 * according to chipset. 212*4478Skz151634 */ 213*4478Skz151634 static int 214*4478Skz151634 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster, ddi_acc_handle_t 215*4478Skz151634 pci_acc_hdl) 216*4478Skz151634 { 217*4478Skz151634 off_t apersize; 218*4478Skz151634 uint32_t value; 219*4478Skz151634 off_t conf_off; /* offset in PCI conf space for aperture */ 220*4478Skz151634 int status; 221*4478Skz151634 222*4478Skz151634 if (IS_INTEL_965(agpmaster)) { 223*4478Skz151634 status = ddi_regs_map_setup(devi, I965_GTTMMADR, 224*4478Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 225*4478Skz151634 &MMIO_HANDLE(agpmaster)); 226*4478Skz151634 CHECK_STATUS(status); 227*4478Skz151634 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I965_GTT_OFFSET; 228*4478Skz151634 229*4478Skz151634 conf_off = I915_CONF_GMADR; 230*4478Skz151634 apersize = i965_apersize(agpmaster); 231*4478Skz151634 /* make this the last line, to clear follow-up status check */ 232*4478Skz151634 status = DDI_SUCCESS; 233*4478Skz151634 234*4478Skz151634 } else if (IS_INTEL_915(agpmaster)) { 235*4478Skz151634 status = ddi_regs_map_setup(devi, I915_GTTADDR, 236*4478Skz151634 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access, 237*4478Skz151634 &MMIO_HANDLE(agpmaster)); 238*4478Skz151634 CHECK_STATUS(status); 239*4478Skz151634 240*4478Skz151634 status = ddi_regs_map_setup(devi, I915_MMADR, 241*4478Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 242*4478Skz151634 &MMIO_HANDLE(agpmaster)); 243*4478Skz151634 CHECK_STATUS(status); 244*4478Skz151634 245*4478Skz151634 conf_off = I915_CONF_GMADR; 246*4478Skz151634 status = ddi_dev_regsize(devi, I915_GMADR, &apersize); 247*4478Skz151634 } else { 248*4478Skz151634 /* I8XX series */ 249*4478Skz151634 status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR, 250*4478Skz151634 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 251*4478Skz151634 &MMIO_HANDLE(agpmaster)); 252*4478Skz151634 CHECK_STATUS(status); 253*4478Skz151634 254*4478Skz151634 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET; 255*4478Skz151634 conf_off = I8XX_CONF_GMADR; 256*4478Skz151634 status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize); 257*4478Skz151634 CHECK_STATUS(status); 258*4478Skz151634 } 259*4478Skz151634 260*4478Skz151634 /* 261*4478Skz151634 * if memory size is smaller than a certain value, it means 262*4478Skz151634 * the register set number for graphics memory range might 263*4478Skz151634 * be wrong 264*4478Skz151634 */ 265*4478Skz151634 if (status != DDI_SUCCESS || apersize < 0x400000) { 266*4478Skz151634 AGPM_DEBUG((CE_WARN, 267*4478Skz151634 "set_gtt_mmio: ddi_dev_regsize error")); 268*4478Skz151634 return (-1); 269*4478Skz151634 } 270*4478Skz151634 271*4478Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = 272*4478Skz151634 BYTES2MB(apersize); 273*4478Skz151634 274*4478Skz151634 /* get GTT base */ 275*4478Skz151634 value = pci_config_get32(pci_acc_hdl, conf_off); 276*4478Skz151634 277*4478Skz151634 APER_BASE(agpmaster) = value & GTT_BASE_MASK; 278*4478Skz151634 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid = 279*4478Skz151634 agpmaster->agpm_id; 280*4478Skz151634 AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = %x, apersize = %lx, " 281*4478Skz151634 "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize, 282*4478Skz151634 (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster))); 283*4478Skz151634 return (0); 284*4478Skz151634 } 285*4478Skz151634 286*4478Skz151634 /* 2873446Smrj * Try to initialize agp master. 2883446Smrj * 0 is returned if the device is successfully initialized. AGP master soft 2893446Smrj * state is returned in master_softcp if needed. 2903446Smrj * Otherwise -1 is returned and *master_softcp is set to NULL. 2913446Smrj */ 2923446Smrj int 2933446Smrj agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp, 2943446Smrj ddi_acc_handle_t pci_acc_hdl, minor_t minor) 2953446Smrj { 2963446Smrj int instance; 2973446Smrj int status; 2983446Smrj agp_master_softc_t *agpmaster; 2993446Smrj char buf[80]; 3003446Smrj 3013446Smrj 3023446Smrj ASSERT(pci_acc_hdl); 3033446Smrj *master_softcp = NULL; 3043446Smrj agpmaster = (agp_master_softc_t *) 3053446Smrj kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP); 3063446Smrj 3073446Smrj agpmaster->agpm_id = 3083446Smrj pci_config_get32(pci_acc_hdl, PCI_CONF_VENID); 3093446Smrj agpmaster->agpm_acc_hdl = pci_acc_hdl; 3103446Smrj 3113446Smrj if (!detect_i8xx_device(agpmaster)) { 312*4478Skz151634 /* Intel 8XX, 915, 945 and 965 series */ 313*4478Skz151634 if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0) 3143446Smrj goto fail; 3153446Smrj } else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) { 316*4478Skz151634 /* non IGD or AGP devices, AMD64 gart */ 3173446Smrj AGPM_DEBUG((CE_WARN, 3183446Smrj "agpmaster_attach: neither IGD or AGP devices exists")); 3193446Smrj agpmaster_detach(&agpmaster); 3203446Smrj return (0); 3213446Smrj } 3223446Smrj 3233446Smrj /* create minor node for IGD or AGP device */ 3243446Smrj instance = ddi_get_instance(devi); 3253446Smrj 3263446Smrj (void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance); 3273446Smrj status = ddi_create_minor_node(devi, buf, S_IFCHR, minor, 3283446Smrj DDI_NT_AGP_MASTER, 0); 3293446Smrj 3303446Smrj if (status != DDI_SUCCESS) { 3313446Smrj AGPM_DEBUG((CE_WARN, 3323446Smrj "agpmaster_attach: create agpmaster node failed")); 3333446Smrj goto fail; 3343446Smrj } 3353446Smrj 3363446Smrj *master_softcp = agpmaster; 3373446Smrj return (0); 3383446Smrj fail: 3393446Smrj agpmaster_detach(&agpmaster); 3403446Smrj return (-1); 3413446Smrj } 3423446Smrj 3433446Smrj /* 3443446Smrj * Currently, it handles ioctl requests related with agp master device for 3453446Smrj * layered driver (agpgart) only. 3463446Smrj */ 3473446Smrj /*ARGSUSED*/ 3483446Smrj int 3493446Smrj agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred, 3503446Smrj int *rval, agp_master_softc_t *softc) 3513446Smrj { 3523446Smrj uint32_t base; 3533446Smrj uint32_t addr; 3543446Smrj igd_gtt_seg_t seg; 3553446Smrj agp_info_t info; 3563446Smrj uint32_t value; 3573446Smrj off_t cap; 3583446Smrj uint32_t command; 3593446Smrj static char kernel_only[] = 3603446Smrj "agpmaster_ioctl: %s is a kernel only ioctl"; 3613446Smrj 3623446Smrj CONFIRM(softc); 3633446Smrj 3643446Smrj switch (cmd) { 3653446Smrj case DEVICE_DETECT: 3663446Smrj if (!(mode & FKIOCTL)) { 3673446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT")); 3683446Smrj return (ENXIO); 3693446Smrj } 3703446Smrj 3713446Smrj if (ddi_copyout(&softc->agpm_dev_type, 3723446Smrj (void *)data, sizeof (int), mode)) 3733446Smrj return (EFAULT); 3743446Smrj break; 3753446Smrj case AGP_MASTER_SETCMD: 3763446Smrj if (!(mode & FKIOCTL)) { 3773446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD")); 3783446Smrj return (ENXIO); 3793446Smrj } 3803446Smrj 3813446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP); 3823446Smrj CONFIRM(softc->agpm_data.agpm_acaptr); 3833446Smrj 3843446Smrj if (ddi_copyin((void *)data, &command, 3853446Smrj sizeof (uint32_t), mode)) 3863446Smrj return (EFAULT); 3873446Smrj 3883446Smrj pci_config_put32(softc->agpm_acc_hdl, 3893446Smrj softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND, 3903446Smrj command); 3913446Smrj break; 3923446Smrj case AGP_MASTER_GETINFO: 3933446Smrj if (!(mode & FKIOCTL)) { 3943446Smrj AGPM_DEBUG((CE_CONT, kernel_only, 3953446Smrj "AGP_MASTER_GETINFO")); 3963446Smrj return (ENXIO); 3973446Smrj } 3983446Smrj 3993446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP); 4003446Smrj CONFIRM(softc->agpm_data.agpm_acaptr); 4013446Smrj 4023446Smrj cap = softc->agpm_data.agpm_acaptr; 4033446Smrj value = pci_config_get32(softc->agpm_acc_hdl, cap); 4043446Smrj info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf); 4053446Smrj info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf); 4063446Smrj info.agpi_devid = softc->agpm_id; 4073446Smrj info.agpi_mode = pci_config_get32( 4083446Smrj softc->agpm_acc_hdl, cap + AGP_CONF_STATUS); 4093446Smrj 4103446Smrj if (ddi_copyout(&info, (void *)data, 4113446Smrj sizeof (agp_info_t), mode)) 4123446Smrj return (EFAULT); 4133446Smrj break; 4143446Smrj case I810_SET_GTT_BASE: 4153446Smrj if (!(mode & FKIOCTL)) { 4163446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR")); 4173446Smrj return (ENXIO); 4183446Smrj } 4193446Smrj 4203446Smrj CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810); 4213446Smrj 4223446Smrj if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode)) 4233446Smrj return (EFAULT); 4243446Smrj 4253446Smrj /* enables page table */ 4263446Smrj addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID; 4273446Smrj 428*4478Skz151634 AGPM_WRITE(softc, PGTBL_CTL, addr); 4293446Smrj break; 4303446Smrj case I8XX_GET_INFO: 4313446Smrj if (!(mode & FKIOCTL)) { 4323446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO")); 4333446Smrj return (ENXIO); 4343446Smrj } 4353446Smrj 4363446Smrj CONFIRM(IS_IGD(softc)); 4373446Smrj 4383446Smrj if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info, 4393446Smrj (void *)data, sizeof (igd_info_t), mode)) 4403446Smrj return (EFAULT); 4413446Smrj break; 4423446Smrj case I8XX_ADD2GTT: 4433446Smrj if (!(mode & FKIOCTL)) { 4443446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT")); 4453446Smrj return (ENXIO); 4463446Smrj } 4473446Smrj 4483446Smrj CONFIRM(IS_IGD(softc)); 4493446Smrj 4503446Smrj if (ddi_copyin((void *)data, &seg, 4513446Smrj sizeof (igd_gtt_seg_t), mode)) 4523446Smrj return (EFAULT); 4533446Smrj 4543446Smrj if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg)) 4553446Smrj return (EINVAL); 4563446Smrj break; 4573446Smrj case I8XX_REM_GTT: 4583446Smrj if (!(mode & FKIOCTL)) { 4593446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT")); 4603446Smrj return (ENXIO); 4613446Smrj } 4623446Smrj 4633446Smrj CONFIRM(IS_IGD(softc)); 4643446Smrj 4653446Smrj if (ddi_copyin((void *)data, &seg, 4663446Smrj sizeof (igd_gtt_seg_t), mode)) 4673446Smrj return (EFAULT); 4683446Smrj 4693446Smrj i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg); 4703446Smrj break; 4713446Smrj case I8XX_UNCONFIG: 4723446Smrj if (!(mode & FKIOCTL)) { 4733446Smrj AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG")); 4743446Smrj return (ENXIO); 4753446Smrj } 4763446Smrj 4773446Smrj CONFIRM(IS_IGD(softc)); 4783446Smrj 4793446Smrj if (softc->agpm_dev_type == DEVICE_IS_I810) 480*4478Skz151634 AGPM_WRITE(softc, PGTBL_CTL, 0); 4813446Smrj /* 4823446Smrj * may need to clear all gtt entries here for i830 series, 4833446Smrj * but may not be necessary 4843446Smrj */ 4853446Smrj break; 4863446Smrj } 4873446Smrj return (0); 4883446Smrj } 4893446Smrj 4903446Smrj /* 4913446Smrj * If AGP cap pointer is successfully found, none-zero value is returned. 4923446Smrj * Otherwise 0 is returned. 4933446Smrj */ 4943446Smrj static off_t 4953446Smrj agpmaster_cap_find(ddi_acc_handle_t acc_handle) 4963446Smrj { 4973446Smrj off_t nextcap; 4983446Smrj uint32_t ncapid; 4993446Smrj uint8_t value; 5003446Smrj 5013446Smrj /* check if this device supports capibility pointer */ 5023446Smrj value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT) 5034303Skz151634 & PCI_CONF_CAP_MASK); 5043446Smrj 5053446Smrj if (!value) 5063446Smrj return (0); 5073446Smrj /* get the offset of the first capability pointer from CAPPTR */ 5083446Smrj nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR)); 5093446Smrj 5103446Smrj /* check AGP capability from the first capability pointer */ 5113446Smrj while (nextcap) { 5123446Smrj ncapid = pci_config_get32(acc_handle, nextcap); 5133446Smrj if ((ncapid & PCI_CONF_CAPID_MASK) 5143446Smrj == AGP_CAP_ID) /* find AGP cap */ 5153446Smrj break; 5163446Smrj 5173446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 5183446Smrj } 5193446Smrj 5203446Smrj return (nextcap); 5213446Smrj 5223446Smrj } 5233446Smrj 5243446Smrj /* 5253446Smrj * If i8xx device is successfully detected, 0 is returned. 5263446Smrj * Otherwise -1 is returned. 5273446Smrj */ 5283446Smrj static int 5293446Smrj detect_i8xx_device(agp_master_softc_t *master_softc) 5303446Smrj { 5313446Smrj 5323446Smrj switch (master_softc->agpm_id) { 5333446Smrj case INTEL_IGD_810: 5343446Smrj case INTEL_IGD_810DC: 5353446Smrj case INTEL_IGD_810E: 5363446Smrj case INTEL_IGD_815: 5373446Smrj master_softc->agpm_dev_type = DEVICE_IS_I810; 5383446Smrj break; 5393446Smrj case INTEL_IGD_830M: 5403446Smrj case INTEL_IGD_845G: 5413446Smrj case INTEL_IGD_855GM: 5423446Smrj case INTEL_IGD_865G: 543*4478Skz151634 case INTEL_IGD_915: 544*4478Skz151634 case INTEL_IGD_915GM: 5453446Smrj case INTEL_IGD_945: 5464303Skz151634 case INTEL_IGD_945GM: 547*4478Skz151634 case INTEL_IGD_946GZ: 548*4478Skz151634 case INTEL_IGD_965G1: 549*4478Skz151634 case INTEL_IGD_965G2: 550*4478Skz151634 case INTEL_IGD_965GM: 551*4478Skz151634 case INTEL_IGD_965Q: 5523446Smrj master_softc->agpm_dev_type = DEVICE_IS_I830; 5533446Smrj break; 5543446Smrj default: /* unknown id */ 5553446Smrj return (-1); 5563446Smrj } 5573446Smrj 5583446Smrj return (0); 5593446Smrj } 5603446Smrj 5613446Smrj /* 5623446Smrj * If agp master is succssfully detected, 0 is returned. 5633446Smrj * Otherwise -1 is returned. 5643446Smrj */ 5653446Smrj static int 5663446Smrj detect_agp_devcice(agp_master_softc_t *master_softc, 5673446Smrj ddi_acc_handle_t acc_handle) 5683446Smrj { 5693446Smrj off_t cap; 5703446Smrj 5713446Smrj cap = agpmaster_cap_find(acc_handle); 5723446Smrj if (cap) { 5733446Smrj master_softc->agpm_dev_type = DEVICE_IS_AGP; 5743446Smrj master_softc->agpm_data.agpm_acaptr = cap; 5753446Smrj return (0); 5763446Smrj } else { 5773446Smrj return (-1); 5783446Smrj } 5793446Smrj 5803446Smrj } 5813446Smrj 5823446Smrj /* 5833446Smrj * Please refer to GART and GTT entry format table in agpdefs.h for 5843446Smrj * intel GTT entry format. 5853446Smrj */ 5863446Smrj static int 5873446Smrj phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry) 5883446Smrj { 5893446Smrj uint32_t value; 5903446Smrj 5913446Smrj switch (type) { 5923446Smrj case AGP_PHYSICAL: 5933446Smrj case AGP_NORMAL: 5943446Smrj value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID; 5953446Smrj break; 5963446Smrj default: 5973446Smrj return (-1); 5983446Smrj } 5993446Smrj 6003446Smrj *entry = value; 6013446Smrj 6023446Smrj return (0); 6033446Smrj } 6043446Smrj 6053446Smrj static int 6063446Smrj i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 6073446Smrj { 6083446Smrj int i; 6093446Smrj uint32_t *paddr; 6103446Smrj uint32_t entry; 6113446Smrj uint32_t maxpages; 6123446Smrj 6133446Smrj maxpages = gtt->gtt_info.igd_apersize; 6143446Smrj maxpages = GTT_MB_TO_PAGES(maxpages); 6153446Smrj 6163446Smrj paddr = seg.igs_phyaddr; 6173446Smrj 6183446Smrj /* check if gtt max page number is reached */ 6193446Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 6203446Smrj return (-1); 6213446Smrj 6223446Smrj paddr = seg.igs_phyaddr; 6233446Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); 6243446Smrj i++, paddr++) { 6253446Smrj if (phys2entry(seg.igs_type, *paddr, &entry)) 6263446Smrj return (-1); 6273446Smrj ddi_put32(gtt->gtt_mmio_handle, 6283446Smrj (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 6293446Smrj entry); 6303446Smrj } 6313446Smrj 6323446Smrj return (0); 6333446Smrj } 6343446Smrj 6353446Smrj static void 6363446Smrj i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 6373446Smrj { 6383446Smrj int i; 6393446Smrj uint32_t maxpages; 6403446Smrj 6413446Smrj maxpages = gtt->gtt_info.igd_apersize; 6423446Smrj maxpages = GTT_MB_TO_PAGES(maxpages); 6433446Smrj 6443446Smrj /* check if gtt max page number is reached */ 6453446Smrj if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 6463446Smrj return; 6473446Smrj 6483446Smrj for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) { 6493446Smrj ddi_put32(gtt->gtt_mmio_handle, 650*4478Skz151634 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 0); 6513446Smrj } 6523446Smrj } 653