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 /* 233527Sms148562 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243446Smrj * Use is subject to license terms. 253446Smrj */ 263446Smrj 273446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 283446Smrj 293446Smrj #include <sys/systm.h> 303446Smrj #include <sys/conf.h> 313446Smrj #include <sys/modctl.h> 323446Smrj #include <sys/file.h> 333446Smrj #include <sys/stat.h> 343446Smrj #include <sys/ddi.h> 353446Smrj #include <sys/sunddi.h> 363446Smrj #include <sys/modctl.h> 373446Smrj #include <sys/sunldi.h> 383446Smrj #include <sys/pci.h> 393446Smrj #include <sys/agpgart.h> 403446Smrj #include <sys/agp/agpdefs.h> 413446Smrj #include <sys/agp/agptarget_io.h> 423446Smrj 433446Smrj int agptarget_debug_var = 0; 443446Smrj #define TARGETDB_PRINT2(fmt) if (agptarget_debug_var >= 1) cmn_err fmt 453446Smrj #define INST2NODENUM(inst) (inst) 463446Smrj #define DEV2INST(dev) (getminor(dev)) 473446Smrj 483446Smrj typedef struct agp_target_softstate { 493446Smrj dev_info_t *tsoft_dip; 503446Smrj ddi_acc_handle_t tsoft_pcihdl; 513446Smrj uint32_t tsoft_devid; 523446Smrj /* The offset of the ACAPID register */ 533446Smrj off_t tsoft_acaptr; 543446Smrj kmutex_t tsoft_lock; 553446Smrj }agp_target_softstate_t; 563446Smrj 57*5036Skz151634 /* 58*5036Skz151634 * To get the pre-allocated graphics mem size using Graphics Mode Select 59*5036Skz151634 * (GMS) value. 60*5036Skz151634 */ 61*5036Skz151634 typedef struct gms_mode { 62*5036Skz151634 uint32_t gm_devid; /* bridge vendor + device id */ 63*5036Skz151634 off_t gm_regoff; /* mode selection register offset */ 64*5036Skz151634 uint32_t gm_mask; /* GMS mask */ 65*5036Skz151634 uint32_t gm_num; /* number of modes in gm_vec */ 66*5036Skz151634 int *gm_vec; /* modes array */ 67*5036Skz151634 } gms_mode_t; 68*5036Skz151634 693446Smrj static void *agptarget_glob_soft_handle; 703446Smrj 713446Smrj #define GETSOFTC(instance) ((agp_target_softstate_t *) \ 723446Smrj ddi_get_soft_state(agptarget_glob_soft_handle, instance)); 733446Smrj 743446Smrj /* 753446Smrj * The AMD8151 bridge is the only supported 64 bit hardware 763446Smrj */ 773446Smrj static int 783446Smrj is_64bit_aper(agp_target_softstate_t *softstate) 793446Smrj { 803446Smrj return (softstate->tsoft_devid == AMD_BR_8151); 813446Smrj } 823446Smrj 833446Smrj /* 843446Smrj * agp_target_cap_find() 853446Smrj * 863446Smrj * Description: 873446Smrj * This function searches the linked capability list to find the offset 883446Smrj * of the AGP capability register. When it was not found, return 0. 893446Smrj * This works for standard AGP chipsets, but not for some Intel chipsets, 903446Smrj * like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for 913446Smrj * these chipsets even if AGP is supported. So the offset of acapid 923446Smrj * should be set manually in thoses cases. 933446Smrj * 943446Smrj * Arguments: 953446Smrj * pci_handle ddi acc handle of pci config 963446Smrj * 973446Smrj * Returns: 983446Smrj * 0 No capability pointer register found 993446Smrj * nexcap The AGP capability pointer register offset 1003446Smrj */ 1013446Smrj static off_t 1023446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle) 1033446Smrj { 1043446Smrj off_t nextcap = 0; 1053446Smrj uint32_t ncapid = 0; 1063446Smrj uint8_t value = 0; 1073446Smrj 1083446Smrj /* Check if this device supports the capability pointer */ 1093446Smrj value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT) 1103446Smrj & PCI_CONF_CAP_MASK); 1113446Smrj 1123446Smrj if (!value) 1133446Smrj return (0); 1143446Smrj /* Get the offset of the first capability pointer from CAPPTR */ 1153446Smrj nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR)); 1163446Smrj 1173446Smrj /* Check the AGP capability from the first capability pointer */ 1183446Smrj while (nextcap) { 1193446Smrj ncapid = pci_config_get32(pci_handle, nextcap); 1203446Smrj /* 1213446Smrj * AGP3.0 rev1.0 127 the capid was assigned by the PCI SIG, 1223446Smrj * 845 data sheet page 69 1233446Smrj */ 1243446Smrj if ((ncapid & PCI_CONF_CAPID_MASK) == 1253446Smrj AGP_CAP_ID) /* The AGP cap was found */ 1263446Smrj break; 1273446Smrj 1283446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 1293446Smrj } 1303446Smrj 1313446Smrj return (nextcap); 1323446Smrj 1333446Smrj } 1343446Smrj 1353446Smrj /* 1363446Smrj * agp_target_get_aperbase() 1373446Smrj * 1383446Smrj * Description: 1393446Smrj * This function gets the AGP aperture base address from the AGP target 1403446Smrj * register, the AGP aperture base register was programmed by the BIOS. 1413446Smrj * 1423446Smrj * Arguments: 1433446Smrj * softstate driver soft state pointer 1443446Smrj * 1453446Smrj * Returns: 1463446Smrj * aper_base AGP aperture base address 1473446Smrj * 1483446Smrj * Notes: 1493446Smrj * If a 64bit bridge device is available, the AGP aperture base address 1503446Smrj * can be 64 bit. 1513446Smrj */ 1523446Smrj static uint64_t 1533446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate) 1543446Smrj { 1553446Smrj uint64_t aper_base; 1563446Smrj 1573446Smrj if (!is_64bit_aper(softstate)) { 1583446Smrj aper_base = pci_config_get32(softstate->tsoft_pcihdl, 1593446Smrj AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK; 1603446Smrj } else { 1613446Smrj aper_base = pci_config_get64(softstate->tsoft_pcihdl, 1623446Smrj AGP_CONF_APERBASE); 1633446Smrj /* 32-bit or 64-bit aperbase base pointer */ 1643446Smrj if ((aper_base & AGP_APER_TYPE_MASK) == 0) 1653446Smrj aper_base &= AGP_32_APERBASE_MASK; 1663446Smrj else 1673446Smrj aper_base &= AGP_64_APERBASE_MASK; 1683446Smrj } 1693446Smrj return (aper_base); 1703446Smrj } 1713446Smrj 1723446Smrj /* 1733446Smrj * agp_target_get_apsize() 1743446Smrj * 1753446Smrj * Description: 1763446Smrj * This function gets the AGP aperture size by reading the AGP aperture 1773446Smrj * size register. 1783446Smrj * Arguments: 1793446Smrj * softstate driver soft state pointer 1803446Smrj * 1813446Smrj * Return: 1823446Smrj * size The AGP aperture size in megabytes 1833446Smrj * 0 an unexpected error 1843446Smrj */ 1853446Smrj static size_t 1863446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate) 1873446Smrj { 1883446Smrj off_t cap; 1893446Smrj uint16_t value; 1903446Smrj size_t size, regsize; 1913446Smrj 1923446Smrj ASSERT(softstate->tsoft_acaptr); 1933446Smrj cap = softstate->tsoft_acaptr; 1943446Smrj 1953446Smrj if ((softstate->tsoft_devid & VENDOR_ID_MASK) == INTEL_VENDOR_ID) { 1963446Smrj /* extend this value to 16 bit for later tests */ 1973446Smrj value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl, 1983446Smrj cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK; 1993446Smrj } else { 2003446Smrj value = pci_config_get16(softstate->tsoft_pcihdl, 2013446Smrj cap + AGP_CONF_APERSIZE); 2023446Smrj } 2033446Smrj 2043446Smrj if (value & AGP_APER_128M_MASK) { 2053446Smrj switch (value & AGP_APER_128M_MASK) { 2063446Smrj case AGP_APER_4M: 2073446Smrj size = 4; /* 4M */ 2083446Smrj break; 2093446Smrj case AGP_APER_8M: 2103446Smrj size = 8; /* 8M */ 2113446Smrj break; 2123446Smrj case AGP_APER_16M: 2133446Smrj size = 16; /* 16M */ 2143446Smrj break; 2153446Smrj case AGP_APER_32M: 2163446Smrj size = 32; /* 32M */ 2173446Smrj break; 2183446Smrj case AGP_APER_64M: 2193446Smrj size = 64; /* 64M */ 2203446Smrj break; 2213446Smrj case AGP_APER_128M: 2223446Smrj size = 128; /* 128M */ 2233446Smrj break; 2243446Smrj default: 2253446Smrj size = 0; /* not true */ 2263446Smrj } 2273446Smrj } else { 2283446Smrj switch (value & AGP_APER_4G_MASK) { 2293446Smrj case AGP_APER_256M: 2303446Smrj size = 256; /* 256 M */ 2313446Smrj break; 2323446Smrj case AGP_APER_512M: 2333446Smrj size = 512; /* 512 M */ 2343446Smrj break; 2353446Smrj case AGP_APER_1024M: 2363446Smrj size = 1024; /* 1024 M */ 2373446Smrj break; 2383446Smrj case AGP_APER_2048M: 2393446Smrj size = 2048; /* 2048 M */ 2403446Smrj break; 2413446Smrj case AGP_APER_4G: 2423446Smrj size = 4096; /* 4096 M */ 2433446Smrj break; 2443446Smrj default: 2453446Smrj size = 0; /* not true */ 2463446Smrj } 2473446Smrj } 2483446Smrj /* 2493446Smrj * In some cases, there is no APSIZE register, so the size value 2503446Smrj * of 256M could be wrong. Check the value by reading the size of 2513446Smrj * the first register which was set in the PCI configuration space. 2523446Smrj */ 2533446Smrj if (size == 256) { 2543446Smrj if (ddi_dev_regsize(softstate->tsoft_dip, 2553446Smrj AGP_TARGET_BAR1, (off_t *)®size) == DDI_FAILURE) 2563446Smrj return (0); 2573446Smrj 2583446Smrj if (MB2BYTES(size) != regsize) { 2593446Smrj TARGETDB_PRINT2((CE_WARN, 2603446Smrj "APSIZE 256M doesn't match regsize %lx", 2613446Smrj regsize)); 2623446Smrj TARGETDB_PRINT2((CE_WARN, "Use regsize instead")); 2633446Smrj size = BYTES2MB(regsize); 2643446Smrj } 2653446Smrj } 2663446Smrj 2673446Smrj return (size); 2683446Smrj } 2693446Smrj 2703446Smrj static void 2713446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr) 2723446Smrj { 2733446Smrj ASSERT(softstate->tsoft_acaptr); 2743446Smrj 2753446Smrj /* Disable the GTLB for Intel chipsets */ 2763446Smrj pci_config_put16(softstate->tsoft_pcihdl, 2773446Smrj softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000); 2783446Smrj 2793446Smrj pci_config_put32(softstate->tsoft_pcihdl, 2803446Smrj softstate->tsoft_acaptr + AGP_CONF_ATTBASE, 2813446Smrj gartaddr & AGP_ATTBASE_MASK); 2823446Smrj } 2833446Smrj 284*5036Skz151634 /* 285*5036Skz151634 * Pre-allocated graphics memory for every type of Intel north bridge, mem size 286*5036Skz151634 * are specified in kbytes. 287*5036Skz151634 */ 288*5036Skz151634 #define GMS_MB(n) ((n) * 1024) 289*5036Skz151634 #define GMS_SHIFT 4 290*5036Skz151634 #define GMS_SIZE(a) (sizeof (a) / sizeof (int)) 291*5036Skz151634 292*5036Skz151634 /* 293*5036Skz151634 * Since value zero always means "No memory pre-allocated", value of (GMS - 1) 294*5036Skz151634 * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb) 295*5036Skz151634 * that GMS value 0x1 corresponding to. 296*5036Skz151634 * 297*5036Skz151634 * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics 298*5036Skz151634 * memory, unless some special BIOS settings exist. 299*5036Skz151634 */ 300*5036Skz151634 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)}; 301*5036Skz151634 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)}; 302*5036Skz151634 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 303*5036Skz151634 GMS_MB(32)}; 304*5036Skz151634 /* There is no modes for 16M in datasheet, but some BIOS add it. */ 305*5036Skz151634 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)}; 306*5036Skz151634 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)}; 307*5036Skz151634 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 308*5036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64)}; 309*5036Skz151634 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 310*5036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)}; 311*5036Skz151634 312*5036Skz151634 static gms_mode_t gms_modes[] = { 313*5036Skz151634 {INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK, 314*5036Skz151634 GMS_SIZE(gms_810), gms_810}, 315*5036Skz151634 {INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK, 316*5036Skz151634 GMS_SIZE(gms_810), gms_810}, 317*5036Skz151634 {INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK, 318*5036Skz151634 GMS_SIZE(gms_810), gms_810}, 319*5036Skz151634 {INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 320*5036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 321*5036Skz151634 {INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 322*5036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 323*5036Skz151634 {INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 324*5036Skz151634 GMS_SIZE(gms_855GM), gms_855GM}, 325*5036Skz151634 {INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 326*5036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 327*5036Skz151634 {INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 328*5036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 329*5036Skz151634 {INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 330*5036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 331*5036Skz151634 {INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 332*5036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 333*5036Skz151634 {INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 334*5036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 335*5036Skz151634 {INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 336*5036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 337*5036Skz151634 {INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 338*5036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 339*5036Skz151634 {INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 340*5036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 341*5036Skz151634 {INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 342*5036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 343*5036Skz151634 {INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 344*5036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 345*5036Skz151634 {INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 346*5036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 347*5036Skz151634 {INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK, 348*5036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 349*5036Skz151634 {INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 350*5036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 351*5036Skz151634 {INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 352*5036Skz151634 GMS_SIZE(gms_X33), gms_X33} 353*5036Skz151634 }; 354*5036Skz151634 355*5036Skz151634 /* Returns the size (kbytes) of pre-allocated graphics memory */ 3563446Smrj static size_t 3573446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate) 3583446Smrj { 3593446Smrj uint8_t memval; 3603446Smrj size_t kbytes; 361*5036Skz151634 int i; 362*5036Skz151634 int num_modes; 3633446Smrj 364*5036Skz151634 kbytes = 0; 365*5036Skz151634 /* get GMS modes list entry */ 366*5036Skz151634 num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); 367*5036Skz151634 for (i = 0; i < num_modes; i++) { 368*5036Skz151634 if (gms_modes[i].gm_devid == softstate->tsoft_devid) 3693446Smrj break; 3703446Smrj } 371*5036Skz151634 if (i == num_modes) 372*5036Skz151634 goto done; 373*5036Skz151634 /* fetch the GMS value from DRAM controller */ 374*5036Skz151634 memval = pci_config_get8(softstate->tsoft_pcihdl, 375*5036Skz151634 gms_modes[i].gm_regoff); 376*5036Skz151634 TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval)); 377*5036Skz151634 memval = (memval & gms_modes[i].gm_mask) >> GMS_SHIFT; 378*5036Skz151634 /* assuming zero byte for 0 or "reserved" GMS values */ 379*5036Skz151634 if (memval == 0 || memval > gms_modes[i].gm_num) { 380*5036Skz151634 TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: " 381*5036Skz151634 "devid = %x, GMS = %x. assuming zero byte of " 382*5036Skz151634 "pre-allocated memory", gms_modes[i].gm_devid, memval)); 383*5036Skz151634 goto done; 384*5036Skz151634 } 385*5036Skz151634 memval--; /* use (GMS_value - 1) as index */ 386*5036Skz151634 kbytes = (gms_modes[i].gm_vec)[memval]; 3873446Smrj 388*5036Skz151634 done: 3894478Skz151634 TARGETDB_PRINT2((CE_NOTE, 3904478Skz151634 "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected", 3914478Skz151634 kbytes)); 3923446Smrj return (kbytes); 3933446Smrj } 3943446Smrj 3953446Smrj /*ARGSUSED*/ 3963446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 3973446Smrj void *arg, void **resultp) 3983446Smrj { 3993446Smrj agp_target_softstate_t *st; 4003446Smrj int instance, rval = DDI_FAILURE; 4013446Smrj dev_t dev; 4023446Smrj 4033446Smrj switch (cmd) { 4043446Smrj case DDI_INFO_DEVT2DEVINFO: 4053446Smrj dev = (dev_t)arg; 4063446Smrj instance = DEV2INST(dev); 4073446Smrj st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4083446Smrj if (st != NULL) { 4093446Smrj mutex_enter(&st->tsoft_lock); 4103446Smrj *resultp = st->tsoft_dip; 4113446Smrj mutex_exit(&st->tsoft_lock); 4123446Smrj rval = DDI_SUCCESS; 4133446Smrj } else 4143446Smrj *resultp = NULL; 4153446Smrj 4163446Smrj break; 4173446Smrj case DDI_INFO_DEVT2INSTANCE: 4183446Smrj dev = (dev_t)arg; 4193446Smrj instance = DEV2INST(dev); 4203446Smrj *resultp = (void *)(uintptr_t)instance; 4213446Smrj rval = DDI_SUCCESS; 4223446Smrj default: 4233446Smrj break; 4243446Smrj } 4253446Smrj 4263446Smrj return (rval); 4273446Smrj } 4283446Smrj 4293446Smrj static int 4303446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4313446Smrj { 4323446Smrj agp_target_softstate_t *softstate; 4333446Smrj int instance; 4343446Smrj int status; 4353446Smrj 4363446Smrj if (cmd != DDI_ATTACH) 4373446Smrj return (DDI_FAILURE); 4383446Smrj 4393446Smrj instance = ddi_get_instance(dip); 4403446Smrj 4413446Smrj if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) != 4423446Smrj DDI_SUCCESS) 4433446Smrj return (DDI_FAILURE); 4443446Smrj 4453446Smrj softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4463446Smrj mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 4473446Smrj softstate->tsoft_dip = dip; 4483446Smrj status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 4493446Smrj if (status != DDI_SUCCESS) { 4503446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 4513446Smrj return (DDI_FAILURE); 4523446Smrj } 4533446Smrj 4543446Smrj softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 4553446Smrj PCI_CONF_VENID); 4563446Smrj softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 4573446Smrj if (softstate->tsoft_acaptr == 0) { 4583446Smrj /* Make a correction for some Intel chipsets */ 4593446Smrj if ((softstate->tsoft_devid & VENDOR_ID_MASK) == 4603446Smrj INTEL_VENDOR_ID) 4613446Smrj softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 4623446Smrj else 4633446Smrj return (DDI_FAILURE); 4643446Smrj } 4653446Smrj 4663446Smrj status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 4673446Smrj INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 4683446Smrj 4693446Smrj if (status != DDI_SUCCESS) { 4703446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 4713446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 4723446Smrj return (DDI_FAILURE); 4733446Smrj } 4743446Smrj 4753446Smrj return (DDI_SUCCESS); 4763446Smrj } 4773446Smrj 4783446Smrj /*ARGSUSED*/ 4793446Smrj static int 4803446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4813446Smrj { 4823446Smrj int instance; 4833446Smrj agp_target_softstate_t *softstate; 4843446Smrj 4853446Smrj if (cmd != DDI_DETACH) 4863446Smrj return (DDI_FAILURE); 4873446Smrj 4883446Smrj instance = ddi_get_instance(dip); 4893446Smrj 4903446Smrj softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4913446Smrj 4923446Smrj ddi_remove_minor_node(dip, AGPTARGET_NAME); 4933446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 4943446Smrj mutex_destroy(&softstate->tsoft_lock); 4953446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 4963446Smrj return (DDI_SUCCESS); 4973446Smrj } 4983446Smrj 4993446Smrj /*ARGSUSED*/ 5003446Smrj static int 5013446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 5023446Smrj cred_t *cred, int *rval) 5033446Smrj { 5043446Smrj int instance = DEV2INST(dev); 5053446Smrj agp_target_softstate_t *st; 5063446Smrj static char kernel_only[] = 5073446Smrj "amd64_gart_ioctl: is a kernel only ioctl"; 5083446Smrj 5093446Smrj if (!(mode & FKIOCTL)) { 5103446Smrj TARGETDB_PRINT2((CE_CONT, kernel_only)); 5113446Smrj return (ENXIO); 5123446Smrj } 5133446Smrj st = GETSOFTC(instance); 5143446Smrj 5153446Smrj if (st == NULL) 5163446Smrj return (ENXIO); 5173446Smrj 5183446Smrj mutex_enter(&st->tsoft_lock); 5193446Smrj 5203446Smrj switch (cmd) { 5213446Smrj case CHIP_DETECT: 5223446Smrj { 5233446Smrj int type; 5243446Smrj switch (st->tsoft_devid & VENDOR_ID_MASK) { 5253446Smrj case INTEL_VENDOR_ID: 5263446Smrj type = CHIP_IS_INTEL; 5273446Smrj break; 5283446Smrj case AMD_VENDOR_ID: 5293446Smrj type = CHIP_IS_AMD; 5303446Smrj break; 5313446Smrj default: 5323446Smrj type = 0; 5333446Smrj } 5343446Smrj if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 5353446Smrj mutex_exit(&st->tsoft_lock); 5363446Smrj return (EFAULT); 5373446Smrj } 5383446Smrj 5393446Smrj break; 5403446Smrj } 5413446Smrj case I8XX_GET_PREALLOC_SIZE: 5423446Smrj { 5433446Smrj size_t prealloc_size; 5443446Smrj 5453446Smrj if ((st->tsoft_devid & VENDOR_ID_MASK) != 5463446Smrj INTEL_VENDOR_ID) { 5473446Smrj mutex_exit(&st->tsoft_lock); 5483446Smrj return (EINVAL); 5493446Smrj } 5503446Smrj 5513446Smrj prealloc_size = i8xx_biosmem_detect(st); 5523446Smrj if (ddi_copyout(&prealloc_size, (void *)data, 5533446Smrj sizeof (size_t), mode)) { 5543446Smrj mutex_exit(&st->tsoft_lock); 5553446Smrj return (EFAULT); 5563446Smrj } 5573446Smrj 5583446Smrj break; 5593446Smrj } 5603446Smrj case AGP_TARGET_GETINFO: 5613446Smrj { 5623446Smrj i_agp_info_t info; 5633446Smrj uint32_t value; 5643446Smrj off_t cap; 5653446Smrj 5663446Smrj ASSERT(st->tsoft_acaptr); 5673446Smrj 5683446Smrj cap = st->tsoft_acaptr; 5693446Smrj value = pci_config_get32(st->tsoft_pcihdl, cap); 5703446Smrj info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 5713446Smrj info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 5723446Smrj info.iagp_devid = st->tsoft_devid; 5733446Smrj info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 5744303Skz151634 cap + AGP_CONF_STATUS); 5753446Smrj info.iagp_aperbase = agp_target_get_apbase(st); 5763446Smrj info.iagp_apersize = agp_target_get_apsize(st); 5773446Smrj 5783446Smrj if (ddi_copyout(&info, (void *)data, 5793446Smrj sizeof (i_agp_info_t), mode)) { 5803446Smrj mutex_exit(&st->tsoft_lock); 5813446Smrj return (EFAULT); 5823446Smrj } 5833446Smrj break; 5843446Smrj 5853446Smrj } 5863446Smrj /* 5873446Smrj * This ioctl is only for Intel AGP chipsets. 5883446Smrj * It is not necessary for the AMD8151 AGP bridge, because 5893446Smrj * this register in the AMD8151 does not control any hardware. 5903446Smrj * It is only provided for compatibility with an Intel AGP bridge. 5913446Smrj * Please refer to the <<AMD8151 data sheet>> page 24, 5923446Smrj * AGP device GART pointer. 5933446Smrj */ 5943446Smrj case AGP_TARGET_SET_GATTADDR: 5953446Smrj { 5963446Smrj uint32_t gartaddr; 5973446Smrj 5983446Smrj if (ddi_copyin((void *)data, &gartaddr, 5993446Smrj sizeof (uint32_t), mode)) { 6003446Smrj mutex_exit(&st->tsoft_lock); 6013446Smrj return (EFAULT); 6023446Smrj } 6033446Smrj 6043446Smrj agp_target_set_gartaddr(st, gartaddr); 6053446Smrj break; 6063446Smrj } 6073446Smrj case AGP_TARGET_SETCMD: 6083446Smrj { 6093446Smrj uint32_t command; 6103446Smrj 6113446Smrj if (ddi_copyin((void *)data, &command, 6123446Smrj sizeof (uint32_t), mode)) { 6133446Smrj mutex_exit(&st->tsoft_lock); 6143446Smrj return (EFAULT); 6153446Smrj } 6163446Smrj 6173446Smrj ASSERT(st->tsoft_acaptr); 6183446Smrj 6193446Smrj pci_config_put32(st->tsoft_pcihdl, 6203446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 6213446Smrj command); 6223446Smrj break; 6233446Smrj 6243446Smrj } 6253446Smrj case AGP_TARGET_FLUSH_GTLB: 6263446Smrj { 6273446Smrj uint16_t value; 6283446Smrj 6293446Smrj ASSERT(st->tsoft_acaptr); 6303446Smrj 6313446Smrj value = pci_config_get16(st->tsoft_pcihdl, 6323446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL); 6333446Smrj value &= ~AGPCTRL_GTLBEN; 6343446Smrj pci_config_put16(st->tsoft_pcihdl, 6353446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 6363446Smrj value |= AGPCTRL_GTLBEN; 6373446Smrj pci_config_put16(st->tsoft_pcihdl, 6383446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 6393446Smrj 6403446Smrj break; 6413446Smrj } 6423446Smrj case AGP_TARGET_CONFIGURE: 6433446Smrj { 6443446Smrj uint8_t value; 6453446Smrj 6463446Smrj ASSERT(st->tsoft_acaptr); 6473446Smrj 6483446Smrj value = pci_config_get8(st->tsoft_pcihdl, 6493446Smrj st->tsoft_acaptr + AGP_CONF_MISC); 6503446Smrj value |= AGP_MISC_APEN; 6513446Smrj pci_config_put8(st->tsoft_pcihdl, 6523446Smrj st->tsoft_acaptr + AGP_CONF_MISC, value); 6533446Smrj break; 6543446Smrj 6553446Smrj } 6563446Smrj case AGP_TARGET_UNCONFIG: 6573446Smrj { 6583446Smrj uint32_t value1; 6593446Smrj uint8_t value2; 6603446Smrj 6613446Smrj ASSERT(st->tsoft_acaptr); 6623446Smrj 6633446Smrj pci_config_put16(st->tsoft_pcihdl, 6643446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 6653446Smrj 6663446Smrj value2 = pci_config_get8(st->tsoft_pcihdl, 6673446Smrj st->tsoft_acaptr + AGP_CONF_MISC); 6683446Smrj value2 &= ~AGP_MISC_APEN; 6693446Smrj pci_config_put8(st->tsoft_pcihdl, 6703446Smrj st->tsoft_acaptr + AGP_CONF_MISC, value2); 6713446Smrj 6723446Smrj value1 = pci_config_get32(st->tsoft_pcihdl, 6733446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND); 6743446Smrj value1 &= ~AGPCMD_AGPEN; 6753446Smrj pci_config_put32(st->tsoft_pcihdl, 6763446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 6773446Smrj value1); 6783446Smrj 6793446Smrj pci_config_put32(st->tsoft_pcihdl, 6803446Smrj st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 6813446Smrj 6823446Smrj break; 6833446Smrj } 6843446Smrj 6853446Smrj default: 6863446Smrj mutex_exit(&st->tsoft_lock); 6873446Smrj return (ENXIO); 6883446Smrj } /* end switch */ 6893446Smrj 6903446Smrj mutex_exit(&st->tsoft_lock); 6913446Smrj 6923446Smrj return (0); 6933446Smrj } 6943446Smrj 6953446Smrj /*ARGSUSED*/ 6963446Smrj static int 6973446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 6983446Smrj { 6993446Smrj int instance = DEV2INST(*devp); 7003446Smrj agp_target_softstate_t *st; 7013446Smrj 7023446Smrj if (!(flag & FKLYR)) 7033446Smrj return (ENXIO); 7043446Smrj 7053446Smrj st = GETSOFTC(instance); 7063446Smrj 7073446Smrj if (st == NULL) 7083446Smrj return (ENXIO); 7093446Smrj 7103446Smrj return (0); 7113446Smrj } 7123446Smrj 7133446Smrj /*ARGSUSED*/ 7143446Smrj static int 7153446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 7163446Smrj { 7173446Smrj int instance = DEV2INST(dev); 7183446Smrj agp_target_softstate_t *st; 7193446Smrj 7203446Smrj st = GETSOFTC(instance); 7213446Smrj 7223446Smrj if (st == NULL) 7233446Smrj return (ENXIO); 7243446Smrj 7253446Smrj return (0); 7263446Smrj } 7273446Smrj 7283446Smrj static struct cb_ops agp_target_cb_ops = { 7293446Smrj agp_target_open, /* cb_open */ 7303446Smrj agp_target_close, /* cb_close */ 7313446Smrj nodev, /* cb_strategy */ 7323446Smrj nodev, /* cb_print */ 7333446Smrj nodev, /* cb_dump */ 7343446Smrj nodev, /* cb_read() */ 7353446Smrj nodev, /* cb_write() */ 7363446Smrj agp_target_ioctl, /* cb_ioctl */ 7373446Smrj nodev, /* cb_devmap */ 7383446Smrj nodev, /* cb_mmap */ 7393446Smrj nodev, /* cb_segmap */ 7403446Smrj nochpoll, /* cb_chpoll */ 7413446Smrj ddi_prop_op, /* cb_prop_op */ 7423446Smrj 0, /* cb_stream */ 7433446Smrj D_NEW | D_MP, /* cb_flag */ 7443446Smrj CB_REV, /* cb_ops version? */ 7453446Smrj nodev, /* cb_aread() */ 7463446Smrj nodev, /* cb_awrite() */ 7473446Smrj }; 7483446Smrj 7493446Smrj /* device operations */ 7503446Smrj static struct dev_ops agp_target_ops = { 7513446Smrj DEVO_REV, /* devo_rev */ 7523446Smrj 0, /* devo_refcnt */ 7533446Smrj agptarget_getinfo, /* devo_getinfo */ 7543446Smrj nulldev, /* devo_identify */ 7553446Smrj nulldev, /* devo_probe */ 7563446Smrj agp_target_attach, /* devo_attach */ 7573446Smrj agp_target_detach, /* devo_detach */ 7583446Smrj nodev, /* devo_reset */ 7593446Smrj &agp_target_cb_ops, /* devo_cb_ops */ 7603446Smrj 0, /* devo_bus_ops */ 7613446Smrj 0, /* devo_power */ 7623446Smrj }; 7633446Smrj 7643446Smrj static struct modldrv modldrv = { 7653446Smrj &mod_driverops, 7663446Smrj "AGP target driver v%I%", 7673446Smrj &agp_target_ops, 7683446Smrj }; 7693446Smrj 7703446Smrj static struct modlinkage modlinkage = { 7713446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 7723446Smrj {&modldrv, NULL, NULL, NULL} 7733446Smrj }; 7743446Smrj 7753446Smrj int 7763446Smrj _init(void) 7773446Smrj { 7783446Smrj int ret; 7793446Smrj 7803446Smrj ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 7813446Smrj sizeof (agp_target_softstate_t), 1); 7823446Smrj 7833446Smrj if (ret) 7843446Smrj goto err1; 7853446Smrj 7863446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 7873446Smrj goto err2; 7883446Smrj } 7893446Smrj 7903446Smrj return (DDI_SUCCESS); 7913446Smrj err2: 7923446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 7933446Smrj err1: 7943446Smrj return (ret); 7953446Smrj } 7963446Smrj 7973446Smrj int 7983446Smrj _info(struct modinfo *modinfop) 7993446Smrj { 8003446Smrj return (mod_info(&modlinkage, modinfop)); 8013446Smrj } 8023446Smrj 8033446Smrj int 8043446Smrj _fini(void) 8053446Smrj { 8063446Smrj int ret; 8073446Smrj 8083446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 8093446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 8103446Smrj } 8113446Smrj return (ret); 8123446Smrj } 813