14478Skz151634 /* 24478Skz151634 * CDDL HEADER START 34478Skz151634 * 44478Skz151634 * The contents of this file are subject to the terms of the 54478Skz151634 * Common Development and Distribution License (the "License"). 64478Skz151634 * You may not use this file except in compliance with the License. 74478Skz151634 * 84478Skz151634 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94478Skz151634 * or http://www.opensolaris.org/os/licensing. 104478Skz151634 * See the License for the specific language governing permissions 114478Skz151634 * and limitations under the License. 124478Skz151634 * 134478Skz151634 * When distributing Covered Code, include this CDDL HEADER in each 144478Skz151634 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154478Skz151634 * If applicable, add the following below this CDDL HEADER, with the 164478Skz151634 * fields enclosed by brackets "[]" replaced with your own identifying 174478Skz151634 * information: Portions Copyright [yyyy] [name of copyright owner] 184478Skz151634 * 194478Skz151634 * CDDL HEADER END 204478Skz151634 */ 214478Skz151634 223446Smrj /* 23*11260SMiao.Chen@Sun.COM * Copyright (c) 2009, Intel Corporation. 24*11260SMiao.Chen@Sun.COM * All Rights Reserved. 25*11260SMiao.Chen@Sun.COM */ 26*11260SMiao.Chen@Sun.COM 27*11260SMiao.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 #include <sys/systm.h> 343446Smrj #include <sys/conf.h> 353446Smrj #include <sys/modctl.h> 363446Smrj #include <sys/file.h> 373446Smrj #include <sys/stat.h> 383446Smrj #include <sys/ddi.h> 393446Smrj #include <sys/sunddi.h> 40*11260SMiao.Chen@Sun.COM #include <sys/sunndi.h> 413446Smrj #include <sys/modctl.h> 423446Smrj #include <sys/sunldi.h> 433446Smrj #include <sys/pci.h> 443446Smrj #include <sys/agpgart.h> 453446Smrj #include <sys/agp/agpdefs.h> 463446Smrj #include <sys/agp/agptarget_io.h> 473446Smrj 483446Smrj int agptarget_debug_var = 0; 493446Smrj #define TARGETDB_PRINT2(fmt) if (agptarget_debug_var >= 1) cmn_err fmt 503446Smrj #define INST2NODENUM(inst) (inst) 513446Smrj #define DEV2INST(dev) (getminor(dev)) 523446Smrj 53*11260SMiao.Chen@Sun.COM static ddi_device_acc_attr_t dev_attr = { 54*11260SMiao.Chen@Sun.COM DDI_DEVICE_ATTR_V0, 55*11260SMiao.Chen@Sun.COM DDI_NEVERSWAP_ACC, 56*11260SMiao.Chen@Sun.COM DDI_STRICTORDER_ACC, 57*11260SMiao.Chen@Sun.COM }; 58*11260SMiao.Chen@Sun.COM 59*11260SMiao.Chen@Sun.COM static struct _i9xx_private_compat { 60*11260SMiao.Chen@Sun.COM uint64_t physical; /* physical address */ 61*11260SMiao.Chen@Sun.COM uint_t size; /* size of mapping */ 62*11260SMiao.Chen@Sun.COM uint_t regnum; /* register number */ 63*11260SMiao.Chen@Sun.COM caddr_t flush_page; /* kernel virtual address */ 64*11260SMiao.Chen@Sun.COM ddi_acc_handle_t handle; /* data access handle */ 65*11260SMiao.Chen@Sun.COM } i9xx_private; 66*11260SMiao.Chen@Sun.COM 67*11260SMiao.Chen@Sun.COM #define I915_IFPADDR 0x60 68*11260SMiao.Chen@Sun.COM #define I965_IFPADDR 0x70 69*11260SMiao.Chen@Sun.COM 70*11260SMiao.Chen@Sun.COM #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & \ 71*11260SMiao.Chen@Sun.COM 0xFFFFFFFF00000000ULL) >> 32)) 72*11260SMiao.Chen@Sun.COM #define LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 73*11260SMiao.Chen@Sun.COM 74*11260SMiao.Chen@Sun.COM /* 75*11260SMiao.Chen@Sun.COM * Using for GEM to flush the chipset global 76*11260SMiao.Chen@Sun.COM * write buffers on certain intel chipset 77*11260SMiao.Chen@Sun.COM */ 78*11260SMiao.Chen@Sun.COM 79*11260SMiao.Chen@Sun.COM static void 80*11260SMiao.Chen@Sun.COM intel_chipset_flush_setup(dev_info_t *dip, 81*11260SMiao.Chen@Sun.COM ddi_acc_handle_t pci_acc_hdl, 82*11260SMiao.Chen@Sun.COM int gms_off); 83*11260SMiao.Chen@Sun.COM 843446Smrj typedef struct agp_target_softstate { 853446Smrj dev_info_t *tsoft_dip; 863446Smrj ddi_acc_handle_t tsoft_pcihdl; 873446Smrj uint32_t tsoft_devid; 883446Smrj /* The offset of the ACAPID register */ 893446Smrj off_t tsoft_acaptr; 903446Smrj kmutex_t tsoft_lock; 917130Sms148562 int tsoft_gms_off; /* GMS offset in config */ 927130Sms148562 uint32_t tsoft_gms; 933446Smrj }agp_target_softstate_t; 943446Smrj 955036Skz151634 /* 965036Skz151634 * To get the pre-allocated graphics mem size using Graphics Mode Select 975036Skz151634 * (GMS) value. 985036Skz151634 */ 995036Skz151634 typedef struct gms_mode { 1005036Skz151634 uint32_t gm_devid; /* bridge vendor + device id */ 1015036Skz151634 off_t gm_regoff; /* mode selection register offset */ 1025036Skz151634 uint32_t gm_mask; /* GMS mask */ 1035036Skz151634 uint32_t gm_num; /* number of modes in gm_vec */ 1045036Skz151634 int *gm_vec; /* modes array */ 1055036Skz151634 } gms_mode_t; 1065036Skz151634 1073446Smrj static void *agptarget_glob_soft_handle; 1083446Smrj 1093446Smrj #define GETSOFTC(instance) ((agp_target_softstate_t *) \ 1103446Smrj ddi_get_soft_state(agptarget_glob_soft_handle, instance)); 1113446Smrj 1123446Smrj /* 1133446Smrj * The AMD8151 bridge is the only supported 64 bit hardware 1143446Smrj */ 1153446Smrj static int 1163446Smrj is_64bit_aper(agp_target_softstate_t *softstate) 1173446Smrj { 1183446Smrj return (softstate->tsoft_devid == AMD_BR_8151); 1193446Smrj } 1207130Sms148562 1215131Sms148562 /* 1225131Sms148562 * Check if it is an intel bridge 1235131Sms148562 */ 1245131Sms148562 static int 1255131Sms148562 is_intel_br(agp_target_softstate_t *softstate) 1265131Sms148562 { 1275131Sms148562 return ((softstate->tsoft_devid & VENDOR_ID_MASK) == 1285131Sms148562 INTEL_VENDOR_ID); 1295131Sms148562 } 1303446Smrj 1313446Smrj /* 1323446Smrj * agp_target_cap_find() 1333446Smrj * 1343446Smrj * Description: 1353446Smrj * This function searches the linked capability list to find the offset 1363446Smrj * of the AGP capability register. When it was not found, return 0. 1373446Smrj * This works for standard AGP chipsets, but not for some Intel chipsets, 1383446Smrj * like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for 1393446Smrj * these chipsets even if AGP is supported. So the offset of acapid 1403446Smrj * should be set manually in thoses cases. 1413446Smrj * 1423446Smrj * Arguments: 1433446Smrj * pci_handle ddi acc handle of pci config 1443446Smrj * 1453446Smrj * Returns: 1463446Smrj * 0 No capability pointer register found 1473446Smrj * nexcap The AGP capability pointer register offset 1483446Smrj */ 1493446Smrj static off_t 1503446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle) 1513446Smrj { 1523446Smrj off_t nextcap = 0; 1533446Smrj uint32_t ncapid = 0; 1543446Smrj uint8_t value = 0; 1553446Smrj 1563446Smrj /* Check if this device supports the capability pointer */ 1573446Smrj value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT) 1583446Smrj & PCI_CONF_CAP_MASK); 1593446Smrj 1603446Smrj if (!value) 1613446Smrj return (0); 1623446Smrj /* Get the offset of the first capability pointer from CAPPTR */ 1633446Smrj nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR)); 1643446Smrj 1653446Smrj /* Check the AGP capability from the first capability pointer */ 1663446Smrj while (nextcap) { 1673446Smrj ncapid = pci_config_get32(pci_handle, nextcap); 1683446Smrj /* 1693446Smrj * AGP3.0 rev1.0 127 the capid was assigned by the PCI SIG, 1703446Smrj * 845 data sheet page 69 1713446Smrj */ 1723446Smrj if ((ncapid & PCI_CONF_CAPID_MASK) == 1733446Smrj AGP_CAP_ID) /* The AGP cap was found */ 1743446Smrj break; 1753446Smrj 1763446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 1773446Smrj } 1783446Smrj 1793446Smrj return (nextcap); 1803446Smrj 1813446Smrj } 1823446Smrj 1833446Smrj /* 1843446Smrj * agp_target_get_aperbase() 1853446Smrj * 1863446Smrj * Description: 1873446Smrj * This function gets the AGP aperture base address from the AGP target 1883446Smrj * register, the AGP aperture base register was programmed by the BIOS. 1893446Smrj * 1903446Smrj * Arguments: 1913446Smrj * softstate driver soft state pointer 1923446Smrj * 1933446Smrj * Returns: 1943446Smrj * aper_base AGP aperture base address 1953446Smrj * 1963446Smrj * Notes: 1973446Smrj * If a 64bit bridge device is available, the AGP aperture base address 1983446Smrj * can be 64 bit. 1993446Smrj */ 2003446Smrj static uint64_t 2013446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate) 2023446Smrj { 2033446Smrj uint64_t aper_base; 2043446Smrj 2055131Sms148562 if (is_intel_br(softstate)) { 2063446Smrj aper_base = pci_config_get32(softstate->tsoft_pcihdl, 2073446Smrj AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK; 2085131Sms148562 } else if (is_64bit_aper(softstate)) { 2093446Smrj aper_base = pci_config_get64(softstate->tsoft_pcihdl, 2103446Smrj AGP_CONF_APERBASE); 2113446Smrj /* 32-bit or 64-bit aperbase base pointer */ 2123446Smrj if ((aper_base & AGP_APER_TYPE_MASK) == 0) 2133446Smrj aper_base &= AGP_32_APERBASE_MASK; 2143446Smrj else 2153446Smrj aper_base &= AGP_64_APERBASE_MASK; 2163446Smrj } 2175131Sms148562 2183446Smrj return (aper_base); 2193446Smrj } 2203446Smrj 2213446Smrj /* 2223446Smrj * agp_target_get_apsize() 2233446Smrj * 2243446Smrj * Description: 2253446Smrj * This function gets the AGP aperture size by reading the AGP aperture 2263446Smrj * size register. 2273446Smrj * Arguments: 2283446Smrj * softstate driver soft state pointer 2293446Smrj * 2303446Smrj * Return: 2313446Smrj * size The AGP aperture size in megabytes 2323446Smrj * 0 an unexpected error 2333446Smrj */ 2343446Smrj static size_t 2353446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate) 2363446Smrj { 2373446Smrj off_t cap; 2383446Smrj uint16_t value; 2393446Smrj size_t size, regsize; 2403446Smrj 2413446Smrj ASSERT(softstate->tsoft_acaptr); 2423446Smrj cap = softstate->tsoft_acaptr; 2433446Smrj 2445131Sms148562 if (is_intel_br(softstate)) { 2453446Smrj /* extend this value to 16 bit for later tests */ 2463446Smrj value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl, 2473446Smrj cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK; 2485131Sms148562 } else if (is_64bit_aper(softstate)) { 2493446Smrj value = pci_config_get16(softstate->tsoft_pcihdl, 2503446Smrj cap + AGP_CONF_APERSIZE); 2513446Smrj } 2523446Smrj 2533446Smrj if (value & AGP_APER_128M_MASK) { 2543446Smrj switch (value & AGP_APER_128M_MASK) { 2553446Smrj case AGP_APER_4M: 2563446Smrj size = 4; /* 4M */ 2573446Smrj break; 2583446Smrj case AGP_APER_8M: 2593446Smrj size = 8; /* 8M */ 2603446Smrj break; 2613446Smrj case AGP_APER_16M: 2623446Smrj size = 16; /* 16M */ 2633446Smrj break; 2643446Smrj case AGP_APER_32M: 2653446Smrj size = 32; /* 32M */ 2663446Smrj break; 2673446Smrj case AGP_APER_64M: 2683446Smrj size = 64; /* 64M */ 2693446Smrj break; 2703446Smrj case AGP_APER_128M: 2713446Smrj size = 128; /* 128M */ 2723446Smrj break; 2733446Smrj default: 2743446Smrj size = 0; /* not true */ 2753446Smrj } 2763446Smrj } else { 2773446Smrj switch (value & AGP_APER_4G_MASK) { 2783446Smrj case AGP_APER_256M: 2793446Smrj size = 256; /* 256 M */ 2803446Smrj break; 2813446Smrj case AGP_APER_512M: 2823446Smrj size = 512; /* 512 M */ 2833446Smrj break; 2843446Smrj case AGP_APER_1024M: 2853446Smrj size = 1024; /* 1024 M */ 2863446Smrj break; 2873446Smrj case AGP_APER_2048M: 2883446Smrj size = 2048; /* 2048 M */ 2893446Smrj break; 2903446Smrj case AGP_APER_4G: 2913446Smrj size = 4096; /* 4096 M */ 2923446Smrj break; 2933446Smrj default: 2943446Smrj size = 0; /* not true */ 2953446Smrj } 2963446Smrj } 2973446Smrj /* 2983446Smrj * In some cases, there is no APSIZE register, so the size value 2993446Smrj * of 256M could be wrong. Check the value by reading the size of 3003446Smrj * the first register which was set in the PCI configuration space. 3013446Smrj */ 3023446Smrj if (size == 256) { 3033446Smrj if (ddi_dev_regsize(softstate->tsoft_dip, 3043446Smrj AGP_TARGET_BAR1, (off_t *)®size) == DDI_FAILURE) 3053446Smrj return (0); 3063446Smrj 3073446Smrj if (MB2BYTES(size) != regsize) { 3083446Smrj TARGETDB_PRINT2((CE_WARN, 3093446Smrj "APSIZE 256M doesn't match regsize %lx", 3103446Smrj regsize)); 3113446Smrj TARGETDB_PRINT2((CE_WARN, "Use regsize instead")); 3123446Smrj size = BYTES2MB(regsize); 3133446Smrj } 3143446Smrj } 3153446Smrj 3163446Smrj return (size); 3173446Smrj } 3183446Smrj 3193446Smrj static void 3203446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr) 3213446Smrj { 3223446Smrj ASSERT(softstate->tsoft_acaptr); 3233446Smrj 3243446Smrj /* Disable the GTLB for Intel chipsets */ 3253446Smrj pci_config_put16(softstate->tsoft_pcihdl, 3263446Smrj softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000); 3273446Smrj 3283446Smrj pci_config_put32(softstate->tsoft_pcihdl, 3293446Smrj softstate->tsoft_acaptr + AGP_CONF_ATTBASE, 3303446Smrj gartaddr & AGP_ATTBASE_MASK); 3313446Smrj } 3323446Smrj 3335036Skz151634 /* 3345036Skz151634 * Pre-allocated graphics memory for every type of Intel north bridge, mem size 3355036Skz151634 * are specified in kbytes. 3365036Skz151634 */ 3375036Skz151634 #define GMS_MB(n) ((n) * 1024) 3385036Skz151634 #define GMS_SHIFT 4 3395036Skz151634 #define GMS_SIZE(a) (sizeof (a) / sizeof (int)) 3405036Skz151634 3415036Skz151634 /* 3425036Skz151634 * Since value zero always means "No memory pre-allocated", value of (GMS - 1) 3435036Skz151634 * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb) 3445036Skz151634 * that GMS value 0x1 corresponding to. 3455036Skz151634 * 3465036Skz151634 * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics 3475036Skz151634 * memory, unless some special BIOS settings exist. 3485036Skz151634 */ 3495036Skz151634 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)}; 3505036Skz151634 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)}; 3515036Skz151634 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3525036Skz151634 GMS_MB(32)}; 3535036Skz151634 /* There is no modes for 16M in datasheet, but some BIOS add it. */ 3545036Skz151634 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)}; 3555036Skz151634 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)}; 3565036Skz151634 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3575036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64)}; 3585036Skz151634 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3595036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)}; 3607662SMiao.Chen@Sun.COM static int gms_G4X[13] = {0, 0, 0, 0, 3617662SMiao.Chen@Sun.COM GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256), 3627662SMiao.Chen@Sun.COM GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)}; 3635036Skz151634 3645036Skz151634 static gms_mode_t gms_modes[] = { 3655036Skz151634 {INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK, 3665036Skz151634 GMS_SIZE(gms_810), gms_810}, 3675036Skz151634 {INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK, 3685036Skz151634 GMS_SIZE(gms_810), gms_810}, 3695036Skz151634 {INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK, 3705036Skz151634 GMS_SIZE(gms_810), gms_810}, 3715036Skz151634 {INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3725036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 3735036Skz151634 {INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3745036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 3755036Skz151634 {INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3765036Skz151634 GMS_SIZE(gms_855GM), gms_855GM}, 3775036Skz151634 {INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3785036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 3795036Skz151634 {INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3805036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 3815036Skz151634 {INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3825036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3835036Skz151634 {INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3845036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3855036Skz151634 {INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3865036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3878020SMiao.Chen@Sun.COM {INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3888020SMiao.Chen@Sun.COM GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3895036Skz151634 {INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3905036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3915036Skz151634 {INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3925036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3935036Skz151634 {INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3945036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3955036Skz151634 {INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3965036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3975036Skz151634 {INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3985036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 3995036Skz151634 {INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4005036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 4015036Skz151634 {INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK, 4025036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 4035036Skz151634 {INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 4045036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 4055036Skz151634 {INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 4066778Smc196098 GMS_SIZE(gms_X33), gms_X33}, 4076778Smc196098 {INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4087662SMiao.Chen@Sun.COM GMS_SIZE(gms_965GM), gms_965GM}, 4097662SMiao.Chen@Sun.COM {INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4107662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 4117662SMiao.Chen@Sun.COM {INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4127662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 4137662SMiao.Chen@Sun.COM {INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4148832SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 4158832SMiao.Chen@Sun.COM {INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 416*11260SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 417*11260SMiao.Chen@Sun.COM {INTEL_BR_B43, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4187662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X} 4195036Skz151634 }; 4207130Sms148562 static int 4217130Sms148562 get_chip_gms(uint32_t devid) 4227130Sms148562 { 4237130Sms148562 int num_modes; 4247130Sms148562 int i; 4257130Sms148562 4267130Sms148562 num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); 4277130Sms148562 4287130Sms148562 for (i = 0; i < num_modes; i++) { 4297130Sms148562 if (gms_modes[i].gm_devid == devid) 4307130Sms148562 break; 4317130Sms148562 } 4327130Sms148562 4337130Sms148562 return ((i == num_modes) ? -1 : i); 4347130Sms148562 } 4355036Skz151634 4365036Skz151634 /* Returns the size (kbytes) of pre-allocated graphics memory */ 4373446Smrj static size_t 4383446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate) 4393446Smrj { 4403446Smrj uint8_t memval; 4413446Smrj size_t kbytes; 4427130Sms148562 int gms_off; 4433446Smrj 4445036Skz151634 kbytes = 0; 4457130Sms148562 gms_off = softstate->tsoft_gms_off; 4467130Sms148562 4475036Skz151634 /* fetch the GMS value from DRAM controller */ 4485036Skz151634 memval = pci_config_get8(softstate->tsoft_pcihdl, 4497130Sms148562 gms_modes[gms_off].gm_regoff); 4505036Skz151634 TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval)); 4517130Sms148562 memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT; 4525036Skz151634 /* assuming zero byte for 0 or "reserved" GMS values */ 4537130Sms148562 if (memval == 0 || memval > gms_modes[gms_off].gm_num) { 4545036Skz151634 TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: " 4555036Skz151634 "devid = %x, GMS = %x. assuming zero byte of " 4567130Sms148562 "pre-allocated memory", 4577130Sms148562 gms_modes[gms_off].gm_devid, memval)); 4585036Skz151634 goto done; 4595036Skz151634 } 4605036Skz151634 memval--; /* use (GMS_value - 1) as index */ 4617130Sms148562 kbytes = (gms_modes[gms_off].gm_vec)[memval]; 4623446Smrj 4635036Skz151634 done: 4644478Skz151634 TARGETDB_PRINT2((CE_NOTE, 4654478Skz151634 "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected", 4664478Skz151634 kbytes)); 4673446Smrj return (kbytes); 4683446Smrj } 4693446Smrj 4703446Smrj /*ARGSUSED*/ 4713446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 4723446Smrj void *arg, void **resultp) 4733446Smrj { 4743446Smrj agp_target_softstate_t *st; 4753446Smrj int instance, rval = DDI_FAILURE; 4763446Smrj dev_t dev; 4773446Smrj 4783446Smrj switch (cmd) { 4793446Smrj case DDI_INFO_DEVT2DEVINFO: 4803446Smrj dev = (dev_t)arg; 4813446Smrj instance = DEV2INST(dev); 4823446Smrj st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4833446Smrj if (st != NULL) { 4843446Smrj mutex_enter(&st->tsoft_lock); 4853446Smrj *resultp = st->tsoft_dip; 4863446Smrj mutex_exit(&st->tsoft_lock); 4873446Smrj rval = DDI_SUCCESS; 4883446Smrj } else 4893446Smrj *resultp = NULL; 4903446Smrj 4913446Smrj break; 4923446Smrj case DDI_INFO_DEVT2INSTANCE: 4933446Smrj dev = (dev_t)arg; 4943446Smrj instance = DEV2INST(dev); 4953446Smrj *resultp = (void *)(uintptr_t)instance; 4963446Smrj rval = DDI_SUCCESS; 4973446Smrj default: 4983446Smrj break; 4993446Smrj } 5003446Smrj 5013446Smrj return (rval); 5023446Smrj } 5033446Smrj 5043446Smrj static int 5057130Sms148562 intel_br_resume(agp_target_softstate_t *softstate) 5067130Sms148562 { 5077130Sms148562 int gms_off; 5087130Sms148562 5097130Sms148562 gms_off = softstate->tsoft_gms_off; 5107130Sms148562 5117130Sms148562 /* 5127130Sms148562 * We recover the gmch graphics control register here 5137130Sms148562 */ 5147130Sms148562 pci_config_put16(softstate->tsoft_pcihdl, 5157130Sms148562 gms_modes[gms_off].gm_regoff, softstate->tsoft_gms); 5167130Sms148562 5177130Sms148562 return (DDI_SUCCESS); 5187130Sms148562 } 5197130Sms148562 static int 5207130Sms148562 intel_br_suspend(agp_target_softstate_t *softstate) 5217130Sms148562 { 5227130Sms148562 int gms_off; 5237130Sms148562 5247130Sms148562 gms_off = softstate->tsoft_gms_off; 5257130Sms148562 softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl, 5267130Sms148562 gms_modes[gms_off].gm_regoff); 5277130Sms148562 5287130Sms148562 return (DDI_SUCCESS); 5297130Sms148562 } 5307130Sms148562 531*11260SMiao.Chen@Sun.COM static void 532*11260SMiao.Chen@Sun.COM intel_chipset_flush_setup(dev_info_t *dip, 533*11260SMiao.Chen@Sun.COM ddi_acc_handle_t pci_acc_hdl, int gms_off) 534*11260SMiao.Chen@Sun.COM { 535*11260SMiao.Chen@Sun.COM uint32_t temp_hi, temp_lo; 536*11260SMiao.Chen@Sun.COM ndi_ra_request_t request; 537*11260SMiao.Chen@Sun.COM uint64_t answer; 538*11260SMiao.Chen@Sun.COM uint64_t alen; 539*11260SMiao.Chen@Sun.COM pci_regspec_t *regs, *regs2; 540*11260SMiao.Chen@Sun.COM int n_reg, length; 541*11260SMiao.Chen@Sun.COM uint32_t i, regnum, ret; 542*11260SMiao.Chen@Sun.COM ddi_acc_handle_t conf_hdl = pci_acc_hdl; 543*11260SMiao.Chen@Sun.COM uint32_t phys_hi_mask = 0; 544*11260SMiao.Chen@Sun.COM 545*11260SMiao.Chen@Sun.COM bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 546*11260SMiao.Chen@Sun.COM request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED; 547*11260SMiao.Chen@Sun.COM request.ra_boundbase = 0; 548*11260SMiao.Chen@Sun.COM request.ra_boundlen = 0xffffffff; 549*11260SMiao.Chen@Sun.COM request.ra_len = AGP_PAGE_SIZE; 550*11260SMiao.Chen@Sun.COM 551*11260SMiao.Chen@Sun.COM /* IS_I965 || IS_G33 || IS_G4X */ 552*11260SMiao.Chen@Sun.COM if (gms_off > 11) { 553*11260SMiao.Chen@Sun.COM temp_hi = pci_config_get32(conf_hdl, I965_IFPADDR + 4); 554*11260SMiao.Chen@Sun.COM temp_lo = pci_config_get32(conf_hdl, I965_IFPADDR); 555*11260SMiao.Chen@Sun.COM phys_hi_mask |= PCI_ADDR_MEM64 | I965_IFPADDR; 556*11260SMiao.Chen@Sun.COM } else { 557*11260SMiao.Chen@Sun.COM temp_lo = pci_config_get32(conf_hdl, I915_IFPADDR); 558*11260SMiao.Chen@Sun.COM phys_hi_mask |= PCI_ADDR_MEM32 | I915_IFPADDR; 559*11260SMiao.Chen@Sun.COM } 560*11260SMiao.Chen@Sun.COM 561*11260SMiao.Chen@Sun.COM if (!(temp_lo & 0x1)) { 562*11260SMiao.Chen@Sun.COM /* allocate space from the allocator */ 563*11260SMiao.Chen@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip), 564*11260SMiao.Chen@Sun.COM &request, &answer, &alen, 565*11260SMiao.Chen@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS) 566*11260SMiao.Chen@Sun.COM != NDI_SUCCESS) { 567*11260SMiao.Chen@Sun.COM return; 568*11260SMiao.Chen@Sun.COM } 569*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "addr = 0x%x.0x%x len [0x%x]\n", 570*11260SMiao.Chen@Sun.COM HIADDR(answer), 571*11260SMiao.Chen@Sun.COM LOADDR(answer), 572*11260SMiao.Chen@Sun.COM (uint32_t)alen)); 573*11260SMiao.Chen@Sun.COM 574*11260SMiao.Chen@Sun.COM if (gms_off > 11) { 575*11260SMiao.Chen@Sun.COM pci_config_put32(conf_hdl, I965_IFPADDR + 4, 576*11260SMiao.Chen@Sun.COM HIADDR(answer)); 577*11260SMiao.Chen@Sun.COM pci_config_put32(conf_hdl, I965_IFPADDR, 578*11260SMiao.Chen@Sun.COM LOADDR(answer) | 0x1); 579*11260SMiao.Chen@Sun.COM } else { 580*11260SMiao.Chen@Sun.COM pci_config_put32(conf_hdl, I915_IFPADDR, 581*11260SMiao.Chen@Sun.COM LOADDR(answer) | 0x1); 582*11260SMiao.Chen@Sun.COM } 583*11260SMiao.Chen@Sun.COM } 584*11260SMiao.Chen@Sun.COM else 585*11260SMiao.Chen@Sun.COM { 586*11260SMiao.Chen@Sun.COM temp_lo &= ~0x1; 587*11260SMiao.Chen@Sun.COM answer = ((uint64_t)temp_hi << 32) | temp_lo; 588*11260SMiao.Chen@Sun.COM } 589*11260SMiao.Chen@Sun.COM 590*11260SMiao.Chen@Sun.COM temp_hi = pci_config_get32(conf_hdl, I965_IFPADDR + 4); 591*11260SMiao.Chen@Sun.COM temp_lo = pci_config_get32(conf_hdl, I965_IFPADDR); 592*11260SMiao.Chen@Sun.COM 593*11260SMiao.Chen@Sun.COM /* set pci props */ 594*11260SMiao.Chen@Sun.COM if (ddi_dev_nregs(dip, &n_reg) == DDI_FAILURE) { 595*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "init_chipset_flush failed")); 596*11260SMiao.Chen@Sun.COM n_reg = 0; 597*11260SMiao.Chen@Sun.COM return; 598*11260SMiao.Chen@Sun.COM } 599*11260SMiao.Chen@Sun.COM 600*11260SMiao.Chen@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 601*11260SMiao.Chen@Sun.COM "reg", (caddr_t)®s, &length) != 602*11260SMiao.Chen@Sun.COM DDI_PROP_SUCCESS) { 603*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "init_chipset_flush failed!")); 604*11260SMiao.Chen@Sun.COM return; 605*11260SMiao.Chen@Sun.COM } 606*11260SMiao.Chen@Sun.COM 607*11260SMiao.Chen@Sun.COM regnum = length / sizeof (pci_regspec_t); 608*11260SMiao.Chen@Sun.COM 609*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "reg regnum %d", regnum)); 610*11260SMiao.Chen@Sun.COM 611*11260SMiao.Chen@Sun.COM regs2 = kmem_alloc((regnum + 1) * sizeof (pci_regspec_t), KM_SLEEP); 612*11260SMiao.Chen@Sun.COM if (regs2 == NULL) { 613*11260SMiao.Chen@Sun.COM 614*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "init_chipset_flush failed")); 615*11260SMiao.Chen@Sun.COM goto error; 616*11260SMiao.Chen@Sun.COM } 617*11260SMiao.Chen@Sun.COM if (memcpy(regs2, regs, (size_t)length) == NULL) { 618*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "init_chipset_flush failed")); 619*11260SMiao.Chen@Sun.COM kmem_free(regs2, (regnum + 1) * sizeof (pci_regspec_t)); 620*11260SMiao.Chen@Sun.COM goto error; 621*11260SMiao.Chen@Sun.COM } 622*11260SMiao.Chen@Sun.COM 623*11260SMiao.Chen@Sun.COM /* Bus=0, Dev=0, Func=0 0x82001000 */ 624*11260SMiao.Chen@Sun.COM regs2[regnum].pci_phys_hi = PCI_REG_REL_M | phys_hi_mask; 625*11260SMiao.Chen@Sun.COM regs2[regnum].pci_phys_mid = HIADDR(answer); 626*11260SMiao.Chen@Sun.COM regs2[regnum].pci_phys_low = LOADDR(answer); 627*11260SMiao.Chen@Sun.COM regs2[regnum].pci_size_hi = 0x00000000; 628*11260SMiao.Chen@Sun.COM regs2[regnum].pci_size_low = AGP_PAGE_SIZE; 629*11260SMiao.Chen@Sun.COM kmem_free(regs, (size_t)length); 630*11260SMiao.Chen@Sun.COM regs = regs2; 631*11260SMiao.Chen@Sun.COM 632*11260SMiao.Chen@Sun.COM i = ndi_prop_update_int_array(DDI_DEV_T_NONE, 633*11260SMiao.Chen@Sun.COM dip, "reg", (int *)regs, (uint_t)5 * (regnum + 1)); 634*11260SMiao.Chen@Sun.COM if (i != DDI_PROP_SUCCESS) { 635*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "Failed to update reg %d", i)); 636*11260SMiao.Chen@Sun.COM kmem_free(regs2, (regnum + 1) * sizeof (pci_regspec_t)); 637*11260SMiao.Chen@Sun.COM return; 638*11260SMiao.Chen@Sun.COM } 639*11260SMiao.Chen@Sun.COM kmem_free(regs2, (regnum + 1) * sizeof (pci_regspec_t)); 640*11260SMiao.Chen@Sun.COM regs = NULL; 641*11260SMiao.Chen@Sun.COM 642*11260SMiao.Chen@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 643*11260SMiao.Chen@Sun.COM "reg", (caddr_t)®s, &length) != 644*11260SMiao.Chen@Sun.COM DDI_PROP_SUCCESS) { 645*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "init_chipset_flush: failed1!")); 646*11260SMiao.Chen@Sun.COM goto error; 647*11260SMiao.Chen@Sun.COM } 648*11260SMiao.Chen@Sun.COM regnum = length / sizeof (pci_regspec_t); 649*11260SMiao.Chen@Sun.COM kmem_free(regs, (size_t)length); 650*11260SMiao.Chen@Sun.COM 651*11260SMiao.Chen@Sun.COM i9xx_private.physical = answer; 652*11260SMiao.Chen@Sun.COM i9xx_private.size = AGP_PAGE_SIZE; 653*11260SMiao.Chen@Sun.COM i9xx_private.regnum = regnum - 1; 654*11260SMiao.Chen@Sun.COM ret = ddi_regs_map_setup(dip, i9xx_private.regnum, 655*11260SMiao.Chen@Sun.COM (caddr_t *)&(i9xx_private.flush_page), 0, 656*11260SMiao.Chen@Sun.COM i9xx_private.size, &dev_attr, 657*11260SMiao.Chen@Sun.COM (ddi_acc_handle_t *)&i9xx_private.handle); 658*11260SMiao.Chen@Sun.COM 659*11260SMiao.Chen@Sun.COM if (ret != DDI_SUCCESS) { 660*11260SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, "chipset_flush do_ioremap failed ")); 661*11260SMiao.Chen@Sun.COM i9xx_private.handle = NULL; 662*11260SMiao.Chen@Sun.COM return; 663*11260SMiao.Chen@Sun.COM } 664*11260SMiao.Chen@Sun.COM return; 665*11260SMiao.Chen@Sun.COM error: 666*11260SMiao.Chen@Sun.COM if (regs) 667*11260SMiao.Chen@Sun.COM kmem_free(regs, (size_t)length); 668*11260SMiao.Chen@Sun.COM } 669*11260SMiao.Chen@Sun.COM 6707130Sms148562 static int 6713446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6723446Smrj { 6733446Smrj agp_target_softstate_t *softstate; 6743446Smrj int instance; 6753446Smrj int status; 6763446Smrj 6773446Smrj instance = ddi_get_instance(dip); 6783446Smrj 6797130Sms148562 switch (cmd) { 6807130Sms148562 case DDI_ATTACH: 6817130Sms148562 break; 6827130Sms148562 case DDI_RESUME: 6837130Sms148562 softstate = 6847130Sms148562 ddi_get_soft_state(agptarget_glob_soft_handle, instance); 6857130Sms148562 return (intel_br_resume(softstate)); 6867130Sms148562 default: 6877130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 6887130Sms148562 "only attach and resume ops are supported")); 6893446Smrj return (DDI_FAILURE); 6907130Sms148562 } 6917130Sms148562 6927130Sms148562 if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, 6937130Sms148562 instance) != DDI_SUCCESS) { 6947130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 6957130Sms148562 "soft state zalloc failed")); 6967130Sms148562 return (DDI_FAILURE); 6977130Sms148562 } 6983446Smrj 6993446Smrj softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 7003446Smrj mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 7013446Smrj softstate->tsoft_dip = dip; 7023446Smrj status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 7033446Smrj if (status != DDI_SUCCESS) { 7047130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7057130Sms148562 "pci config setup failed")); 7067130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 7077130Sms148562 instance); 7083446Smrj return (DDI_FAILURE); 7093446Smrj } 7103446Smrj 7113446Smrj softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 7123446Smrj PCI_CONF_VENID); 7137130Sms148562 softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid); 7147130Sms148562 if (softstate->tsoft_gms_off < 0) { 7157130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7167130Sms148562 "read gms offset failed")); 7177130Sms148562 pci_config_teardown(&softstate->tsoft_pcihdl); 7187130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 7197130Sms148562 instance); 7207130Sms148562 return (DDI_FAILURE); 7217130Sms148562 } 7223446Smrj softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 7233446Smrj if (softstate->tsoft_acaptr == 0) { 7243446Smrj /* Make a correction for some Intel chipsets */ 7255131Sms148562 if (is_intel_br(softstate)) 7263446Smrj softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 7277130Sms148562 else { 7287130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7297130Sms148562 "Not a supposed corretion")); 7307130Sms148562 pci_config_teardown(&softstate->tsoft_pcihdl); 7317130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 7327130Sms148562 instance); 7333446Smrj return (DDI_FAILURE); 7347130Sms148562 } 7353446Smrj } 7363446Smrj 7373446Smrj status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 7383446Smrj INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 7393446Smrj 7403446Smrj if (status != DDI_SUCCESS) { 7417130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7427130Sms148562 "Create minor node failed")); 7433446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 7443446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 7453446Smrj return (DDI_FAILURE); 7463446Smrj } 7473446Smrj 7483446Smrj return (DDI_SUCCESS); 7493446Smrj } 7503446Smrj 7513446Smrj /*ARGSUSED*/ 7523446Smrj static int 7533446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7543446Smrj { 7553446Smrj int instance; 7563446Smrj agp_target_softstate_t *softstate; 7573446Smrj 7587130Sms148562 instance = ddi_get_instance(dip); 7597130Sms148562 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 7603446Smrj 7617130Sms148562 if (cmd == DDI_SUSPEND) { 7627130Sms148562 /* get GMS modes list entry */ 7637130Sms148562 return (intel_br_suspend(softstate)); 7647130Sms148562 } 7653446Smrj 7667130Sms148562 if (cmd != DDI_DETACH) { 7677130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_detach:" 7687130Sms148562 "only detach and suspend ops are supported")); 7697130Sms148562 return (DDI_FAILURE); 7707130Sms148562 } 7713446Smrj 7723446Smrj ddi_remove_minor_node(dip, AGPTARGET_NAME); 7733446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 7743446Smrj mutex_destroy(&softstate->tsoft_lock); 7753446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 7763446Smrj return (DDI_SUCCESS); 7773446Smrj } 7783446Smrj 7793446Smrj /*ARGSUSED*/ 7803446Smrj static int 7813446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 7823446Smrj cred_t *cred, int *rval) 7833446Smrj { 7843446Smrj int instance = DEV2INST(dev); 7853446Smrj agp_target_softstate_t *st; 7863446Smrj static char kernel_only[] = 7873446Smrj "amd64_gart_ioctl: is a kernel only ioctl"; 7883446Smrj 7893446Smrj if (!(mode & FKIOCTL)) { 7903446Smrj TARGETDB_PRINT2((CE_CONT, kernel_only)); 7913446Smrj return (ENXIO); 7923446Smrj } 7933446Smrj st = GETSOFTC(instance); 7943446Smrj 7953446Smrj if (st == NULL) 7963446Smrj return (ENXIO); 7973446Smrj 7983446Smrj mutex_enter(&st->tsoft_lock); 7993446Smrj 8003446Smrj switch (cmd) { 8013446Smrj case CHIP_DETECT: 8023446Smrj { 8035131Sms148562 int type = 0; 8045131Sms148562 8055131Sms148562 if (is_intel_br(st)) 8063446Smrj type = CHIP_IS_INTEL; 8075131Sms148562 else if (is_64bit_aper(st)) 8083446Smrj type = CHIP_IS_AMD; 8095131Sms148562 else { 8103446Smrj type = 0; 8115131Sms148562 TARGETDB_PRINT2((CE_WARN, "Unknown bridge!")); 8123446Smrj } 8135131Sms148562 8143446Smrj if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 8153446Smrj mutex_exit(&st->tsoft_lock); 8163446Smrj return (EFAULT); 8173446Smrj } 8183446Smrj 8193446Smrj break; 8203446Smrj } 8213446Smrj case I8XX_GET_PREALLOC_SIZE: 8223446Smrj { 8233446Smrj size_t prealloc_size; 8243446Smrj 8255131Sms148562 if (!is_intel_br(st)) { 8263446Smrj mutex_exit(&st->tsoft_lock); 8273446Smrj return (EINVAL); 8283446Smrj } 8293446Smrj 8303446Smrj prealloc_size = i8xx_biosmem_detect(st); 8313446Smrj if (ddi_copyout(&prealloc_size, (void *)data, 8323446Smrj sizeof (size_t), mode)) { 8333446Smrj mutex_exit(&st->tsoft_lock); 8343446Smrj return (EFAULT); 8353446Smrj } 8363446Smrj 8373446Smrj break; 8383446Smrj } 8393446Smrj case AGP_TARGET_GETINFO: 8403446Smrj { 8413446Smrj i_agp_info_t info; 8423446Smrj uint32_t value; 8433446Smrj off_t cap; 8443446Smrj 8453446Smrj ASSERT(st->tsoft_acaptr); 8463446Smrj 8473446Smrj cap = st->tsoft_acaptr; 8483446Smrj value = pci_config_get32(st->tsoft_pcihdl, cap); 8493446Smrj info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 8503446Smrj info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 8513446Smrj info.iagp_devid = st->tsoft_devid; 8523446Smrj info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 8534303Skz151634 cap + AGP_CONF_STATUS); 8543446Smrj info.iagp_aperbase = agp_target_get_apbase(st); 8553446Smrj info.iagp_apersize = agp_target_get_apsize(st); 8563446Smrj 8573446Smrj if (ddi_copyout(&info, (void *)data, 8583446Smrj sizeof (i_agp_info_t), mode)) { 8593446Smrj mutex_exit(&st->tsoft_lock); 8603446Smrj return (EFAULT); 8613446Smrj } 8623446Smrj break; 8633446Smrj 8643446Smrj } 8653446Smrj /* 8663446Smrj * This ioctl is only for Intel AGP chipsets. 8673446Smrj * It is not necessary for the AMD8151 AGP bridge, because 8683446Smrj * this register in the AMD8151 does not control any hardware. 8693446Smrj * It is only provided for compatibility with an Intel AGP bridge. 8703446Smrj * Please refer to the <<AMD8151 data sheet>> page 24, 8713446Smrj * AGP device GART pointer. 8723446Smrj */ 8733446Smrj case AGP_TARGET_SET_GATTADDR: 8743446Smrj { 8753446Smrj uint32_t gartaddr; 8763446Smrj 8773446Smrj if (ddi_copyin((void *)data, &gartaddr, 8783446Smrj sizeof (uint32_t), mode)) { 8793446Smrj mutex_exit(&st->tsoft_lock); 8803446Smrj return (EFAULT); 8813446Smrj } 8823446Smrj 8833446Smrj agp_target_set_gartaddr(st, gartaddr); 8843446Smrj break; 8853446Smrj } 8863446Smrj case AGP_TARGET_SETCMD: 8873446Smrj { 8883446Smrj uint32_t command; 8893446Smrj 8903446Smrj if (ddi_copyin((void *)data, &command, 8913446Smrj sizeof (uint32_t), mode)) { 8923446Smrj mutex_exit(&st->tsoft_lock); 8933446Smrj return (EFAULT); 8943446Smrj } 8953446Smrj 8963446Smrj ASSERT(st->tsoft_acaptr); 8973446Smrj 8983446Smrj pci_config_put32(st->tsoft_pcihdl, 8993446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 9003446Smrj command); 9013446Smrj break; 9023446Smrj 9033446Smrj } 9043446Smrj case AGP_TARGET_FLUSH_GTLB: 9053446Smrj { 9063446Smrj uint16_t value; 9073446Smrj 9083446Smrj ASSERT(st->tsoft_acaptr); 9093446Smrj 9103446Smrj value = pci_config_get16(st->tsoft_pcihdl, 9113446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL); 9123446Smrj value &= ~AGPCTRL_GTLBEN; 9133446Smrj pci_config_put16(st->tsoft_pcihdl, 9143446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 9153446Smrj value |= AGPCTRL_GTLBEN; 9163446Smrj pci_config_put16(st->tsoft_pcihdl, 9173446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 9183446Smrj 9193446Smrj break; 9203446Smrj } 9213446Smrj case AGP_TARGET_CONFIGURE: 9223446Smrj { 9233446Smrj uint8_t value; 9243446Smrj 9253446Smrj ASSERT(st->tsoft_acaptr); 9263446Smrj 9275131Sms148562 /* 9285131Sms148562 * In Intel agp bridges, agp misc register offset 9295131Sms148562 * is indexed from 0 instead of capability register. 9305131Sms148562 * AMD agp bridges have no such misc register 9315131Sms148562 * to control the aperture access, and they have 9325131Sms148562 * similar regsiters in CPU gart devices instead. 9335131Sms148562 */ 9345131Sms148562 9355131Sms148562 if (is_intel_br(st)) { 9365131Sms148562 value = pci_config_get8(st->tsoft_pcihdl, 9375131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC); 9385131Sms148562 value |= AGP_MISC_APEN; 9395131Sms148562 pci_config_put8(st->tsoft_pcihdl, 9405131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC, value); 9415131Sms148562 } 9423446Smrj break; 9433446Smrj 9443446Smrj } 9453446Smrj case AGP_TARGET_UNCONFIG: 9463446Smrj { 9473446Smrj uint32_t value1; 9483446Smrj uint8_t value2; 9493446Smrj 9503446Smrj ASSERT(st->tsoft_acaptr); 9513446Smrj 9523446Smrj pci_config_put16(st->tsoft_pcihdl, 9533446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 9543446Smrj 9555131Sms148562 if (is_intel_br(st)) { 9565131Sms148562 value2 = pci_config_get8(st->tsoft_pcihdl, 9575131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC); 9585131Sms148562 value2 &= ~AGP_MISC_APEN; 9595131Sms148562 pci_config_put8(st->tsoft_pcihdl, 9605131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC, value2); 9615131Sms148562 } 9623446Smrj 9633446Smrj value1 = pci_config_get32(st->tsoft_pcihdl, 9643446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND); 9653446Smrj value1 &= ~AGPCMD_AGPEN; 9663446Smrj pci_config_put32(st->tsoft_pcihdl, 9673446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 9683446Smrj value1); 9693446Smrj 9703446Smrj pci_config_put32(st->tsoft_pcihdl, 9713446Smrj st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 9723446Smrj 9733446Smrj break; 9743446Smrj } 9753446Smrj 976*11260SMiao.Chen@Sun.COM case INTEL_CHIPSET_FLUSH_SETUP: 977*11260SMiao.Chen@Sun.COM { 978*11260SMiao.Chen@Sun.COM intel_chipset_flush_setup(st->tsoft_dip, 979*11260SMiao.Chen@Sun.COM st->tsoft_pcihdl, st->tsoft_gms_off); 980*11260SMiao.Chen@Sun.COM break; 981*11260SMiao.Chen@Sun.COM } 982*11260SMiao.Chen@Sun.COM case INTEL_CHIPSET_FLUSH: 983*11260SMiao.Chen@Sun.COM { 984*11260SMiao.Chen@Sun.COM if (i9xx_private.handle != NULL) 985*11260SMiao.Chen@Sun.COM ddi_put32(i9xx_private.handle, 986*11260SMiao.Chen@Sun.COM (uint32_t *)(uintptr_t)i9xx_private.flush_page, 1); 987*11260SMiao.Chen@Sun.COM 988*11260SMiao.Chen@Sun.COM break; 989*11260SMiao.Chen@Sun.COM } 990*11260SMiao.Chen@Sun.COM case INTEL_CHIPSET_FLUSH_FREE: 991*11260SMiao.Chen@Sun.COM { 992*11260SMiao.Chen@Sun.COM if (i9xx_private.handle != NULL) { 993*11260SMiao.Chen@Sun.COM ddi_regs_map_free( 994*11260SMiao.Chen@Sun.COM (ddi_acc_handle_t *)&i9xx_private.handle); 995*11260SMiao.Chen@Sun.COM i9xx_private.handle = NULL; 996*11260SMiao.Chen@Sun.COM } 997*11260SMiao.Chen@Sun.COM break; 998*11260SMiao.Chen@Sun.COM } 9993446Smrj default: 10003446Smrj mutex_exit(&st->tsoft_lock); 10013446Smrj return (ENXIO); 10023446Smrj } /* end switch */ 10033446Smrj 10043446Smrj mutex_exit(&st->tsoft_lock); 10053446Smrj 10063446Smrj return (0); 10073446Smrj } 10083446Smrj 10093446Smrj /*ARGSUSED*/ 10103446Smrj static int 10113446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 10123446Smrj { 10133446Smrj int instance = DEV2INST(*devp); 10143446Smrj agp_target_softstate_t *st; 10153446Smrj 10163446Smrj if (!(flag & FKLYR)) 10173446Smrj return (ENXIO); 10183446Smrj 10193446Smrj st = GETSOFTC(instance); 10203446Smrj 10213446Smrj if (st == NULL) 10223446Smrj return (ENXIO); 10233446Smrj 10243446Smrj return (0); 10253446Smrj } 10263446Smrj 10273446Smrj /*ARGSUSED*/ 10283446Smrj static int 10293446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 10303446Smrj { 10313446Smrj int instance = DEV2INST(dev); 10323446Smrj agp_target_softstate_t *st; 10333446Smrj 10343446Smrj st = GETSOFTC(instance); 10353446Smrj 10363446Smrj if (st == NULL) 10373446Smrj return (ENXIO); 10383446Smrj 10393446Smrj return (0); 10403446Smrj } 10413446Smrj 10423446Smrj static struct cb_ops agp_target_cb_ops = { 10433446Smrj agp_target_open, /* cb_open */ 10443446Smrj agp_target_close, /* cb_close */ 10453446Smrj nodev, /* cb_strategy */ 10463446Smrj nodev, /* cb_print */ 10473446Smrj nodev, /* cb_dump */ 10483446Smrj nodev, /* cb_read() */ 10493446Smrj nodev, /* cb_write() */ 10503446Smrj agp_target_ioctl, /* cb_ioctl */ 10513446Smrj nodev, /* cb_devmap */ 10523446Smrj nodev, /* cb_mmap */ 10533446Smrj nodev, /* cb_segmap */ 10543446Smrj nochpoll, /* cb_chpoll */ 10553446Smrj ddi_prop_op, /* cb_prop_op */ 10563446Smrj 0, /* cb_stream */ 10573446Smrj D_NEW | D_MP, /* cb_flag */ 10583446Smrj CB_REV, /* cb_ops version? */ 10593446Smrj nodev, /* cb_aread() */ 10603446Smrj nodev, /* cb_awrite() */ 10613446Smrj }; 10623446Smrj 10633446Smrj /* device operations */ 10643446Smrj static struct dev_ops agp_target_ops = { 10653446Smrj DEVO_REV, /* devo_rev */ 10663446Smrj 0, /* devo_refcnt */ 10673446Smrj agptarget_getinfo, /* devo_getinfo */ 10683446Smrj nulldev, /* devo_identify */ 10693446Smrj nulldev, /* devo_probe */ 10703446Smrj agp_target_attach, /* devo_attach */ 10713446Smrj agp_target_detach, /* devo_detach */ 10723446Smrj nodev, /* devo_reset */ 10733446Smrj &agp_target_cb_ops, /* devo_cb_ops */ 10743446Smrj 0, /* devo_bus_ops */ 10753446Smrj 0, /* devo_power */ 10768328SMiao.Chen@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */ 10773446Smrj }; 10783446Smrj 10793446Smrj static struct modldrv modldrv = { 10803446Smrj &mod_driverops, 10817130Sms148562 "AGP target driver", 10823446Smrj &agp_target_ops, 10833446Smrj }; 10843446Smrj 10853446Smrj static struct modlinkage modlinkage = { 10863446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 10873446Smrj {&modldrv, NULL, NULL, NULL} 10883446Smrj }; 10893446Smrj 10903446Smrj int 10913446Smrj _init(void) 10923446Smrj { 10933446Smrj int ret; 10943446Smrj 10953446Smrj ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 10963446Smrj sizeof (agp_target_softstate_t), 1); 10973446Smrj 10983446Smrj if (ret) 10993446Smrj goto err1; 11003446Smrj 11013446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 11023446Smrj goto err2; 11033446Smrj } 11043446Smrj 11053446Smrj return (DDI_SUCCESS); 11063446Smrj err2: 11073446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 11083446Smrj err1: 11093446Smrj return (ret); 11103446Smrj } 11113446Smrj 11123446Smrj int 11133446Smrj _info(struct modinfo *modinfop) 11143446Smrj { 11153446Smrj return (mod_info(&modlinkage, modinfop)); 11163446Smrj } 11173446Smrj 11183446Smrj int 11193446Smrj _fini(void) 11203446Smrj { 11213446Smrj int ret; 11223446Smrj 11233446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 11243446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 11253446Smrj } 11263446Smrj return (ret); 11273446Smrj } 1128