13446Smrj /* 23527Sms148562 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 33446Smrj * Use is subject to license terms. 43446Smrj */ 53446Smrj 63446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 73446Smrj 83446Smrj #include <sys/systm.h> 93446Smrj #include <sys/conf.h> 103446Smrj #include <sys/modctl.h> 113446Smrj #include <sys/file.h> 123446Smrj #include <sys/stat.h> 133446Smrj #include <sys/ddi.h> 143446Smrj #include <sys/sunddi.h> 153446Smrj #include <sys/modctl.h> 163446Smrj #include <sys/sunldi.h> 173446Smrj #include <sys/pci.h> 183446Smrj #include <sys/agpgart.h> 193446Smrj #include <sys/agp/agpdefs.h> 203446Smrj #include <sys/agp/agptarget_io.h> 213446Smrj 223446Smrj int agptarget_debug_var = 0; 233446Smrj #define TARGETDB_PRINT2(fmt) if (agptarget_debug_var >= 1) cmn_err fmt 243446Smrj #define INST2NODENUM(inst) (inst) 253446Smrj #define DEV2INST(dev) (getminor(dev)) 263446Smrj 273446Smrj typedef struct agp_target_softstate { 283446Smrj dev_info_t *tsoft_dip; 293446Smrj ddi_acc_handle_t tsoft_pcihdl; 303446Smrj uint32_t tsoft_devid; 313446Smrj /* The offset of the ACAPID register */ 323446Smrj off_t tsoft_acaptr; 333446Smrj kmutex_t tsoft_lock; 343446Smrj }agp_target_softstate_t; 353446Smrj 363446Smrj static void *agptarget_glob_soft_handle; 373446Smrj 383446Smrj #define GETSOFTC(instance) ((agp_target_softstate_t *) \ 393446Smrj ddi_get_soft_state(agptarget_glob_soft_handle, instance)); 403446Smrj 413446Smrj /* 423446Smrj * The AMD8151 bridge is the only supported 64 bit hardware 433446Smrj */ 443446Smrj static int 453446Smrj is_64bit_aper(agp_target_softstate_t *softstate) 463446Smrj { 473446Smrj return (softstate->tsoft_devid == AMD_BR_8151); 483446Smrj } 493446Smrj 503446Smrj /* 513446Smrj * agp_target_cap_find() 523446Smrj * 533446Smrj * Description: 543446Smrj * This function searches the linked capability list to find the offset 553446Smrj * of the AGP capability register. When it was not found, return 0. 563446Smrj * This works for standard AGP chipsets, but not for some Intel chipsets, 573446Smrj * like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for 583446Smrj * these chipsets even if AGP is supported. So the offset of acapid 593446Smrj * should be set manually in thoses cases. 603446Smrj * 613446Smrj * Arguments: 623446Smrj * pci_handle ddi acc handle of pci config 633446Smrj * 643446Smrj * Returns: 653446Smrj * 0 No capability pointer register found 663446Smrj * nexcap The AGP capability pointer register offset 673446Smrj */ 683446Smrj static off_t 693446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle) 703446Smrj { 713446Smrj off_t nextcap = 0; 723446Smrj uint32_t ncapid = 0; 733446Smrj uint8_t value = 0; 743446Smrj 753446Smrj /* Check if this device supports the capability pointer */ 763446Smrj value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT) 773446Smrj & PCI_CONF_CAP_MASK); 783446Smrj 793446Smrj if (!value) 803446Smrj return (0); 813446Smrj /* Get the offset of the first capability pointer from CAPPTR */ 823446Smrj nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR)); 833446Smrj 843446Smrj /* Check the AGP capability from the first capability pointer */ 853446Smrj while (nextcap) { 863446Smrj ncapid = pci_config_get32(pci_handle, nextcap); 873446Smrj /* 883446Smrj * AGP3.0 rev1.0 127 the capid was assigned by the PCI SIG, 893446Smrj * 845 data sheet page 69 903446Smrj */ 913446Smrj if ((ncapid & PCI_CONF_CAPID_MASK) == 923446Smrj AGP_CAP_ID) /* The AGP cap was found */ 933446Smrj break; 943446Smrj 953446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 963446Smrj } 973446Smrj 983446Smrj return (nextcap); 993446Smrj 1003446Smrj } 1013446Smrj 1023446Smrj /* 1033446Smrj * agp_target_get_aperbase() 1043446Smrj * 1053446Smrj * Description: 1063446Smrj * This function gets the AGP aperture base address from the AGP target 1073446Smrj * register, the AGP aperture base register was programmed by the BIOS. 1083446Smrj * 1093446Smrj * Arguments: 1103446Smrj * softstate driver soft state pointer 1113446Smrj * 1123446Smrj * Returns: 1133446Smrj * aper_base AGP aperture base address 1143446Smrj * 1153446Smrj * Notes: 1163446Smrj * If a 64bit bridge device is available, the AGP aperture base address 1173446Smrj * can be 64 bit. 1183446Smrj */ 1193446Smrj static uint64_t 1203446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate) 1213446Smrj { 1223446Smrj uint64_t aper_base; 1233446Smrj 1243446Smrj if (!is_64bit_aper(softstate)) { 1253446Smrj aper_base = pci_config_get32(softstate->tsoft_pcihdl, 1263446Smrj AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK; 1273446Smrj } else { 1283446Smrj aper_base = pci_config_get64(softstate->tsoft_pcihdl, 1293446Smrj AGP_CONF_APERBASE); 1303446Smrj /* 32-bit or 64-bit aperbase base pointer */ 1313446Smrj if ((aper_base & AGP_APER_TYPE_MASK) == 0) 1323446Smrj aper_base &= AGP_32_APERBASE_MASK; 1333446Smrj else 1343446Smrj aper_base &= AGP_64_APERBASE_MASK; 1353446Smrj } 1363446Smrj return (aper_base); 1373446Smrj } 1383446Smrj 1393446Smrj /* 1403446Smrj * agp_target_get_apsize() 1413446Smrj * 1423446Smrj * Description: 1433446Smrj * This function gets the AGP aperture size by reading the AGP aperture 1443446Smrj * size register. 1453446Smrj * Arguments: 1463446Smrj * softstate driver soft state pointer 1473446Smrj * 1483446Smrj * Return: 1493446Smrj * size The AGP aperture size in megabytes 1503446Smrj * 0 an unexpected error 1513446Smrj */ 1523446Smrj static size_t 1533446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate) 1543446Smrj { 1553446Smrj off_t cap; 1563446Smrj uint16_t value; 1573446Smrj size_t size, regsize; 1583446Smrj 1593446Smrj ASSERT(softstate->tsoft_acaptr); 1603446Smrj cap = softstate->tsoft_acaptr; 1613446Smrj 1623446Smrj if ((softstate->tsoft_devid & VENDOR_ID_MASK) == INTEL_VENDOR_ID) { 1633446Smrj /* extend this value to 16 bit for later tests */ 1643446Smrj value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl, 1653446Smrj cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK; 1663446Smrj } else { 1673446Smrj value = pci_config_get16(softstate->tsoft_pcihdl, 1683446Smrj cap + AGP_CONF_APERSIZE); 1693446Smrj } 1703446Smrj 1713446Smrj if (value & AGP_APER_128M_MASK) { 1723446Smrj switch (value & AGP_APER_128M_MASK) { 1733446Smrj case AGP_APER_4M: 1743446Smrj size = 4; /* 4M */ 1753446Smrj break; 1763446Smrj case AGP_APER_8M: 1773446Smrj size = 8; /* 8M */ 1783446Smrj break; 1793446Smrj case AGP_APER_16M: 1803446Smrj size = 16; /* 16M */ 1813446Smrj break; 1823446Smrj case AGP_APER_32M: 1833446Smrj size = 32; /* 32M */ 1843446Smrj break; 1853446Smrj case AGP_APER_64M: 1863446Smrj size = 64; /* 64M */ 1873446Smrj break; 1883446Smrj case AGP_APER_128M: 1893446Smrj size = 128; /* 128M */ 1903446Smrj break; 1913446Smrj default: 1923446Smrj size = 0; /* not true */ 1933446Smrj } 1943446Smrj } else { 1953446Smrj switch (value & AGP_APER_4G_MASK) { 1963446Smrj case AGP_APER_256M: 1973446Smrj size = 256; /* 256 M */ 1983446Smrj break; 1993446Smrj case AGP_APER_512M: 2003446Smrj size = 512; /* 512 M */ 2013446Smrj break; 2023446Smrj case AGP_APER_1024M: 2033446Smrj size = 1024; /* 1024 M */ 2043446Smrj break; 2053446Smrj case AGP_APER_2048M: 2063446Smrj size = 2048; /* 2048 M */ 2073446Smrj break; 2083446Smrj case AGP_APER_4G: 2093446Smrj size = 4096; /* 4096 M */ 2103446Smrj break; 2113446Smrj default: 2123446Smrj size = 0; /* not true */ 2133446Smrj } 2143446Smrj } 2153446Smrj /* 2163446Smrj * In some cases, there is no APSIZE register, so the size value 2173446Smrj * of 256M could be wrong. Check the value by reading the size of 2183446Smrj * the first register which was set in the PCI configuration space. 2193446Smrj */ 2203446Smrj if (size == 256) { 2213446Smrj if (ddi_dev_regsize(softstate->tsoft_dip, 2223446Smrj AGP_TARGET_BAR1, (off_t *)®size) == DDI_FAILURE) 2233446Smrj return (0); 2243446Smrj 2253446Smrj if (MB2BYTES(size) != regsize) { 2263446Smrj TARGETDB_PRINT2((CE_WARN, 2273446Smrj "APSIZE 256M doesn't match regsize %lx", 2283446Smrj regsize)); 2293446Smrj TARGETDB_PRINT2((CE_WARN, "Use regsize instead")); 2303446Smrj size = BYTES2MB(regsize); 2313446Smrj } 2323446Smrj } 2333446Smrj 2343446Smrj return (size); 2353446Smrj } 2363446Smrj 2373446Smrj static void 2383446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr) 2393446Smrj { 2403446Smrj ASSERT(softstate->tsoft_acaptr); 2413446Smrj 2423446Smrj /* Disable the GTLB for Intel chipsets */ 2433446Smrj pci_config_put16(softstate->tsoft_pcihdl, 2443446Smrj softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000); 2453446Smrj 2463446Smrj pci_config_put32(softstate->tsoft_pcihdl, 2473446Smrj softstate->tsoft_acaptr + AGP_CONF_ATTBASE, 2483446Smrj gartaddr & AGP_ATTBASE_MASK); 2493446Smrj } 2503446Smrj 2513446Smrj static size_t 2523446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate) 2533446Smrj { 2543446Smrj uint8_t memval; 2553446Smrj size_t kbytes; 2563446Smrj 2573446Smrj switch (softstate->tsoft_devid) { 2583446Smrj case INTEL_BR_810: 2593446Smrj case INTEL_BR_810DC: 2603446Smrj case INTEL_BR_810E: 2613446Smrj memval = pci_config_get8(softstate->tsoft_pcihdl, 2623446Smrj I810_CONF_SMRAM); 2633446Smrj switch (memval & I810_GMS_MASK) { 2643446Smrj case 0x80: 2653446Smrj kbytes = 512; /* 512K preallocated memory */ 2663446Smrj break; 2673446Smrj case 0xc0: 2683446Smrj kbytes = 1024; /* 1024K preallocated memory */ 2693446Smrj break; 2703446Smrj default: 2713446Smrj kbytes = 0; /* an unexpected case */ 2723446Smrj } 2733446Smrj break; 2743446Smrj case INTEL_BR_830M: 2753446Smrj case INTEL_BR_845: 2763446Smrj memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 2773446Smrj switch (memval & I8XX_GC_MODE_MASK) { 2783446Smrj case I8XX_GC_MODE2: 2793446Smrj kbytes = 512; /* 512K preallocated memory */ 2803446Smrj break; 2813446Smrj case I8XX_GC_MODE3: 2823446Smrj kbytes = 1024; /* 1M preallocated memory */ 2833446Smrj break; 2843446Smrj case I8XX_GC_MODE4: 2853446Smrj kbytes = 8 * 1024; /* 8M preallocated memory */ 2863446Smrj break; 2873446Smrj default: 2883446Smrj kbytes = 0; /* an unexpected case */ 2893446Smrj } 2903446Smrj break; 2913446Smrj case INTEL_BR_855GM: 2923446Smrj memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 2933446Smrj switch (memval & I8XX_GC_MODE_MASK) { 2943446Smrj case I8XX_GC_MODE1: 2953446Smrj kbytes = 1024; /* 1M preallocated memory */ 2963446Smrj break; 2973446Smrj case I8XX_GC_MODE2: 2983446Smrj kbytes = 4 * 1024; /* 4M preallocated memory */ 2993446Smrj break; 3003446Smrj case I8XX_GC_MODE3: 3013446Smrj kbytes = 8 * 1024; /* 8M preallocated memory */ 3023446Smrj break; 3033446Smrj case I8XX_GC_MODE4: 3043446Smrj kbytes = 16 * 1024; /* 16M preallocated memory */ 3053446Smrj break; 3063446Smrj case I8XX_GC_MODE5: 3073446Smrj kbytes = 32 * 1024; /* 32M preallocated memory */ 3083446Smrj break; 3093446Smrj default: 3103446Smrj kbytes = 0; /* an unexpected case */ 3113446Smrj } 3123446Smrj break; 3133446Smrj case INTEL_BR_865: 3143527Sms148562 case INTEL_BR_910M: 3153446Smrj memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 3163446Smrj switch (memval & I8XX_GC_MODE_MASK) { 3173446Smrj case I8XX_GC_MODE1: 3183446Smrj kbytes = 1024; /* 1M preallocated memory */ 3193446Smrj break; 3203446Smrj case I8XX_GC_MODE3: 3213446Smrj kbytes = 8 * 1024; /* 8M preallocated memory */ 3223446Smrj break; 3233527Sms148562 /* 3243527Sms148562 * There is no option for 16M in 910GM datasheet, 3253527Sms148562 * but some BIOS add this option for 16M support. 3263527Sms148562 */ 3273446Smrj case I8XX_GC_MODE4: 3283446Smrj kbytes = 16 * 1024; /* 16M preallocated memory */ 3293446Smrj break; 3303446Smrj default: 3313446Smrj kbytes = 0; /* an unexpected case */ 3323446Smrj } 3333446Smrj break; 3343446Smrj case INTEL_BR_910: 3353446Smrj case INTEL_BR_945: 336*4303Skz151634 case INTEL_BR_945GM: 3373446Smrj memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC); 3383446Smrj switch (memval & I8XX_GC_MODE_MASK) { 3393446Smrj case I8XX_GC_MODE1: 3403446Smrj kbytes = 1024; /* 1M preallocated memory */ 3413446Smrj break; 3423446Smrj case I8XX_GC_MODE3: 3433446Smrj kbytes = 8 * 1024; /* 8M preallocated memory */ 3443446Smrj break; 3453446Smrj default: 3463446Smrj kbytes = 0; /* an unexpected case */ 3473446Smrj } 3483446Smrj break; 3493446Smrj default: 3503446Smrj kbytes = 0; 3513446Smrj } 3523446Smrj 3533446Smrj return (kbytes); 3543446Smrj } 3553446Smrj 3563446Smrj /*ARGSUSED*/ 3573446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 3583446Smrj void *arg, void **resultp) 3593446Smrj { 3603446Smrj agp_target_softstate_t *st; 3613446Smrj int instance, rval = DDI_FAILURE; 3623446Smrj dev_t dev; 3633446Smrj 3643446Smrj switch (cmd) { 3653446Smrj case DDI_INFO_DEVT2DEVINFO: 3663446Smrj dev = (dev_t)arg; 3673446Smrj instance = DEV2INST(dev); 3683446Smrj st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 3693446Smrj if (st != NULL) { 3703446Smrj mutex_enter(&st->tsoft_lock); 3713446Smrj *resultp = st->tsoft_dip; 3723446Smrj mutex_exit(&st->tsoft_lock); 3733446Smrj rval = DDI_SUCCESS; 3743446Smrj } else 3753446Smrj *resultp = NULL; 3763446Smrj 3773446Smrj break; 3783446Smrj case DDI_INFO_DEVT2INSTANCE: 3793446Smrj dev = (dev_t)arg; 3803446Smrj instance = DEV2INST(dev); 3813446Smrj *resultp = (void *)(uintptr_t)instance; 3823446Smrj rval = DDI_SUCCESS; 3833446Smrj default: 3843446Smrj break; 3853446Smrj } 3863446Smrj 3873446Smrj return (rval); 3883446Smrj } 3893446Smrj 3903446Smrj static int 3913446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3923446Smrj { 3933446Smrj agp_target_softstate_t *softstate; 3943446Smrj int instance; 3953446Smrj int status; 3963446Smrj 3973446Smrj if (cmd != DDI_ATTACH) 3983446Smrj return (DDI_FAILURE); 3993446Smrj 4003446Smrj instance = ddi_get_instance(dip); 4013446Smrj 4023446Smrj if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) != 4033446Smrj DDI_SUCCESS) 4043446Smrj return (DDI_FAILURE); 4053446Smrj 4063446Smrj softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4073446Smrj mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 4083446Smrj softstate->tsoft_dip = dip; 4093446Smrj status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 4103446Smrj if (status != DDI_SUCCESS) { 4113446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 4123446Smrj return (DDI_FAILURE); 4133446Smrj } 4143446Smrj 4153446Smrj softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 4163446Smrj PCI_CONF_VENID); 4173446Smrj softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 4183446Smrj if (softstate->tsoft_acaptr == 0) { 4193446Smrj /* Make a correction for some Intel chipsets */ 4203446Smrj if ((softstate->tsoft_devid & VENDOR_ID_MASK) == 4213446Smrj INTEL_VENDOR_ID) 4223446Smrj softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 4233446Smrj else 4243446Smrj return (DDI_FAILURE); 4253446Smrj } 4263446Smrj 4273446Smrj status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 4283446Smrj INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 4293446Smrj 4303446Smrj if (status != DDI_SUCCESS) { 4313446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 4323446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 4333446Smrj return (DDI_FAILURE); 4343446Smrj } 4353446Smrj 4363446Smrj return (DDI_SUCCESS); 4373446Smrj } 4383446Smrj 4393446Smrj /*ARGSUSED*/ 4403446Smrj static int 4413446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4423446Smrj { 4433446Smrj int instance; 4443446Smrj agp_target_softstate_t *softstate; 4453446Smrj 4463446Smrj if (cmd != DDI_DETACH) 4473446Smrj return (DDI_FAILURE); 4483446Smrj 4493446Smrj instance = ddi_get_instance(dip); 4503446Smrj 4513446Smrj softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4523446Smrj 4533446Smrj ddi_remove_minor_node(dip, AGPTARGET_NAME); 4543446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 4553446Smrj mutex_destroy(&softstate->tsoft_lock); 4563446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 4573446Smrj return (DDI_SUCCESS); 4583446Smrj } 4593446Smrj 4603446Smrj /*ARGSUSED*/ 4613446Smrj static int 4623446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 4633446Smrj cred_t *cred, int *rval) 4643446Smrj { 4653446Smrj int instance = DEV2INST(dev); 4663446Smrj agp_target_softstate_t *st; 4673446Smrj static char kernel_only[] = 4683446Smrj "amd64_gart_ioctl: is a kernel only ioctl"; 4693446Smrj 4703446Smrj if (!(mode & FKIOCTL)) { 4713446Smrj TARGETDB_PRINT2((CE_CONT, kernel_only)); 4723446Smrj return (ENXIO); 4733446Smrj } 4743446Smrj st = GETSOFTC(instance); 4753446Smrj 4763446Smrj if (st == NULL) 4773446Smrj return (ENXIO); 4783446Smrj 4793446Smrj mutex_enter(&st->tsoft_lock); 4803446Smrj 4813446Smrj switch (cmd) { 4823446Smrj case CHIP_DETECT: 4833446Smrj { 4843446Smrj int type; 4853446Smrj switch (st->tsoft_devid & VENDOR_ID_MASK) { 4863446Smrj case INTEL_VENDOR_ID: 4873446Smrj type = CHIP_IS_INTEL; 4883446Smrj break; 4893446Smrj case AMD_VENDOR_ID: 4903446Smrj type = CHIP_IS_AMD; 4913446Smrj break; 4923446Smrj default: 4933446Smrj type = 0; 4943446Smrj } 4953446Smrj if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 4963446Smrj mutex_exit(&st->tsoft_lock); 4973446Smrj return (EFAULT); 4983446Smrj } 4993446Smrj 5003446Smrj break; 5013446Smrj } 5023446Smrj case I8XX_GET_PREALLOC_SIZE: 5033446Smrj { 5043446Smrj size_t prealloc_size; 5053446Smrj 5063446Smrj if ((st->tsoft_devid & VENDOR_ID_MASK) != 5073446Smrj INTEL_VENDOR_ID) { 5083446Smrj mutex_exit(&st->tsoft_lock); 5093446Smrj return (EINVAL); 5103446Smrj } 5113446Smrj 5123446Smrj prealloc_size = i8xx_biosmem_detect(st); 5133446Smrj if (ddi_copyout(&prealloc_size, (void *)data, 5143446Smrj sizeof (size_t), mode)) { 5153446Smrj mutex_exit(&st->tsoft_lock); 5163446Smrj return (EFAULT); 5173446Smrj } 5183446Smrj 5193446Smrj break; 5203446Smrj } 5213446Smrj case AGP_TARGET_GETINFO: 5223446Smrj { 5233446Smrj i_agp_info_t info; 5243446Smrj uint32_t value; 5253446Smrj off_t cap; 5263446Smrj 5273446Smrj ASSERT(st->tsoft_acaptr); 5283446Smrj 5293446Smrj cap = st->tsoft_acaptr; 5303446Smrj value = pci_config_get32(st->tsoft_pcihdl, cap); 5313446Smrj info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 5323446Smrj info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 5333446Smrj info.iagp_devid = st->tsoft_devid; 5343446Smrj info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 535*4303Skz151634 cap + AGP_CONF_STATUS); 5363446Smrj info.iagp_aperbase = agp_target_get_apbase(st); 5373446Smrj info.iagp_apersize = agp_target_get_apsize(st); 5383446Smrj 5393446Smrj if (ddi_copyout(&info, (void *)data, 5403446Smrj sizeof (i_agp_info_t), mode)) { 5413446Smrj mutex_exit(&st->tsoft_lock); 5423446Smrj return (EFAULT); 5433446Smrj } 5443446Smrj break; 5453446Smrj 5463446Smrj } 5473446Smrj /* 5483446Smrj * This ioctl is only for Intel AGP chipsets. 5493446Smrj * It is not necessary for the AMD8151 AGP bridge, because 5503446Smrj * this register in the AMD8151 does not control any hardware. 5513446Smrj * It is only provided for compatibility with an Intel AGP bridge. 5523446Smrj * Please refer to the <<AMD8151 data sheet>> page 24, 5533446Smrj * AGP device GART pointer. 5543446Smrj */ 5553446Smrj case AGP_TARGET_SET_GATTADDR: 5563446Smrj { 5573446Smrj uint32_t gartaddr; 5583446Smrj 5593446Smrj if (ddi_copyin((void *)data, &gartaddr, 5603446Smrj sizeof (uint32_t), mode)) { 5613446Smrj mutex_exit(&st->tsoft_lock); 5623446Smrj return (EFAULT); 5633446Smrj } 5643446Smrj 5653446Smrj agp_target_set_gartaddr(st, gartaddr); 5663446Smrj break; 5673446Smrj } 5683446Smrj case AGP_TARGET_SETCMD: 5693446Smrj { 5703446Smrj uint32_t command; 5713446Smrj 5723446Smrj if (ddi_copyin((void *)data, &command, 5733446Smrj sizeof (uint32_t), mode)) { 5743446Smrj mutex_exit(&st->tsoft_lock); 5753446Smrj return (EFAULT); 5763446Smrj } 5773446Smrj 5783446Smrj ASSERT(st->tsoft_acaptr); 5793446Smrj 5803446Smrj pci_config_put32(st->tsoft_pcihdl, 5813446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 5823446Smrj command); 5833446Smrj break; 5843446Smrj 5853446Smrj } 5863446Smrj case AGP_TARGET_FLUSH_GTLB: 5873446Smrj { 5883446Smrj uint16_t value; 5893446Smrj 5903446Smrj ASSERT(st->tsoft_acaptr); 5913446Smrj 5923446Smrj value = pci_config_get16(st->tsoft_pcihdl, 5933446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL); 5943446Smrj value &= ~AGPCTRL_GTLBEN; 5953446Smrj pci_config_put16(st->tsoft_pcihdl, 5963446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 5973446Smrj value |= AGPCTRL_GTLBEN; 5983446Smrj pci_config_put16(st->tsoft_pcihdl, 5993446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 6003446Smrj 6013446Smrj break; 6023446Smrj } 6033446Smrj case AGP_TARGET_CONFIGURE: 6043446Smrj { 6053446Smrj uint8_t value; 6063446Smrj 6073446Smrj ASSERT(st->tsoft_acaptr); 6083446Smrj 6093446Smrj value = pci_config_get8(st->tsoft_pcihdl, 6103446Smrj st->tsoft_acaptr + AGP_CONF_MISC); 6113446Smrj value |= AGP_MISC_APEN; 6123446Smrj pci_config_put8(st->tsoft_pcihdl, 6133446Smrj st->tsoft_acaptr + AGP_CONF_MISC, value); 6143446Smrj break; 6153446Smrj 6163446Smrj } 6173446Smrj case AGP_TARGET_UNCONFIG: 6183446Smrj { 6193446Smrj uint32_t value1; 6203446Smrj uint8_t value2; 6213446Smrj 6223446Smrj ASSERT(st->tsoft_acaptr); 6233446Smrj 6243446Smrj pci_config_put16(st->tsoft_pcihdl, 6253446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 6263446Smrj 6273446Smrj value2 = pci_config_get8(st->tsoft_pcihdl, 6283446Smrj st->tsoft_acaptr + AGP_CONF_MISC); 6293446Smrj value2 &= ~AGP_MISC_APEN; 6303446Smrj pci_config_put8(st->tsoft_pcihdl, 6313446Smrj st->tsoft_acaptr + AGP_CONF_MISC, value2); 6323446Smrj 6333446Smrj value1 = pci_config_get32(st->tsoft_pcihdl, 6343446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND); 6353446Smrj value1 &= ~AGPCMD_AGPEN; 6363446Smrj pci_config_put32(st->tsoft_pcihdl, 6373446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 6383446Smrj value1); 6393446Smrj 6403446Smrj pci_config_put32(st->tsoft_pcihdl, 6413446Smrj st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 6423446Smrj 6433446Smrj break; 6443446Smrj } 6453446Smrj 6463446Smrj default: 6473446Smrj mutex_exit(&st->tsoft_lock); 6483446Smrj return (ENXIO); 6493446Smrj } /* end switch */ 6503446Smrj 6513446Smrj mutex_exit(&st->tsoft_lock); 6523446Smrj 6533446Smrj return (0); 6543446Smrj } 6553446Smrj 6563446Smrj /*ARGSUSED*/ 6573446Smrj static int 6583446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 6593446Smrj { 6603446Smrj int instance = DEV2INST(*devp); 6613446Smrj agp_target_softstate_t *st; 6623446Smrj 6633446Smrj if (!(flag & FKLYR)) 6643446Smrj return (ENXIO); 6653446Smrj 6663446Smrj st = GETSOFTC(instance); 6673446Smrj 6683446Smrj if (st == NULL) 6693446Smrj return (ENXIO); 6703446Smrj 6713446Smrj return (0); 6723446Smrj } 6733446Smrj 6743446Smrj /*ARGSUSED*/ 6753446Smrj static int 6763446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 6773446Smrj { 6783446Smrj int instance = DEV2INST(dev); 6793446Smrj agp_target_softstate_t *st; 6803446Smrj 6813446Smrj st = GETSOFTC(instance); 6823446Smrj 6833446Smrj if (st == NULL) 6843446Smrj return (ENXIO); 6853446Smrj 6863446Smrj return (0); 6873446Smrj } 6883446Smrj 6893446Smrj static struct cb_ops agp_target_cb_ops = { 6903446Smrj agp_target_open, /* cb_open */ 6913446Smrj agp_target_close, /* cb_close */ 6923446Smrj nodev, /* cb_strategy */ 6933446Smrj nodev, /* cb_print */ 6943446Smrj nodev, /* cb_dump */ 6953446Smrj nodev, /* cb_read() */ 6963446Smrj nodev, /* cb_write() */ 6973446Smrj agp_target_ioctl, /* cb_ioctl */ 6983446Smrj nodev, /* cb_devmap */ 6993446Smrj nodev, /* cb_mmap */ 7003446Smrj nodev, /* cb_segmap */ 7013446Smrj nochpoll, /* cb_chpoll */ 7023446Smrj ddi_prop_op, /* cb_prop_op */ 7033446Smrj 0, /* cb_stream */ 7043446Smrj D_NEW | D_MP, /* cb_flag */ 7053446Smrj CB_REV, /* cb_ops version? */ 7063446Smrj nodev, /* cb_aread() */ 7073446Smrj nodev, /* cb_awrite() */ 7083446Smrj }; 7093446Smrj 7103446Smrj /* device operations */ 7113446Smrj static struct dev_ops agp_target_ops = { 7123446Smrj DEVO_REV, /* devo_rev */ 7133446Smrj 0, /* devo_refcnt */ 7143446Smrj agptarget_getinfo, /* devo_getinfo */ 7153446Smrj nulldev, /* devo_identify */ 7163446Smrj nulldev, /* devo_probe */ 7173446Smrj agp_target_attach, /* devo_attach */ 7183446Smrj agp_target_detach, /* devo_detach */ 7193446Smrj nodev, /* devo_reset */ 7203446Smrj &agp_target_cb_ops, /* devo_cb_ops */ 7213446Smrj 0, /* devo_bus_ops */ 7223446Smrj 0, /* devo_power */ 7233446Smrj }; 7243446Smrj 7253446Smrj static struct modldrv modldrv = { 7263446Smrj &mod_driverops, 7273446Smrj "AGP target driver v%I%", 7283446Smrj &agp_target_ops, 7293446Smrj }; 7303446Smrj 7313446Smrj static struct modlinkage modlinkage = { 7323446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 7333446Smrj {&modldrv, NULL, NULL, NULL} 7343446Smrj }; 7353446Smrj 7363446Smrj int 7373446Smrj _init(void) 7383446Smrj { 7393446Smrj int ret; 7403446Smrj 7413446Smrj ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 7423446Smrj sizeof (agp_target_softstate_t), 1); 7433446Smrj 7443446Smrj if (ret) 7453446Smrj goto err1; 7463446Smrj 7473446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 7483446Smrj goto err2; 7493446Smrj } 7503446Smrj 7513446Smrj return (DDI_SUCCESS); 7523446Smrj err2: 7533446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 7543446Smrj err1: 7553446Smrj return (ret); 7563446Smrj } 7573446Smrj 7583446Smrj int 7593446Smrj _info(struct modinfo *modinfop) 7603446Smrj { 7613446Smrj return (mod_info(&modlinkage, modinfop)); 7623446Smrj } 7633446Smrj 7643446Smrj int 7653446Smrj _fini(void) 7663446Smrj { 7673446Smrj int ret; 7683446Smrj 7693446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 7703446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 7713446Smrj } 7723446Smrj return (ret); 7733446Smrj } 774