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 /* 2311260SMiao.Chen@Sun.COM * Copyright (c) 2009, Intel Corporation. 2411260SMiao.Chen@Sun.COM * All Rights Reserved. 2511260SMiao.Chen@Sun.COM */ 2611260SMiao.Chen@Sun.COM 2711260SMiao.Chen@Sun.COM /* 288832SMiao.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 293446Smrj * Use is subject to license terms. 303446Smrj */ 313446Smrj 323446Smrj 333446Smrj #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> 4011260SMiao.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 5311260SMiao.Chen@Sun.COM static ddi_device_acc_attr_t dev_attr = { 5411260SMiao.Chen@Sun.COM DDI_DEVICE_ATTR_V0, 5511260SMiao.Chen@Sun.COM DDI_NEVERSWAP_ACC, 5611260SMiao.Chen@Sun.COM DDI_STRICTORDER_ACC, 5711260SMiao.Chen@Sun.COM }; 5811260SMiao.Chen@Sun.COM 5911260SMiao.Chen@Sun.COM static struct _i9xx_private_compat { 6011260SMiao.Chen@Sun.COM uint64_t physical; /* physical address */ 6111260SMiao.Chen@Sun.COM uint_t size; /* size of mapping */ 6211260SMiao.Chen@Sun.COM uint_t regnum; /* register number */ 6311260SMiao.Chen@Sun.COM caddr_t flush_page; /* kernel virtual address */ 6411260SMiao.Chen@Sun.COM ddi_acc_handle_t handle; /* data access handle */ 65*11359SMiao.Chen@Sun.COM uint_t ra_alloced; 66*11359SMiao.Chen@Sun.COM } i9xx_private = {0, 0, 0, 0, 0, 0}; 6711260SMiao.Chen@Sun.COM 6811260SMiao.Chen@Sun.COM #define I915_IFPADDR 0x60 6911260SMiao.Chen@Sun.COM #define I965_IFPADDR 0x70 7011260SMiao.Chen@Sun.COM 7111260SMiao.Chen@Sun.COM #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & \ 7211260SMiao.Chen@Sun.COM 0xFFFFFFFF00000000ULL) >> 32)) 7311260SMiao.Chen@Sun.COM #define LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 7411260SMiao.Chen@Sun.COM 7511260SMiao.Chen@Sun.COM /* 7611260SMiao.Chen@Sun.COM * Using for GEM to flush the chipset global 7711260SMiao.Chen@Sun.COM * write buffers on certain intel chipset 7811260SMiao.Chen@Sun.COM */ 7911260SMiao.Chen@Sun.COM 8011260SMiao.Chen@Sun.COM static void 8111260SMiao.Chen@Sun.COM intel_chipset_flush_setup(dev_info_t *dip, 8211260SMiao.Chen@Sun.COM ddi_acc_handle_t pci_acc_hdl, 8311260SMiao.Chen@Sun.COM int gms_off); 8411260SMiao.Chen@Sun.COM 853446Smrj typedef struct agp_target_softstate { 863446Smrj dev_info_t *tsoft_dip; 873446Smrj ddi_acc_handle_t tsoft_pcihdl; 883446Smrj uint32_t tsoft_devid; 893446Smrj /* The offset of the ACAPID register */ 903446Smrj off_t tsoft_acaptr; 913446Smrj kmutex_t tsoft_lock; 927130Sms148562 int tsoft_gms_off; /* GMS offset in config */ 937130Sms148562 uint32_t tsoft_gms; 943446Smrj }agp_target_softstate_t; 953446Smrj 965036Skz151634 /* 975036Skz151634 * To get the pre-allocated graphics mem size using Graphics Mode Select 985036Skz151634 * (GMS) value. 995036Skz151634 */ 1005036Skz151634 typedef struct gms_mode { 1015036Skz151634 uint32_t gm_devid; /* bridge vendor + device id */ 1025036Skz151634 off_t gm_regoff; /* mode selection register offset */ 1035036Skz151634 uint32_t gm_mask; /* GMS mask */ 1045036Skz151634 uint32_t gm_num; /* number of modes in gm_vec */ 1055036Skz151634 int *gm_vec; /* modes array */ 1065036Skz151634 } gms_mode_t; 1075036Skz151634 1083446Smrj static void *agptarget_glob_soft_handle; 1093446Smrj 1103446Smrj #define GETSOFTC(instance) ((agp_target_softstate_t *) \ 1113446Smrj ddi_get_soft_state(agptarget_glob_soft_handle, instance)); 1123446Smrj 1133446Smrj /* 1143446Smrj * The AMD8151 bridge is the only supported 64 bit hardware 1153446Smrj */ 1163446Smrj static int 1173446Smrj is_64bit_aper(agp_target_softstate_t *softstate) 1183446Smrj { 1193446Smrj return (softstate->tsoft_devid == AMD_BR_8151); 1203446Smrj } 1217130Sms148562 1225131Sms148562 /* 1235131Sms148562 * Check if it is an intel bridge 1245131Sms148562 */ 1255131Sms148562 static int 1265131Sms148562 is_intel_br(agp_target_softstate_t *softstate) 1275131Sms148562 { 1285131Sms148562 return ((softstate->tsoft_devid & VENDOR_ID_MASK) == 1295131Sms148562 INTEL_VENDOR_ID); 1305131Sms148562 } 1313446Smrj 1323446Smrj /* 1333446Smrj * agp_target_cap_find() 1343446Smrj * 1353446Smrj * Description: 1363446Smrj * This function searches the linked capability list to find the offset 1373446Smrj * of the AGP capability register. When it was not found, return 0. 1383446Smrj * This works for standard AGP chipsets, but not for some Intel chipsets, 1393446Smrj * like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for 1403446Smrj * these chipsets even if AGP is supported. So the offset of acapid 1413446Smrj * should be set manually in thoses cases. 1423446Smrj * 1433446Smrj * Arguments: 1443446Smrj * pci_handle ddi acc handle of pci config 1453446Smrj * 1463446Smrj * Returns: 1473446Smrj * 0 No capability pointer register found 1483446Smrj * nexcap The AGP capability pointer register offset 1493446Smrj */ 1503446Smrj static off_t 1513446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle) 1523446Smrj { 1533446Smrj off_t nextcap = 0; 1543446Smrj uint32_t ncapid = 0; 1553446Smrj uint8_t value = 0; 1563446Smrj 1573446Smrj /* Check if this device supports the capability pointer */ 1583446Smrj value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT) 1593446Smrj & PCI_CONF_CAP_MASK); 1603446Smrj 1613446Smrj if (!value) 1623446Smrj return (0); 1633446Smrj /* Get the offset of the first capability pointer from CAPPTR */ 1643446Smrj nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR)); 1653446Smrj 1663446Smrj /* Check the AGP capability from the first capability pointer */ 1673446Smrj while (nextcap) { 1683446Smrj ncapid = pci_config_get32(pci_handle, nextcap); 1693446Smrj /* 1703446Smrj * AGP3.0 rev1.0 127 the capid was assigned by the PCI SIG, 1713446Smrj * 845 data sheet page 69 1723446Smrj */ 1733446Smrj if ((ncapid & PCI_CONF_CAPID_MASK) == 1743446Smrj AGP_CAP_ID) /* The AGP cap was found */ 1753446Smrj break; 1763446Smrj 1773446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 1783446Smrj } 1793446Smrj 1803446Smrj return (nextcap); 1813446Smrj 1823446Smrj } 1833446Smrj 1843446Smrj /* 1853446Smrj * agp_target_get_aperbase() 1863446Smrj * 1873446Smrj * Description: 1883446Smrj * This function gets the AGP aperture base address from the AGP target 1893446Smrj * register, the AGP aperture base register was programmed by the BIOS. 1903446Smrj * 1913446Smrj * Arguments: 1923446Smrj * softstate driver soft state pointer 1933446Smrj * 1943446Smrj * Returns: 1953446Smrj * aper_base AGP aperture base address 1963446Smrj * 1973446Smrj * Notes: 1983446Smrj * If a 64bit bridge device is available, the AGP aperture base address 1993446Smrj * can be 64 bit. 2003446Smrj */ 2013446Smrj static uint64_t 2023446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate) 2033446Smrj { 2043446Smrj uint64_t aper_base; 2053446Smrj 2065131Sms148562 if (is_intel_br(softstate)) { 2073446Smrj aper_base = pci_config_get32(softstate->tsoft_pcihdl, 2083446Smrj AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK; 2095131Sms148562 } else if (is_64bit_aper(softstate)) { 2103446Smrj aper_base = pci_config_get64(softstate->tsoft_pcihdl, 2113446Smrj AGP_CONF_APERBASE); 2123446Smrj /* 32-bit or 64-bit aperbase base pointer */ 2133446Smrj if ((aper_base & AGP_APER_TYPE_MASK) == 0) 2143446Smrj aper_base &= AGP_32_APERBASE_MASK; 2153446Smrj else 2163446Smrj aper_base &= AGP_64_APERBASE_MASK; 2173446Smrj } 2185131Sms148562 2193446Smrj return (aper_base); 2203446Smrj } 2213446Smrj 2223446Smrj /* 2233446Smrj * agp_target_get_apsize() 2243446Smrj * 2253446Smrj * Description: 2263446Smrj * This function gets the AGP aperture size by reading the AGP aperture 2273446Smrj * size register. 2283446Smrj * Arguments: 2293446Smrj * softstate driver soft state pointer 2303446Smrj * 2313446Smrj * Return: 2323446Smrj * size The AGP aperture size in megabytes 2333446Smrj * 0 an unexpected error 2343446Smrj */ 2353446Smrj static size_t 2363446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate) 2373446Smrj { 2383446Smrj off_t cap; 2393446Smrj uint16_t value; 2403446Smrj size_t size, regsize; 2413446Smrj 2423446Smrj ASSERT(softstate->tsoft_acaptr); 2433446Smrj cap = softstate->tsoft_acaptr; 2443446Smrj 2455131Sms148562 if (is_intel_br(softstate)) { 2463446Smrj /* extend this value to 16 bit for later tests */ 2473446Smrj value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl, 2483446Smrj cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK; 2495131Sms148562 } else if (is_64bit_aper(softstate)) { 2503446Smrj value = pci_config_get16(softstate->tsoft_pcihdl, 2513446Smrj cap + AGP_CONF_APERSIZE); 2523446Smrj } 2533446Smrj 2543446Smrj if (value & AGP_APER_128M_MASK) { 2553446Smrj switch (value & AGP_APER_128M_MASK) { 2563446Smrj case AGP_APER_4M: 2573446Smrj size = 4; /* 4M */ 2583446Smrj break; 2593446Smrj case AGP_APER_8M: 2603446Smrj size = 8; /* 8M */ 2613446Smrj break; 2623446Smrj case AGP_APER_16M: 2633446Smrj size = 16; /* 16M */ 2643446Smrj break; 2653446Smrj case AGP_APER_32M: 2663446Smrj size = 32; /* 32M */ 2673446Smrj break; 2683446Smrj case AGP_APER_64M: 2693446Smrj size = 64; /* 64M */ 2703446Smrj break; 2713446Smrj case AGP_APER_128M: 2723446Smrj size = 128; /* 128M */ 2733446Smrj break; 2743446Smrj default: 2753446Smrj size = 0; /* not true */ 2763446Smrj } 2773446Smrj } else { 2783446Smrj switch (value & AGP_APER_4G_MASK) { 2793446Smrj case AGP_APER_256M: 2803446Smrj size = 256; /* 256 M */ 2813446Smrj break; 2823446Smrj case AGP_APER_512M: 2833446Smrj size = 512; /* 512 M */ 2843446Smrj break; 2853446Smrj case AGP_APER_1024M: 2863446Smrj size = 1024; /* 1024 M */ 2873446Smrj break; 2883446Smrj case AGP_APER_2048M: 2893446Smrj size = 2048; /* 2048 M */ 2903446Smrj break; 2913446Smrj case AGP_APER_4G: 2923446Smrj size = 4096; /* 4096 M */ 2933446Smrj break; 2943446Smrj default: 2953446Smrj size = 0; /* not true */ 2963446Smrj } 2973446Smrj } 2983446Smrj /* 2993446Smrj * In some cases, there is no APSIZE register, so the size value 3003446Smrj * of 256M could be wrong. Check the value by reading the size of 3013446Smrj * the first register which was set in the PCI configuration space. 3023446Smrj */ 3033446Smrj if (size == 256) { 3043446Smrj if (ddi_dev_regsize(softstate->tsoft_dip, 3053446Smrj AGP_TARGET_BAR1, (off_t *)®size) == DDI_FAILURE) 3063446Smrj return (0); 3073446Smrj 3083446Smrj if (MB2BYTES(size) != regsize) { 3093446Smrj TARGETDB_PRINT2((CE_WARN, 3103446Smrj "APSIZE 256M doesn't match regsize %lx", 3113446Smrj regsize)); 3123446Smrj TARGETDB_PRINT2((CE_WARN, "Use regsize instead")); 3133446Smrj size = BYTES2MB(regsize); 3143446Smrj } 3153446Smrj } 3163446Smrj 3173446Smrj return (size); 3183446Smrj } 3193446Smrj 3203446Smrj static void 3213446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr) 3223446Smrj { 3233446Smrj ASSERT(softstate->tsoft_acaptr); 3243446Smrj 3253446Smrj /* Disable the GTLB for Intel chipsets */ 3263446Smrj pci_config_put16(softstate->tsoft_pcihdl, 3273446Smrj softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000); 3283446Smrj 3293446Smrj pci_config_put32(softstate->tsoft_pcihdl, 3303446Smrj softstate->tsoft_acaptr + AGP_CONF_ATTBASE, 3313446Smrj gartaddr & AGP_ATTBASE_MASK); 3323446Smrj } 3333446Smrj 3345036Skz151634 /* 3355036Skz151634 * Pre-allocated graphics memory for every type of Intel north bridge, mem size 3365036Skz151634 * are specified in kbytes. 3375036Skz151634 */ 3385036Skz151634 #define GMS_MB(n) ((n) * 1024) 3395036Skz151634 #define GMS_SHIFT 4 3405036Skz151634 #define GMS_SIZE(a) (sizeof (a) / sizeof (int)) 3415036Skz151634 3425036Skz151634 /* 3435036Skz151634 * Since value zero always means "No memory pre-allocated", value of (GMS - 1) 3445036Skz151634 * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb) 3455036Skz151634 * that GMS value 0x1 corresponding to. 3465036Skz151634 * 3475036Skz151634 * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics 3485036Skz151634 * memory, unless some special BIOS settings exist. 3495036Skz151634 */ 3505036Skz151634 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)}; 3515036Skz151634 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)}; 3525036Skz151634 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3535036Skz151634 GMS_MB(32)}; 3545036Skz151634 /* There is no modes for 16M in datasheet, but some BIOS add it. */ 3555036Skz151634 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)}; 3565036Skz151634 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)}; 3575036Skz151634 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3585036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64)}; 3595036Skz151634 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3605036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)}; 3617662SMiao.Chen@Sun.COM static int gms_G4X[13] = {0, 0, 0, 0, 3627662SMiao.Chen@Sun.COM GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256), 3637662SMiao.Chen@Sun.COM GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)}; 3645036Skz151634 3655036Skz151634 static gms_mode_t gms_modes[] = { 3665036Skz151634 {INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK, 3675036Skz151634 GMS_SIZE(gms_810), gms_810}, 3685036Skz151634 {INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK, 3695036Skz151634 GMS_SIZE(gms_810), gms_810}, 3705036Skz151634 {INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK, 3715036Skz151634 GMS_SIZE(gms_810), gms_810}, 3725036Skz151634 {INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3735036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 3745036Skz151634 {INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3755036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 3765036Skz151634 {INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3775036Skz151634 GMS_SIZE(gms_855GM), gms_855GM}, 3785036Skz151634 {INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3795036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 3805036Skz151634 {INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3815036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 3825036Skz151634 {INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3835036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3845036Skz151634 {INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3855036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3865036Skz151634 {INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3875036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3888020SMiao.Chen@Sun.COM {INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3898020SMiao.Chen@Sun.COM GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3905036Skz151634 {INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3915036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3925036Skz151634 {INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3935036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3945036Skz151634 {INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3955036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3965036Skz151634 {INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3975036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3985036Skz151634 {INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3995036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 4005036Skz151634 {INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4015036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 4025036Skz151634 {INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK, 4035036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 4045036Skz151634 {INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 4055036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 4065036Skz151634 {INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 4076778Smc196098 GMS_SIZE(gms_X33), gms_X33}, 4086778Smc196098 {INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4097662SMiao.Chen@Sun.COM GMS_SIZE(gms_965GM), gms_965GM}, 4107662SMiao.Chen@Sun.COM {INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4117662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 4127662SMiao.Chen@Sun.COM {INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4137662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 4147662SMiao.Chen@Sun.COM {INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4158832SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 4168832SMiao.Chen@Sun.COM {INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 41711260SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 418*11359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_D, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 419*11359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 420*11359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_M, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 421*11359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 422*11359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_MA, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 423*11359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 424*11359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_MC2, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 425*11359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 42611260SMiao.Chen@Sun.COM {INTEL_BR_B43, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4277662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X} 4285036Skz151634 }; 4297130Sms148562 static int 4307130Sms148562 get_chip_gms(uint32_t devid) 4317130Sms148562 { 4327130Sms148562 int num_modes; 4337130Sms148562 int i; 4347130Sms148562 4357130Sms148562 num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); 4367130Sms148562 4377130Sms148562 for (i = 0; i < num_modes; i++) { 4387130Sms148562 if (gms_modes[i].gm_devid == devid) 4397130Sms148562 break; 4407130Sms148562 } 4417130Sms148562 4427130Sms148562 return ((i == num_modes) ? -1 : i); 4437130Sms148562 } 4445036Skz151634 4455036Skz151634 /* Returns the size (kbytes) of pre-allocated graphics memory */ 4463446Smrj static size_t 4473446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate) 4483446Smrj { 4493446Smrj uint8_t memval; 4503446Smrj size_t kbytes; 4517130Sms148562 int gms_off; 4523446Smrj 4535036Skz151634 kbytes = 0; 4547130Sms148562 gms_off = softstate->tsoft_gms_off; 4557130Sms148562 4565036Skz151634 /* fetch the GMS value from DRAM controller */ 4575036Skz151634 memval = pci_config_get8(softstate->tsoft_pcihdl, 4587130Sms148562 gms_modes[gms_off].gm_regoff); 4595036Skz151634 TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval)); 4607130Sms148562 memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT; 4615036Skz151634 /* assuming zero byte for 0 or "reserved" GMS values */ 4627130Sms148562 if (memval == 0 || memval > gms_modes[gms_off].gm_num) { 4635036Skz151634 TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: " 4645036Skz151634 "devid = %x, GMS = %x. assuming zero byte of " 4657130Sms148562 "pre-allocated memory", 4667130Sms148562 gms_modes[gms_off].gm_devid, memval)); 4675036Skz151634 goto done; 4685036Skz151634 } 4695036Skz151634 memval--; /* use (GMS_value - 1) as index */ 4707130Sms148562 kbytes = (gms_modes[gms_off].gm_vec)[memval]; 4713446Smrj 4725036Skz151634 done: 4734478Skz151634 TARGETDB_PRINT2((CE_NOTE, 4744478Skz151634 "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected", 4754478Skz151634 kbytes)); 4763446Smrj return (kbytes); 4773446Smrj } 4783446Smrj 4793446Smrj /*ARGSUSED*/ 4803446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 4813446Smrj void *arg, void **resultp) 4823446Smrj { 4833446Smrj agp_target_softstate_t *st; 4843446Smrj int instance, rval = DDI_FAILURE; 4853446Smrj dev_t dev; 4863446Smrj 4873446Smrj switch (cmd) { 4883446Smrj case DDI_INFO_DEVT2DEVINFO: 4893446Smrj dev = (dev_t)arg; 4903446Smrj instance = DEV2INST(dev); 4913446Smrj st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4923446Smrj if (st != NULL) { 4933446Smrj mutex_enter(&st->tsoft_lock); 4943446Smrj *resultp = st->tsoft_dip; 4953446Smrj mutex_exit(&st->tsoft_lock); 4963446Smrj rval = DDI_SUCCESS; 4973446Smrj } else 4983446Smrj *resultp = NULL; 4993446Smrj 5003446Smrj break; 5013446Smrj case DDI_INFO_DEVT2INSTANCE: 5023446Smrj dev = (dev_t)arg; 5033446Smrj instance = DEV2INST(dev); 5043446Smrj *resultp = (void *)(uintptr_t)instance; 5053446Smrj rval = DDI_SUCCESS; 5063446Smrj default: 5073446Smrj break; 5083446Smrj } 5093446Smrj 5103446Smrj return (rval); 5113446Smrj } 5123446Smrj 5133446Smrj static int 5147130Sms148562 intel_br_resume(agp_target_softstate_t *softstate) 5157130Sms148562 { 5167130Sms148562 int gms_off; 5177130Sms148562 5187130Sms148562 gms_off = softstate->tsoft_gms_off; 5197130Sms148562 5207130Sms148562 /* 5217130Sms148562 * We recover the gmch graphics control register here 5227130Sms148562 */ 5237130Sms148562 pci_config_put16(softstate->tsoft_pcihdl, 5247130Sms148562 gms_modes[gms_off].gm_regoff, softstate->tsoft_gms); 5257130Sms148562 5267130Sms148562 return (DDI_SUCCESS); 5277130Sms148562 } 5287130Sms148562 static int 5297130Sms148562 intel_br_suspend(agp_target_softstate_t *softstate) 5307130Sms148562 { 5317130Sms148562 int gms_off; 5327130Sms148562 5337130Sms148562 gms_off = softstate->tsoft_gms_off; 5347130Sms148562 softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl, 5357130Sms148562 gms_modes[gms_off].gm_regoff); 5367130Sms148562 5377130Sms148562 return (DDI_SUCCESS); 5387130Sms148562 } 5397130Sms148562 54011260SMiao.Chen@Sun.COM static void 54111260SMiao.Chen@Sun.COM intel_chipset_flush_setup(dev_info_t *dip, 542*11359SMiao.Chen@Sun.COM ddi_acc_handle_t pci_acc_hdl, int gms_off) 54311260SMiao.Chen@Sun.COM { 54411260SMiao.Chen@Sun.COM uint32_t temp_hi, temp_lo; 545*11359SMiao.Chen@Sun.COM uint64_t phys_base, phys_len; 54611260SMiao.Chen@Sun.COM uint32_t phys_hi_mask = 0; 547*11359SMiao.Chen@Sun.COM pci_regspec_t *old_regs = NULL, *new_regs = NULL; 548*11359SMiao.Chen@Sun.COM int old_len = 0, new_len = 0; 549*11359SMiao.Chen@Sun.COM uint32_t old_regnum, new_regnum; 550*11359SMiao.Chen@Sun.COM int circular = 0, prop_updated = 0; 551*11359SMiao.Chen@Sun.COM int ret; 55211260SMiao.Chen@Sun.COM 553*11359SMiao.Chen@Sun.COM if (i9xx_private.handle) 554*11359SMiao.Chen@Sun.COM return; 55511260SMiao.Chen@Sun.COM 55611260SMiao.Chen@Sun.COM /* IS_I965 || IS_G33 || IS_G4X */ 55711260SMiao.Chen@Sun.COM if (gms_off > 11) { 558*11359SMiao.Chen@Sun.COM temp_hi = pci_config_get32(pci_acc_hdl, I965_IFPADDR + 4); 559*11359SMiao.Chen@Sun.COM temp_lo = pci_config_get32(pci_acc_hdl, I965_IFPADDR); 56011260SMiao.Chen@Sun.COM phys_hi_mask |= PCI_ADDR_MEM64 | I965_IFPADDR; 56111260SMiao.Chen@Sun.COM } else { 562*11359SMiao.Chen@Sun.COM temp_lo = pci_config_get32(pci_acc_hdl, I915_IFPADDR); 56311260SMiao.Chen@Sun.COM phys_hi_mask |= PCI_ADDR_MEM32 | I915_IFPADDR; 56411260SMiao.Chen@Sun.COM } 56511260SMiao.Chen@Sun.COM 56611260SMiao.Chen@Sun.COM if (!(temp_lo & 0x1)) { 567*11359SMiao.Chen@Sun.COM ndi_ra_request_t request; 568*11359SMiao.Chen@Sun.COM 569*11359SMiao.Chen@Sun.COM bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 570*11359SMiao.Chen@Sun.COM request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED; 571*11359SMiao.Chen@Sun.COM request.ra_boundbase = 0; 572*11359SMiao.Chen@Sun.COM request.ra_boundlen = 0xffffffff; 573*11359SMiao.Chen@Sun.COM request.ra_len = AGP_PAGE_SIZE; 574*11359SMiao.Chen@Sun.COM 57511260SMiao.Chen@Sun.COM /* allocate space from the allocator */ 576*11359SMiao.Chen@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &circular); 577*11359SMiao.Chen@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip), &request, &phys_base, 578*11359SMiao.Chen@Sun.COM &phys_len, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) { 579*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 580*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: " 581*11359SMiao.Chen@Sun.COM "ndi_ra_alloc failed!")); 582*11359SMiao.Chen@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular); 583*11359SMiao.Chen@Sun.COM goto error; 58411260SMiao.Chen@Sun.COM } 585*11359SMiao.Chen@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular); 586*11359SMiao.Chen@Sun.COM i9xx_private.ra_alloced = 1; 587*11359SMiao.Chen@Sun.COM 588*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 589*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: " 590*11359SMiao.Chen@Sun.COM "addr = 0x%x.0x%x len [0x%x]\n", 591*11359SMiao.Chen@Sun.COM HIADDR(phys_base), LOADDR(phys_base), 592*11359SMiao.Chen@Sun.COM (uint32_t)phys_len)); 59311260SMiao.Chen@Sun.COM 59411260SMiao.Chen@Sun.COM if (gms_off > 11) { 595*11359SMiao.Chen@Sun.COM pci_config_put32(pci_acc_hdl, I965_IFPADDR + 4, 596*11359SMiao.Chen@Sun.COM HIADDR(phys_base)); 597*11359SMiao.Chen@Sun.COM pci_config_put32(pci_acc_hdl, I965_IFPADDR, 598*11359SMiao.Chen@Sun.COM LOADDR(phys_base) | 0x1); 59911260SMiao.Chen@Sun.COM } else { 600*11359SMiao.Chen@Sun.COM pci_config_put32(pci_acc_hdl, I915_IFPADDR, 601*11359SMiao.Chen@Sun.COM LOADDR(phys_base) | 0x1); 60211260SMiao.Chen@Sun.COM } 603*11359SMiao.Chen@Sun.COM } else { 60411260SMiao.Chen@Sun.COM temp_lo &= ~0x1; 605*11359SMiao.Chen@Sun.COM phys_base = ((uint64_t)temp_hi << 32) | temp_lo; 60611260SMiao.Chen@Sun.COM } 60711260SMiao.Chen@Sun.COM 608*11359SMiao.Chen@Sun.COM temp_hi = pci_config_get32(pci_acc_hdl, I965_IFPADDR + 4); 609*11359SMiao.Chen@Sun.COM temp_lo = pci_config_get32(pci_acc_hdl, I965_IFPADDR); 61011260SMiao.Chen@Sun.COM 61111260SMiao.Chen@Sun.COM /* set pci props */ 612*11359SMiao.Chen@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 613*11359SMiao.Chen@Sun.COM "reg", (caddr_t)&old_regs, &old_len) != DDI_PROP_SUCCESS) { 614*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 615*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: " 616*11359SMiao.Chen@Sun.COM "ddi_getlongprop(1) failed!")); 617*11359SMiao.Chen@Sun.COM goto error; 61811260SMiao.Chen@Sun.COM } 61911260SMiao.Chen@Sun.COM 620*11359SMiao.Chen@Sun.COM old_regnum = old_len / sizeof (pci_regspec_t); 621*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 622*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: old_regnum = %d", old_regnum)); 62311260SMiao.Chen@Sun.COM 624*11359SMiao.Chen@Sun.COM new_regnum = old_regnum + 1; 625*11359SMiao.Chen@Sun.COM new_len = new_regnum * sizeof (pci_regspec_t); 626*11359SMiao.Chen@Sun.COM new_regs = kmem_zalloc(new_len, KM_SLEEP); 627*11359SMiao.Chen@Sun.COM if (memcpy(new_regs, old_regs, (size_t)old_len) == NULL) { 628*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 629*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: memcpy failed")); 63011260SMiao.Chen@Sun.COM goto error; 63111260SMiao.Chen@Sun.COM } 63211260SMiao.Chen@Sun.COM 63311260SMiao.Chen@Sun.COM /* Bus=0, Dev=0, Func=0 0x82001000 */ 634*11359SMiao.Chen@Sun.COM new_regs[old_regnum].pci_phys_hi = PCI_REG_REL_M | phys_hi_mask; 635*11359SMiao.Chen@Sun.COM new_regs[old_regnum].pci_phys_mid = HIADDR(phys_base); 636*11359SMiao.Chen@Sun.COM new_regs[old_regnum].pci_phys_low = LOADDR(phys_base); 637*11359SMiao.Chen@Sun.COM new_regs[old_regnum].pci_size_hi = 0x00000000; 638*11359SMiao.Chen@Sun.COM new_regs[old_regnum].pci_size_low = AGP_PAGE_SIZE; 63911260SMiao.Chen@Sun.COM 640*11359SMiao.Chen@Sun.COM ret = ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 641*11359SMiao.Chen@Sun.COM "reg", (int *)new_regs, (uint_t)5 * new_regnum); 642*11359SMiao.Chen@Sun.COM if (ret != DDI_PROP_SUCCESS) { 643*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 644*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: " 645*11359SMiao.Chen@Sun.COM "ndi_prop_update_int_array failed %d", ret)); 646*11359SMiao.Chen@Sun.COM goto error; 64711260SMiao.Chen@Sun.COM } 648*11359SMiao.Chen@Sun.COM kmem_free(new_regs, (size_t)new_len); 649*11359SMiao.Chen@Sun.COM new_regs = NULL; 650*11359SMiao.Chen@Sun.COM 651*11359SMiao.Chen@Sun.COM prop_updated = 1; 65211260SMiao.Chen@Sun.COM 65311260SMiao.Chen@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 654*11359SMiao.Chen@Sun.COM "reg", (caddr_t)&new_regs, &new_len) != DDI_PROP_SUCCESS) { 655*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 656*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: " 657*11359SMiao.Chen@Sun.COM "ddi_getlongprop(2) failed")); 65811260SMiao.Chen@Sun.COM goto error; 65911260SMiao.Chen@Sun.COM } 660*11359SMiao.Chen@Sun.COM kmem_free(new_regs, (size_t)new_len); 661*11359SMiao.Chen@Sun.COM new_regs = NULL; 662*11359SMiao.Chen@Sun.COM 663*11359SMiao.Chen@Sun.COM new_regnum = new_len / sizeof (pci_regspec_t); 66411260SMiao.Chen@Sun.COM 665*11359SMiao.Chen@Sun.COM i9xx_private.physical = phys_base; 66611260SMiao.Chen@Sun.COM i9xx_private.size = AGP_PAGE_SIZE; 667*11359SMiao.Chen@Sun.COM i9xx_private.regnum = new_regnum - 1; 668*11359SMiao.Chen@Sun.COM 66911260SMiao.Chen@Sun.COM ret = ddi_regs_map_setup(dip, i9xx_private.regnum, 67011260SMiao.Chen@Sun.COM (caddr_t *)&(i9xx_private.flush_page), 0, 671*11359SMiao.Chen@Sun.COM i9xx_private.size, &dev_attr, &i9xx_private.handle); 67211260SMiao.Chen@Sun.COM if (ret != DDI_SUCCESS) { 673*11359SMiao.Chen@Sun.COM TARGETDB_PRINT2((CE_WARN, 674*11359SMiao.Chen@Sun.COM "intel_chipset_flush_setup: ddi_regs_map_setup failed")); 67511260SMiao.Chen@Sun.COM i9xx_private.handle = NULL; 676*11359SMiao.Chen@Sun.COM goto error; 67711260SMiao.Chen@Sun.COM } 678*11359SMiao.Chen@Sun.COM 679*11359SMiao.Chen@Sun.COM kmem_free(old_regs, (size_t)old_len); 68011260SMiao.Chen@Sun.COM return; 68111260SMiao.Chen@Sun.COM error: 682*11359SMiao.Chen@Sun.COM if (prop_updated) 683*11359SMiao.Chen@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 684*11359SMiao.Chen@Sun.COM "reg", (int *)old_regs, (uint_t)5 * old_regnum); 685*11359SMiao.Chen@Sun.COM if (new_regs) 686*11359SMiao.Chen@Sun.COM kmem_free(new_regs, (size_t)new_len); 687*11359SMiao.Chen@Sun.COM if (old_regs) 688*11359SMiao.Chen@Sun.COM kmem_free(old_regs, (size_t)old_len); 689*11359SMiao.Chen@Sun.COM if (i9xx_private.ra_alloced) { 690*11359SMiao.Chen@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &circular); 691*11359SMiao.Chen@Sun.COM (void) ndi_ra_free(ddi_get_parent(dip), 692*11359SMiao.Chen@Sun.COM phys_base, phys_len, NDI_RA_TYPE_MEM, NDI_RA_PASS); 693*11359SMiao.Chen@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular); 694*11359SMiao.Chen@Sun.COM i9xx_private.ra_alloced = 0; 695*11359SMiao.Chen@Sun.COM } 696*11359SMiao.Chen@Sun.COM } 697*11359SMiao.Chen@Sun.COM 698*11359SMiao.Chen@Sun.COM static void 699*11359SMiao.Chen@Sun.COM intel_chipset_flush_free(dev_info_t *dip) 700*11359SMiao.Chen@Sun.COM { 701*11359SMiao.Chen@Sun.COM pci_regspec_t *regs = NULL; 702*11359SMiao.Chen@Sun.COM int len = 0, regnum; 703*11359SMiao.Chen@Sun.COM int circular = 0; 704*11359SMiao.Chen@Sun.COM 705*11359SMiao.Chen@Sun.COM if (i9xx_private.handle == NULL) 706*11359SMiao.Chen@Sun.COM return; 707*11359SMiao.Chen@Sun.COM 708*11359SMiao.Chen@Sun.COM ddi_regs_map_free(&i9xx_private.handle); 709*11359SMiao.Chen@Sun.COM i9xx_private.handle = NULL; 710*11359SMiao.Chen@Sun.COM 711*11359SMiao.Chen@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 712*11359SMiao.Chen@Sun.COM "reg", (caddr_t)®s, &len) == DDI_PROP_SUCCESS) { 713*11359SMiao.Chen@Sun.COM regnum = len / sizeof (pci_regspec_t) - 1; 714*11359SMiao.Chen@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 715*11359SMiao.Chen@Sun.COM "reg", (int *)regs, (uint_t)5 * regnum); 716*11359SMiao.Chen@Sun.COM } 71711260SMiao.Chen@Sun.COM if (regs) 718*11359SMiao.Chen@Sun.COM kmem_free(regs, (size_t)len); 719*11359SMiao.Chen@Sun.COM 720*11359SMiao.Chen@Sun.COM if (i9xx_private.ra_alloced) { 721*11359SMiao.Chen@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &circular); 722*11359SMiao.Chen@Sun.COM (void) ndi_ra_free(ddi_get_parent(dip), 723*11359SMiao.Chen@Sun.COM i9xx_private.physical, i9xx_private.size, 724*11359SMiao.Chen@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS); 725*11359SMiao.Chen@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular); 726*11359SMiao.Chen@Sun.COM i9xx_private.ra_alloced = 0; 727*11359SMiao.Chen@Sun.COM } 72811260SMiao.Chen@Sun.COM } 72911260SMiao.Chen@Sun.COM 7307130Sms148562 static int 7313446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 7323446Smrj { 7333446Smrj agp_target_softstate_t *softstate; 7343446Smrj int instance; 7353446Smrj int status; 7363446Smrj 7373446Smrj instance = ddi_get_instance(dip); 7383446Smrj 7397130Sms148562 switch (cmd) { 7407130Sms148562 case DDI_ATTACH: 7417130Sms148562 break; 7427130Sms148562 case DDI_RESUME: 7437130Sms148562 softstate = 7447130Sms148562 ddi_get_soft_state(agptarget_glob_soft_handle, instance); 7457130Sms148562 return (intel_br_resume(softstate)); 7467130Sms148562 default: 7477130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7487130Sms148562 "only attach and resume ops are supported")); 7493446Smrj return (DDI_FAILURE); 7507130Sms148562 } 7517130Sms148562 7527130Sms148562 if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, 7537130Sms148562 instance) != DDI_SUCCESS) { 7547130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7557130Sms148562 "soft state zalloc failed")); 7567130Sms148562 return (DDI_FAILURE); 7577130Sms148562 } 7583446Smrj 7593446Smrj softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 7603446Smrj mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 7613446Smrj softstate->tsoft_dip = dip; 7623446Smrj status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 7633446Smrj if (status != DDI_SUCCESS) { 7647130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7657130Sms148562 "pci config setup failed")); 7667130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 7677130Sms148562 instance); 7683446Smrj return (DDI_FAILURE); 7693446Smrj } 7703446Smrj 7713446Smrj softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 7723446Smrj PCI_CONF_VENID); 7737130Sms148562 softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid); 7747130Sms148562 if (softstate->tsoft_gms_off < 0) { 7757130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7767130Sms148562 "read gms offset failed")); 7777130Sms148562 pci_config_teardown(&softstate->tsoft_pcihdl); 7787130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 7797130Sms148562 instance); 7807130Sms148562 return (DDI_FAILURE); 7817130Sms148562 } 7823446Smrj softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 7833446Smrj if (softstate->tsoft_acaptr == 0) { 7843446Smrj /* Make a correction for some Intel chipsets */ 7855131Sms148562 if (is_intel_br(softstate)) 7863446Smrj softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 7877130Sms148562 else { 7887130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 7897130Sms148562 "Not a supposed corretion")); 7907130Sms148562 pci_config_teardown(&softstate->tsoft_pcihdl); 7917130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 7927130Sms148562 instance); 7933446Smrj return (DDI_FAILURE); 7947130Sms148562 } 7953446Smrj } 7963446Smrj 7973446Smrj status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 7983446Smrj INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 7993446Smrj 8003446Smrj if (status != DDI_SUCCESS) { 8017130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 8027130Sms148562 "Create minor node failed")); 8033446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 8043446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 8053446Smrj return (DDI_FAILURE); 8063446Smrj } 8073446Smrj 8083446Smrj return (DDI_SUCCESS); 8093446Smrj } 8103446Smrj 8113446Smrj /*ARGSUSED*/ 8123446Smrj static int 8133446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 8143446Smrj { 8153446Smrj int instance; 8163446Smrj agp_target_softstate_t *softstate; 8173446Smrj 8187130Sms148562 instance = ddi_get_instance(dip); 8197130Sms148562 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 8203446Smrj 8217130Sms148562 if (cmd == DDI_SUSPEND) { 8227130Sms148562 /* get GMS modes list entry */ 8237130Sms148562 return (intel_br_suspend(softstate)); 8247130Sms148562 } 8253446Smrj 8267130Sms148562 if (cmd != DDI_DETACH) { 8277130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_detach:" 8287130Sms148562 "only detach and suspend ops are supported")); 8297130Sms148562 return (DDI_FAILURE); 8307130Sms148562 } 8313446Smrj 8323446Smrj ddi_remove_minor_node(dip, AGPTARGET_NAME); 8333446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 8343446Smrj mutex_destroy(&softstate->tsoft_lock); 8353446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 8363446Smrj return (DDI_SUCCESS); 8373446Smrj } 8383446Smrj 8393446Smrj /*ARGSUSED*/ 8403446Smrj static int 8413446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 8423446Smrj cred_t *cred, int *rval) 8433446Smrj { 8443446Smrj int instance = DEV2INST(dev); 8453446Smrj agp_target_softstate_t *st; 8463446Smrj static char kernel_only[] = 8473446Smrj "amd64_gart_ioctl: is a kernel only ioctl"; 8483446Smrj 8493446Smrj if (!(mode & FKIOCTL)) { 8503446Smrj TARGETDB_PRINT2((CE_CONT, kernel_only)); 8513446Smrj return (ENXIO); 8523446Smrj } 8533446Smrj st = GETSOFTC(instance); 8543446Smrj 8553446Smrj if (st == NULL) 8563446Smrj return (ENXIO); 8573446Smrj 8583446Smrj mutex_enter(&st->tsoft_lock); 8593446Smrj 8603446Smrj switch (cmd) { 8613446Smrj case CHIP_DETECT: 8623446Smrj { 8635131Sms148562 int type = 0; 8645131Sms148562 8655131Sms148562 if (is_intel_br(st)) 8663446Smrj type = CHIP_IS_INTEL; 8675131Sms148562 else if (is_64bit_aper(st)) 8683446Smrj type = CHIP_IS_AMD; 8695131Sms148562 else { 8703446Smrj type = 0; 8715131Sms148562 TARGETDB_PRINT2((CE_WARN, "Unknown bridge!")); 8723446Smrj } 8735131Sms148562 8743446Smrj if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 8753446Smrj mutex_exit(&st->tsoft_lock); 8763446Smrj return (EFAULT); 8773446Smrj } 8783446Smrj 8793446Smrj break; 8803446Smrj } 8813446Smrj case I8XX_GET_PREALLOC_SIZE: 8823446Smrj { 8833446Smrj size_t prealloc_size; 8843446Smrj 8855131Sms148562 if (!is_intel_br(st)) { 8863446Smrj mutex_exit(&st->tsoft_lock); 8873446Smrj return (EINVAL); 8883446Smrj } 8893446Smrj 8903446Smrj prealloc_size = i8xx_biosmem_detect(st); 8913446Smrj if (ddi_copyout(&prealloc_size, (void *)data, 8923446Smrj sizeof (size_t), mode)) { 8933446Smrj mutex_exit(&st->tsoft_lock); 8943446Smrj return (EFAULT); 8953446Smrj } 8963446Smrj 8973446Smrj break; 8983446Smrj } 8993446Smrj case AGP_TARGET_GETINFO: 9003446Smrj { 9013446Smrj i_agp_info_t info; 9023446Smrj uint32_t value; 9033446Smrj off_t cap; 9043446Smrj 9053446Smrj ASSERT(st->tsoft_acaptr); 9063446Smrj 9073446Smrj cap = st->tsoft_acaptr; 9083446Smrj value = pci_config_get32(st->tsoft_pcihdl, cap); 9093446Smrj info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 9103446Smrj info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 9113446Smrj info.iagp_devid = st->tsoft_devid; 9123446Smrj info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 9134303Skz151634 cap + AGP_CONF_STATUS); 9143446Smrj info.iagp_aperbase = agp_target_get_apbase(st); 9153446Smrj info.iagp_apersize = agp_target_get_apsize(st); 9163446Smrj 9173446Smrj if (ddi_copyout(&info, (void *)data, 9183446Smrj sizeof (i_agp_info_t), mode)) { 9193446Smrj mutex_exit(&st->tsoft_lock); 9203446Smrj return (EFAULT); 9213446Smrj } 9223446Smrj break; 9233446Smrj 9243446Smrj } 9253446Smrj /* 9263446Smrj * This ioctl is only for Intel AGP chipsets. 9273446Smrj * It is not necessary for the AMD8151 AGP bridge, because 9283446Smrj * this register in the AMD8151 does not control any hardware. 9293446Smrj * It is only provided for compatibility with an Intel AGP bridge. 9303446Smrj * Please refer to the <<AMD8151 data sheet>> page 24, 9313446Smrj * AGP device GART pointer. 9323446Smrj */ 9333446Smrj case AGP_TARGET_SET_GATTADDR: 9343446Smrj { 9353446Smrj uint32_t gartaddr; 9363446Smrj 9373446Smrj if (ddi_copyin((void *)data, &gartaddr, 9383446Smrj sizeof (uint32_t), mode)) { 9393446Smrj mutex_exit(&st->tsoft_lock); 9403446Smrj return (EFAULT); 9413446Smrj } 9423446Smrj 9433446Smrj agp_target_set_gartaddr(st, gartaddr); 9443446Smrj break; 9453446Smrj } 9463446Smrj case AGP_TARGET_SETCMD: 9473446Smrj { 9483446Smrj uint32_t command; 9493446Smrj 9503446Smrj if (ddi_copyin((void *)data, &command, 9513446Smrj sizeof (uint32_t), mode)) { 9523446Smrj mutex_exit(&st->tsoft_lock); 9533446Smrj return (EFAULT); 9543446Smrj } 9553446Smrj 9563446Smrj ASSERT(st->tsoft_acaptr); 9573446Smrj 9583446Smrj pci_config_put32(st->tsoft_pcihdl, 9593446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 9603446Smrj command); 9613446Smrj break; 9623446Smrj 9633446Smrj } 9643446Smrj case AGP_TARGET_FLUSH_GTLB: 9653446Smrj { 9663446Smrj uint16_t value; 9673446Smrj 9683446Smrj ASSERT(st->tsoft_acaptr); 9693446Smrj 9703446Smrj value = pci_config_get16(st->tsoft_pcihdl, 9713446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL); 9723446Smrj value &= ~AGPCTRL_GTLBEN; 9733446Smrj pci_config_put16(st->tsoft_pcihdl, 9743446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 9753446Smrj value |= AGPCTRL_GTLBEN; 9763446Smrj pci_config_put16(st->tsoft_pcihdl, 9773446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 9783446Smrj 9793446Smrj break; 9803446Smrj } 9813446Smrj case AGP_TARGET_CONFIGURE: 9823446Smrj { 9833446Smrj uint8_t value; 9843446Smrj 9853446Smrj ASSERT(st->tsoft_acaptr); 9863446Smrj 9875131Sms148562 /* 9885131Sms148562 * In Intel agp bridges, agp misc register offset 9895131Sms148562 * is indexed from 0 instead of capability register. 9905131Sms148562 * AMD agp bridges have no such misc register 9915131Sms148562 * to control the aperture access, and they have 9925131Sms148562 * similar regsiters in CPU gart devices instead. 9935131Sms148562 */ 9945131Sms148562 9955131Sms148562 if (is_intel_br(st)) { 9965131Sms148562 value = pci_config_get8(st->tsoft_pcihdl, 9975131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC); 9985131Sms148562 value |= AGP_MISC_APEN; 9995131Sms148562 pci_config_put8(st->tsoft_pcihdl, 10005131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC, value); 10015131Sms148562 } 10023446Smrj break; 10033446Smrj 10043446Smrj } 10053446Smrj case AGP_TARGET_UNCONFIG: 10063446Smrj { 10073446Smrj uint32_t value1; 10083446Smrj uint8_t value2; 10093446Smrj 10103446Smrj ASSERT(st->tsoft_acaptr); 10113446Smrj 10123446Smrj pci_config_put16(st->tsoft_pcihdl, 10133446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 10143446Smrj 10155131Sms148562 if (is_intel_br(st)) { 10165131Sms148562 value2 = pci_config_get8(st->tsoft_pcihdl, 10175131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC); 10185131Sms148562 value2 &= ~AGP_MISC_APEN; 10195131Sms148562 pci_config_put8(st->tsoft_pcihdl, 10205131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC, value2); 10215131Sms148562 } 10223446Smrj 10233446Smrj value1 = pci_config_get32(st->tsoft_pcihdl, 10243446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND); 10253446Smrj value1 &= ~AGPCMD_AGPEN; 10263446Smrj pci_config_put32(st->tsoft_pcihdl, 10273446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 10283446Smrj value1); 10293446Smrj 10303446Smrj pci_config_put32(st->tsoft_pcihdl, 10313446Smrj st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 10323446Smrj 10333446Smrj break; 10343446Smrj } 10353446Smrj 103611260SMiao.Chen@Sun.COM case INTEL_CHIPSET_FLUSH_SETUP: 103711260SMiao.Chen@Sun.COM { 103811260SMiao.Chen@Sun.COM intel_chipset_flush_setup(st->tsoft_dip, 103911260SMiao.Chen@Sun.COM st->tsoft_pcihdl, st->tsoft_gms_off); 104011260SMiao.Chen@Sun.COM break; 104111260SMiao.Chen@Sun.COM } 104211260SMiao.Chen@Sun.COM case INTEL_CHIPSET_FLUSH: 104311260SMiao.Chen@Sun.COM { 104411260SMiao.Chen@Sun.COM if (i9xx_private.handle != NULL) 104511260SMiao.Chen@Sun.COM ddi_put32(i9xx_private.handle, 104611260SMiao.Chen@Sun.COM (uint32_t *)(uintptr_t)i9xx_private.flush_page, 1); 104711260SMiao.Chen@Sun.COM 104811260SMiao.Chen@Sun.COM break; 104911260SMiao.Chen@Sun.COM } 105011260SMiao.Chen@Sun.COM case INTEL_CHIPSET_FLUSH_FREE: 105111260SMiao.Chen@Sun.COM { 1052*11359SMiao.Chen@Sun.COM intel_chipset_flush_free(st->tsoft_dip); 105311260SMiao.Chen@Sun.COM break; 105411260SMiao.Chen@Sun.COM } 10553446Smrj default: 10563446Smrj mutex_exit(&st->tsoft_lock); 10573446Smrj return (ENXIO); 10583446Smrj } /* end switch */ 10593446Smrj 10603446Smrj mutex_exit(&st->tsoft_lock); 10613446Smrj 10623446Smrj return (0); 10633446Smrj } 10643446Smrj 10653446Smrj /*ARGSUSED*/ 10663446Smrj static int 10673446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 10683446Smrj { 10693446Smrj int instance = DEV2INST(*devp); 10703446Smrj agp_target_softstate_t *st; 10713446Smrj 10723446Smrj if (!(flag & FKLYR)) 10733446Smrj return (ENXIO); 10743446Smrj 10753446Smrj st = GETSOFTC(instance); 10763446Smrj 10773446Smrj if (st == NULL) 10783446Smrj return (ENXIO); 10793446Smrj 10803446Smrj return (0); 10813446Smrj } 10823446Smrj 10833446Smrj /*ARGSUSED*/ 10843446Smrj static int 10853446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 10863446Smrj { 10873446Smrj int instance = DEV2INST(dev); 10883446Smrj agp_target_softstate_t *st; 10893446Smrj 10903446Smrj st = GETSOFTC(instance); 10913446Smrj 10923446Smrj if (st == NULL) 10933446Smrj return (ENXIO); 10943446Smrj 10953446Smrj return (0); 10963446Smrj } 10973446Smrj 10983446Smrj static struct cb_ops agp_target_cb_ops = { 10993446Smrj agp_target_open, /* cb_open */ 11003446Smrj agp_target_close, /* cb_close */ 11013446Smrj nodev, /* cb_strategy */ 11023446Smrj nodev, /* cb_print */ 11033446Smrj nodev, /* cb_dump */ 11043446Smrj nodev, /* cb_read() */ 11053446Smrj nodev, /* cb_write() */ 11063446Smrj agp_target_ioctl, /* cb_ioctl */ 11073446Smrj nodev, /* cb_devmap */ 11083446Smrj nodev, /* cb_mmap */ 11093446Smrj nodev, /* cb_segmap */ 11103446Smrj nochpoll, /* cb_chpoll */ 11113446Smrj ddi_prop_op, /* cb_prop_op */ 11123446Smrj 0, /* cb_stream */ 11133446Smrj D_NEW | D_MP, /* cb_flag */ 11143446Smrj CB_REV, /* cb_ops version? */ 11153446Smrj nodev, /* cb_aread() */ 11163446Smrj nodev, /* cb_awrite() */ 11173446Smrj }; 11183446Smrj 11193446Smrj /* device operations */ 11203446Smrj static struct dev_ops agp_target_ops = { 11213446Smrj DEVO_REV, /* devo_rev */ 11223446Smrj 0, /* devo_refcnt */ 11233446Smrj agptarget_getinfo, /* devo_getinfo */ 11243446Smrj nulldev, /* devo_identify */ 11253446Smrj nulldev, /* devo_probe */ 11263446Smrj agp_target_attach, /* devo_attach */ 11273446Smrj agp_target_detach, /* devo_detach */ 11283446Smrj nodev, /* devo_reset */ 11293446Smrj &agp_target_cb_ops, /* devo_cb_ops */ 11303446Smrj 0, /* devo_bus_ops */ 11313446Smrj 0, /* devo_power */ 11328328SMiao.Chen@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */ 11333446Smrj }; 11343446Smrj 11353446Smrj static struct modldrv modldrv = { 11363446Smrj &mod_driverops, 11377130Sms148562 "AGP target driver", 11383446Smrj &agp_target_ops, 11393446Smrj }; 11403446Smrj 11413446Smrj static struct modlinkage modlinkage = { 11423446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 11433446Smrj {&modldrv, NULL, NULL, NULL} 11443446Smrj }; 11453446Smrj 11463446Smrj int 11473446Smrj _init(void) 11483446Smrj { 11493446Smrj int ret; 11503446Smrj 11513446Smrj ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 11523446Smrj sizeof (agp_target_softstate_t), 1); 11533446Smrj 11543446Smrj if (ret) 11553446Smrj goto err1; 11563446Smrj 11573446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 11583446Smrj goto err2; 11593446Smrj } 11603446Smrj 11613446Smrj return (DDI_SUCCESS); 11623446Smrj err2: 11633446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 11643446Smrj err1: 11653446Smrj return (ret); 11663446Smrj } 11673446Smrj 11683446Smrj int 11693446Smrj _info(struct modinfo *modinfop) 11703446Smrj { 11713446Smrj return (mod_info(&modlinkage, modinfop)); 11723446Smrj } 11733446Smrj 11743446Smrj int 11753446Smrj _fini(void) 11763446Smrj { 11773446Smrj int ret; 11783446Smrj 11793446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 11803446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 11813446Smrj } 11823446Smrj return (ret); 11833446Smrj } 1184