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 /* 28*11637SEdward.Shu@Sun.COM * Copyright 2010 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 #define I915_IFPADDR 0x60 5411260SMiao.Chen@Sun.COM #define I965_IFPADDR 0x70 5511260SMiao.Chen@Sun.COM 5611260SMiao.Chen@Sun.COM #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & \ 5711260SMiao.Chen@Sun.COM 0xFFFFFFFF00000000ULL) >> 32)) 5811260SMiao.Chen@Sun.COM #define LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 5911260SMiao.Chen@Sun.COM 603446Smrj typedef struct agp_target_softstate { 613446Smrj dev_info_t *tsoft_dip; 623446Smrj ddi_acc_handle_t tsoft_pcihdl; 633446Smrj uint32_t tsoft_devid; 643446Smrj /* The offset of the ACAPID register */ 653446Smrj off_t tsoft_acaptr; 663446Smrj kmutex_t tsoft_lock; 677130Sms148562 int tsoft_gms_off; /* GMS offset in config */ 687130Sms148562 uint32_t tsoft_gms; 693446Smrj }agp_target_softstate_t; 703446Smrj 715036Skz151634 /* 725036Skz151634 * To get the pre-allocated graphics mem size using Graphics Mode Select 735036Skz151634 * (GMS) value. 745036Skz151634 */ 755036Skz151634 typedef struct gms_mode { 765036Skz151634 uint32_t gm_devid; /* bridge vendor + device id */ 775036Skz151634 off_t gm_regoff; /* mode selection register offset */ 785036Skz151634 uint32_t gm_mask; /* GMS mask */ 795036Skz151634 uint32_t gm_num; /* number of modes in gm_vec */ 805036Skz151634 int *gm_vec; /* modes array */ 815036Skz151634 } gms_mode_t; 825036Skz151634 833446Smrj static void *agptarget_glob_soft_handle; 843446Smrj 853446Smrj #define GETSOFTC(instance) ((agp_target_softstate_t *) \ 863446Smrj ddi_get_soft_state(agptarget_glob_soft_handle, instance)); 873446Smrj 883446Smrj /* 893446Smrj * The AMD8151 bridge is the only supported 64 bit hardware 903446Smrj */ 913446Smrj static int 923446Smrj is_64bit_aper(agp_target_softstate_t *softstate) 933446Smrj { 943446Smrj return (softstate->tsoft_devid == AMD_BR_8151); 953446Smrj } 967130Sms148562 975131Sms148562 /* 985131Sms148562 * Check if it is an intel bridge 995131Sms148562 */ 1005131Sms148562 static int 1015131Sms148562 is_intel_br(agp_target_softstate_t *softstate) 1025131Sms148562 { 1035131Sms148562 return ((softstate->tsoft_devid & VENDOR_ID_MASK) == 1045131Sms148562 INTEL_VENDOR_ID); 1055131Sms148562 } 1063446Smrj 1073446Smrj /* 1083446Smrj * agp_target_cap_find() 1093446Smrj * 1103446Smrj * Description: 1113446Smrj * This function searches the linked capability list to find the offset 1123446Smrj * of the AGP capability register. When it was not found, return 0. 1133446Smrj * This works for standard AGP chipsets, but not for some Intel chipsets, 1143446Smrj * like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for 1153446Smrj * these chipsets even if AGP is supported. So the offset of acapid 1163446Smrj * should be set manually in thoses cases. 1173446Smrj * 1183446Smrj * Arguments: 1193446Smrj * pci_handle ddi acc handle of pci config 1203446Smrj * 1213446Smrj * Returns: 1223446Smrj * 0 No capability pointer register found 1233446Smrj * nexcap The AGP capability pointer register offset 1243446Smrj */ 1253446Smrj static off_t 1263446Smrj agp_target_cap_find(ddi_acc_handle_t pci_handle) 1273446Smrj { 1283446Smrj off_t nextcap = 0; 1293446Smrj uint32_t ncapid = 0; 1303446Smrj uint8_t value = 0; 1313446Smrj 1323446Smrj /* Check if this device supports the capability pointer */ 1333446Smrj value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT) 1343446Smrj & PCI_CONF_CAP_MASK); 1353446Smrj 1363446Smrj if (!value) 1373446Smrj return (0); 1383446Smrj /* Get the offset of the first capability pointer from CAPPTR */ 1393446Smrj nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR)); 1403446Smrj 1413446Smrj /* Check the AGP capability from the first capability pointer */ 1423446Smrj while (nextcap) { 1433446Smrj ncapid = pci_config_get32(pci_handle, nextcap); 1443446Smrj /* 1453446Smrj * AGP3.0 rev1.0 127 the capid was assigned by the PCI SIG, 1463446Smrj * 845 data sheet page 69 1473446Smrj */ 1483446Smrj if ((ncapid & PCI_CONF_CAPID_MASK) == 1493446Smrj AGP_CAP_ID) /* The AGP cap was found */ 1503446Smrj break; 1513446Smrj 1523446Smrj nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 1533446Smrj } 1543446Smrj 1553446Smrj return (nextcap); 1563446Smrj 1573446Smrj } 1583446Smrj 1593446Smrj /* 1603446Smrj * agp_target_get_aperbase() 1613446Smrj * 1623446Smrj * Description: 1633446Smrj * This function gets the AGP aperture base address from the AGP target 1643446Smrj * register, the AGP aperture base register was programmed by the BIOS. 1653446Smrj * 1663446Smrj * Arguments: 1673446Smrj * softstate driver soft state pointer 1683446Smrj * 1693446Smrj * Returns: 1703446Smrj * aper_base AGP aperture base address 1713446Smrj * 1723446Smrj * Notes: 1733446Smrj * If a 64bit bridge device is available, the AGP aperture base address 1743446Smrj * can be 64 bit. 1753446Smrj */ 1763446Smrj static uint64_t 1773446Smrj agp_target_get_apbase(agp_target_softstate_t *softstate) 1783446Smrj { 1793446Smrj uint64_t aper_base; 1803446Smrj 1815131Sms148562 if (is_intel_br(softstate)) { 1823446Smrj aper_base = pci_config_get32(softstate->tsoft_pcihdl, 1833446Smrj AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK; 1845131Sms148562 } else if (is_64bit_aper(softstate)) { 1853446Smrj aper_base = pci_config_get64(softstate->tsoft_pcihdl, 1863446Smrj AGP_CONF_APERBASE); 1873446Smrj /* 32-bit or 64-bit aperbase base pointer */ 1883446Smrj if ((aper_base & AGP_APER_TYPE_MASK) == 0) 1893446Smrj aper_base &= AGP_32_APERBASE_MASK; 1903446Smrj else 1913446Smrj aper_base &= AGP_64_APERBASE_MASK; 1923446Smrj } 1935131Sms148562 1943446Smrj return (aper_base); 1953446Smrj } 1963446Smrj 1973446Smrj /* 1983446Smrj * agp_target_get_apsize() 1993446Smrj * 2003446Smrj * Description: 2013446Smrj * This function gets the AGP aperture size by reading the AGP aperture 2023446Smrj * size register. 2033446Smrj * Arguments: 2043446Smrj * softstate driver soft state pointer 2053446Smrj * 2063446Smrj * Return: 2073446Smrj * size The AGP aperture size in megabytes 2083446Smrj * 0 an unexpected error 2093446Smrj */ 2103446Smrj static size_t 2113446Smrj agp_target_get_apsize(agp_target_softstate_t *softstate) 2123446Smrj { 2133446Smrj off_t cap; 2143446Smrj uint16_t value; 2153446Smrj size_t size, regsize; 2163446Smrj 2173446Smrj ASSERT(softstate->tsoft_acaptr); 2183446Smrj cap = softstate->tsoft_acaptr; 2193446Smrj 2205131Sms148562 if (is_intel_br(softstate)) { 2213446Smrj /* extend this value to 16 bit for later tests */ 2223446Smrj value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl, 2233446Smrj cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK; 2245131Sms148562 } else if (is_64bit_aper(softstate)) { 2253446Smrj value = pci_config_get16(softstate->tsoft_pcihdl, 2263446Smrj cap + AGP_CONF_APERSIZE); 2273446Smrj } 2283446Smrj 2293446Smrj if (value & AGP_APER_128M_MASK) { 2303446Smrj switch (value & AGP_APER_128M_MASK) { 2313446Smrj case AGP_APER_4M: 2323446Smrj size = 4; /* 4M */ 2333446Smrj break; 2343446Smrj case AGP_APER_8M: 2353446Smrj size = 8; /* 8M */ 2363446Smrj break; 2373446Smrj case AGP_APER_16M: 2383446Smrj size = 16; /* 16M */ 2393446Smrj break; 2403446Smrj case AGP_APER_32M: 2413446Smrj size = 32; /* 32M */ 2423446Smrj break; 2433446Smrj case AGP_APER_64M: 2443446Smrj size = 64; /* 64M */ 2453446Smrj break; 2463446Smrj case AGP_APER_128M: 2473446Smrj size = 128; /* 128M */ 2483446Smrj break; 2493446Smrj default: 2503446Smrj size = 0; /* not true */ 2513446Smrj } 2523446Smrj } else { 2533446Smrj switch (value & AGP_APER_4G_MASK) { 2543446Smrj case AGP_APER_256M: 2553446Smrj size = 256; /* 256 M */ 2563446Smrj break; 2573446Smrj case AGP_APER_512M: 2583446Smrj size = 512; /* 512 M */ 2593446Smrj break; 2603446Smrj case AGP_APER_1024M: 2613446Smrj size = 1024; /* 1024 M */ 2623446Smrj break; 2633446Smrj case AGP_APER_2048M: 2643446Smrj size = 2048; /* 2048 M */ 2653446Smrj break; 2663446Smrj case AGP_APER_4G: 2673446Smrj size = 4096; /* 4096 M */ 2683446Smrj break; 2693446Smrj default: 2703446Smrj size = 0; /* not true */ 2713446Smrj } 2723446Smrj } 2733446Smrj /* 2743446Smrj * In some cases, there is no APSIZE register, so the size value 2753446Smrj * of 256M could be wrong. Check the value by reading the size of 2763446Smrj * the first register which was set in the PCI configuration space. 2773446Smrj */ 2783446Smrj if (size == 256) { 2793446Smrj if (ddi_dev_regsize(softstate->tsoft_dip, 2803446Smrj AGP_TARGET_BAR1, (off_t *)®size) == DDI_FAILURE) 2813446Smrj return (0); 2823446Smrj 2833446Smrj if (MB2BYTES(size) != regsize) { 2843446Smrj TARGETDB_PRINT2((CE_WARN, 2853446Smrj "APSIZE 256M doesn't match regsize %lx", 2863446Smrj regsize)); 2873446Smrj TARGETDB_PRINT2((CE_WARN, "Use regsize instead")); 2883446Smrj size = BYTES2MB(regsize); 2893446Smrj } 2903446Smrj } 2913446Smrj 2923446Smrj return (size); 2933446Smrj } 2943446Smrj 2953446Smrj static void 2963446Smrj agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr) 2973446Smrj { 2983446Smrj ASSERT(softstate->tsoft_acaptr); 2993446Smrj 3003446Smrj /* Disable the GTLB for Intel chipsets */ 3013446Smrj pci_config_put16(softstate->tsoft_pcihdl, 3023446Smrj softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000); 3033446Smrj 3043446Smrj pci_config_put32(softstate->tsoft_pcihdl, 3053446Smrj softstate->tsoft_acaptr + AGP_CONF_ATTBASE, 3063446Smrj gartaddr & AGP_ATTBASE_MASK); 3073446Smrj } 3083446Smrj 3095036Skz151634 /* 3105036Skz151634 * Pre-allocated graphics memory for every type of Intel north bridge, mem size 3115036Skz151634 * are specified in kbytes. 3125036Skz151634 */ 3135036Skz151634 #define GMS_MB(n) ((n) * 1024) 3145036Skz151634 #define GMS_SHIFT 4 3155036Skz151634 #define GMS_SIZE(a) (sizeof (a) / sizeof (int)) 3165036Skz151634 3175036Skz151634 /* 3185036Skz151634 * Since value zero always means "No memory pre-allocated", value of (GMS - 1) 3195036Skz151634 * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb) 3205036Skz151634 * that GMS value 0x1 corresponding to. 3215036Skz151634 * 3225036Skz151634 * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics 3235036Skz151634 * memory, unless some special BIOS settings exist. 3245036Skz151634 */ 3255036Skz151634 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)}; 3265036Skz151634 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)}; 3275036Skz151634 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3285036Skz151634 GMS_MB(32)}; 3295036Skz151634 /* There is no modes for 16M in datasheet, but some BIOS add it. */ 3305036Skz151634 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)}; 3315036Skz151634 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)}; 3325036Skz151634 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3335036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64)}; 3345036Skz151634 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 3355036Skz151634 GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)}; 3367662SMiao.Chen@Sun.COM static int gms_G4X[13] = {0, 0, 0, 0, 3377662SMiao.Chen@Sun.COM GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256), 3387662SMiao.Chen@Sun.COM GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)}; 3395036Skz151634 3405036Skz151634 static gms_mode_t gms_modes[] = { 3415036Skz151634 {INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK, 3425036Skz151634 GMS_SIZE(gms_810), gms_810}, 3435036Skz151634 {INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK, 3445036Skz151634 GMS_SIZE(gms_810), gms_810}, 3455036Skz151634 {INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK, 3465036Skz151634 GMS_SIZE(gms_810), gms_810}, 3475036Skz151634 {INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3485036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 3495036Skz151634 {INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3505036Skz151634 GMS_SIZE(gms_830_845), gms_830_845}, 3515036Skz151634 {INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3525036Skz151634 GMS_SIZE(gms_855GM), gms_855GM}, 3535036Skz151634 {INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3545036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 3555036Skz151634 {INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3565036Skz151634 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 3575036Skz151634 {INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3585036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3595036Skz151634 {INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3605036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3615036Skz151634 {INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3625036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3638020SMiao.Chen@Sun.COM {INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3648020SMiao.Chen@Sun.COM GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3655036Skz151634 {INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3665036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3675036Skz151634 {INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3685036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3695036Skz151634 {INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3705036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3715036Skz151634 {INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3725036Skz151634 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 3735036Skz151634 {INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3745036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 3755036Skz151634 {INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3765036Skz151634 GMS_SIZE(gms_965GM), gms_965GM}, 3775036Skz151634 {INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK, 3785036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 3795036Skz151634 {INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 3805036Skz151634 GMS_SIZE(gms_X33), gms_X33}, 3815036Skz151634 {INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 3826778Smc196098 GMS_SIZE(gms_X33), gms_X33}, 3836778Smc196098 {INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3847662SMiao.Chen@Sun.COM GMS_SIZE(gms_965GM), gms_965GM}, 3857662SMiao.Chen@Sun.COM {INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3867662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 3877662SMiao.Chen@Sun.COM {INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3887662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 3897662SMiao.Chen@Sun.COM {INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 3908832SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 3918832SMiao.Chen@Sun.COM {INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 39211260SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 39311359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_D, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 39411359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 39511359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_M, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 39611359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 39711359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_MA, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 39811359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 39911359SMiao.Chen@Sun.COM {INTEL_BR_IGDNG_MC2, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 40011359SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X}, 40111260SMiao.Chen@Sun.COM {INTEL_BR_B43, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 4027662SMiao.Chen@Sun.COM GMS_SIZE(gms_G4X), gms_G4X} 4035036Skz151634 }; 4047130Sms148562 static int 4057130Sms148562 get_chip_gms(uint32_t devid) 4067130Sms148562 { 4077130Sms148562 int num_modes; 4087130Sms148562 int i; 4097130Sms148562 4107130Sms148562 num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); 4117130Sms148562 4127130Sms148562 for (i = 0; i < num_modes; i++) { 4137130Sms148562 if (gms_modes[i].gm_devid == devid) 4147130Sms148562 break; 4157130Sms148562 } 4167130Sms148562 4177130Sms148562 return ((i == num_modes) ? -1 : i); 4187130Sms148562 } 4195036Skz151634 4205036Skz151634 /* Returns the size (kbytes) of pre-allocated graphics memory */ 4213446Smrj static size_t 4223446Smrj i8xx_biosmem_detect(agp_target_softstate_t *softstate) 4233446Smrj { 4243446Smrj uint8_t memval; 4253446Smrj size_t kbytes; 4267130Sms148562 int gms_off; 4273446Smrj 4285036Skz151634 kbytes = 0; 4297130Sms148562 gms_off = softstate->tsoft_gms_off; 4307130Sms148562 4315036Skz151634 /* fetch the GMS value from DRAM controller */ 4325036Skz151634 memval = pci_config_get8(softstate->tsoft_pcihdl, 4337130Sms148562 gms_modes[gms_off].gm_regoff); 4345036Skz151634 TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval)); 4357130Sms148562 memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT; 4365036Skz151634 /* assuming zero byte for 0 or "reserved" GMS values */ 4377130Sms148562 if (memval == 0 || memval > gms_modes[gms_off].gm_num) { 4385036Skz151634 TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: " 4395036Skz151634 "devid = %x, GMS = %x. assuming zero byte of " 4407130Sms148562 "pre-allocated memory", 4417130Sms148562 gms_modes[gms_off].gm_devid, memval)); 4425036Skz151634 goto done; 4435036Skz151634 } 4445036Skz151634 memval--; /* use (GMS_value - 1) as index */ 4457130Sms148562 kbytes = (gms_modes[gms_off].gm_vec)[memval]; 4463446Smrj 4475036Skz151634 done: 4484478Skz151634 TARGETDB_PRINT2((CE_NOTE, 4494478Skz151634 "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected", 4504478Skz151634 kbytes)); 4513446Smrj return (kbytes); 4523446Smrj } 4533446Smrj 4543446Smrj /*ARGSUSED*/ 4553446Smrj static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 4563446Smrj void *arg, void **resultp) 4573446Smrj { 4583446Smrj agp_target_softstate_t *st; 4593446Smrj int instance, rval = DDI_FAILURE; 4603446Smrj dev_t dev; 4613446Smrj 4623446Smrj switch (cmd) { 4633446Smrj case DDI_INFO_DEVT2DEVINFO: 4643446Smrj dev = (dev_t)arg; 4653446Smrj instance = DEV2INST(dev); 4663446Smrj st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 4673446Smrj if (st != NULL) { 4683446Smrj mutex_enter(&st->tsoft_lock); 4693446Smrj *resultp = st->tsoft_dip; 4703446Smrj mutex_exit(&st->tsoft_lock); 4713446Smrj rval = DDI_SUCCESS; 4723446Smrj } else 4733446Smrj *resultp = NULL; 4743446Smrj 4753446Smrj break; 4763446Smrj case DDI_INFO_DEVT2INSTANCE: 4773446Smrj dev = (dev_t)arg; 4783446Smrj instance = DEV2INST(dev); 4793446Smrj *resultp = (void *)(uintptr_t)instance; 4803446Smrj rval = DDI_SUCCESS; 4813446Smrj default: 4823446Smrj break; 4833446Smrj } 4843446Smrj 4853446Smrj return (rval); 4863446Smrj } 4873446Smrj 4883446Smrj static int 4897130Sms148562 intel_br_resume(agp_target_softstate_t *softstate) 4907130Sms148562 { 4917130Sms148562 int gms_off; 4927130Sms148562 4937130Sms148562 gms_off = softstate->tsoft_gms_off; 4947130Sms148562 4957130Sms148562 /* 4967130Sms148562 * We recover the gmch graphics control register here 4977130Sms148562 */ 4987130Sms148562 pci_config_put16(softstate->tsoft_pcihdl, 4997130Sms148562 gms_modes[gms_off].gm_regoff, softstate->tsoft_gms); 5007130Sms148562 5017130Sms148562 return (DDI_SUCCESS); 5027130Sms148562 } 5037130Sms148562 static int 5047130Sms148562 intel_br_suspend(agp_target_softstate_t *softstate) 5057130Sms148562 { 5067130Sms148562 int gms_off; 5077130Sms148562 5087130Sms148562 gms_off = softstate->tsoft_gms_off; 5097130Sms148562 softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl, 5107130Sms148562 gms_modes[gms_off].gm_regoff); 5117130Sms148562 5127130Sms148562 return (DDI_SUCCESS); 5137130Sms148562 } 5147130Sms148562 5157130Sms148562 static int 5163446Smrj agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5173446Smrj { 5183446Smrj agp_target_softstate_t *softstate; 5193446Smrj int instance; 5203446Smrj int status; 5213446Smrj 5223446Smrj instance = ddi_get_instance(dip); 5233446Smrj 5247130Sms148562 switch (cmd) { 5257130Sms148562 case DDI_ATTACH: 5267130Sms148562 break; 5277130Sms148562 case DDI_RESUME: 5287130Sms148562 softstate = 5297130Sms148562 ddi_get_soft_state(agptarget_glob_soft_handle, instance); 5307130Sms148562 return (intel_br_resume(softstate)); 5317130Sms148562 default: 5327130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 5337130Sms148562 "only attach and resume ops are supported")); 5343446Smrj return (DDI_FAILURE); 5357130Sms148562 } 5367130Sms148562 5377130Sms148562 if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, 5387130Sms148562 instance) != DDI_SUCCESS) { 5397130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 5407130Sms148562 "soft state zalloc failed")); 5417130Sms148562 return (DDI_FAILURE); 5427130Sms148562 } 5433446Smrj 5443446Smrj softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 5453446Smrj mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 5463446Smrj softstate->tsoft_dip = dip; 5473446Smrj status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 5483446Smrj if (status != DDI_SUCCESS) { 5497130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 5507130Sms148562 "pci config setup failed")); 5517130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 5527130Sms148562 instance); 5533446Smrj return (DDI_FAILURE); 5543446Smrj } 5553446Smrj 5563446Smrj softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 5573446Smrj PCI_CONF_VENID); 5587130Sms148562 softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid); 5597130Sms148562 if (softstate->tsoft_gms_off < 0) { 5607130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 5617130Sms148562 "read gms offset failed")); 5627130Sms148562 pci_config_teardown(&softstate->tsoft_pcihdl); 5637130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 5647130Sms148562 instance); 5657130Sms148562 return (DDI_FAILURE); 5667130Sms148562 } 5673446Smrj softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 5683446Smrj if (softstate->tsoft_acaptr == 0) { 5693446Smrj /* Make a correction for some Intel chipsets */ 5705131Sms148562 if (is_intel_br(softstate)) 5713446Smrj softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 5727130Sms148562 else { 5737130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 5747130Sms148562 "Not a supposed corretion")); 5757130Sms148562 pci_config_teardown(&softstate->tsoft_pcihdl); 5767130Sms148562 ddi_soft_state_free(agptarget_glob_soft_handle, 5777130Sms148562 instance); 5783446Smrj return (DDI_FAILURE); 5797130Sms148562 } 5803446Smrj } 5813446Smrj 5823446Smrj status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 5833446Smrj INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 5843446Smrj 5853446Smrj if (status != DDI_SUCCESS) { 5867130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 5877130Sms148562 "Create minor node failed")); 5883446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 5893446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 5903446Smrj return (DDI_FAILURE); 5913446Smrj } 5923446Smrj 5933446Smrj return (DDI_SUCCESS); 5943446Smrj } 5953446Smrj 5963446Smrj /*ARGSUSED*/ 5973446Smrj static int 5983446Smrj agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5993446Smrj { 6003446Smrj int instance; 6013446Smrj agp_target_softstate_t *softstate; 6023446Smrj 6037130Sms148562 instance = ddi_get_instance(dip); 6047130Sms148562 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 6053446Smrj 6067130Sms148562 if (cmd == DDI_SUSPEND) { 6077130Sms148562 /* get GMS modes list entry */ 6087130Sms148562 return (intel_br_suspend(softstate)); 6097130Sms148562 } 6103446Smrj 6117130Sms148562 if (cmd != DDI_DETACH) { 6127130Sms148562 TARGETDB_PRINT2((CE_WARN, "agp_target_detach:" 6137130Sms148562 "only detach and suspend ops are supported")); 6147130Sms148562 return (DDI_FAILURE); 6157130Sms148562 } 6163446Smrj 6173446Smrj ddi_remove_minor_node(dip, AGPTARGET_NAME); 6183446Smrj pci_config_teardown(&softstate->tsoft_pcihdl); 6193446Smrj mutex_destroy(&softstate->tsoft_lock); 6203446Smrj ddi_soft_state_free(agptarget_glob_soft_handle, instance); 6213446Smrj return (DDI_SUCCESS); 6223446Smrj } 6233446Smrj 6243446Smrj /*ARGSUSED*/ 6253446Smrj static int 6263446Smrj agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 6273446Smrj cred_t *cred, int *rval) 6283446Smrj { 6293446Smrj int instance = DEV2INST(dev); 6303446Smrj agp_target_softstate_t *st; 6313446Smrj static char kernel_only[] = 6323446Smrj "amd64_gart_ioctl: is a kernel only ioctl"; 6333446Smrj 6343446Smrj if (!(mode & FKIOCTL)) { 6353446Smrj TARGETDB_PRINT2((CE_CONT, kernel_only)); 6363446Smrj return (ENXIO); 6373446Smrj } 6383446Smrj st = GETSOFTC(instance); 6393446Smrj 6403446Smrj if (st == NULL) 6413446Smrj return (ENXIO); 6423446Smrj 6433446Smrj mutex_enter(&st->tsoft_lock); 6443446Smrj 6453446Smrj switch (cmd) { 6463446Smrj case CHIP_DETECT: 6473446Smrj { 6485131Sms148562 int type = 0; 6495131Sms148562 6505131Sms148562 if (is_intel_br(st)) 6513446Smrj type = CHIP_IS_INTEL; 6525131Sms148562 else if (is_64bit_aper(st)) 6533446Smrj type = CHIP_IS_AMD; 6545131Sms148562 else { 6553446Smrj type = 0; 6565131Sms148562 TARGETDB_PRINT2((CE_WARN, "Unknown bridge!")); 6573446Smrj } 6585131Sms148562 6593446Smrj if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 6603446Smrj mutex_exit(&st->tsoft_lock); 6613446Smrj return (EFAULT); 6623446Smrj } 6633446Smrj 6643446Smrj break; 6653446Smrj } 6663446Smrj case I8XX_GET_PREALLOC_SIZE: 6673446Smrj { 6683446Smrj size_t prealloc_size; 6693446Smrj 6705131Sms148562 if (!is_intel_br(st)) { 6713446Smrj mutex_exit(&st->tsoft_lock); 6723446Smrj return (EINVAL); 6733446Smrj } 6743446Smrj 6753446Smrj prealloc_size = i8xx_biosmem_detect(st); 6763446Smrj if (ddi_copyout(&prealloc_size, (void *)data, 6773446Smrj sizeof (size_t), mode)) { 6783446Smrj mutex_exit(&st->tsoft_lock); 6793446Smrj return (EFAULT); 6803446Smrj } 6813446Smrj 6823446Smrj break; 6833446Smrj } 6843446Smrj case AGP_TARGET_GETINFO: 6853446Smrj { 6863446Smrj i_agp_info_t info; 6873446Smrj uint32_t value; 6883446Smrj off_t cap; 6893446Smrj 6903446Smrj ASSERT(st->tsoft_acaptr); 6913446Smrj 6923446Smrj cap = st->tsoft_acaptr; 6933446Smrj value = pci_config_get32(st->tsoft_pcihdl, cap); 6943446Smrj info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 6953446Smrj info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 6963446Smrj info.iagp_devid = st->tsoft_devid; 6973446Smrj info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 6984303Skz151634 cap + AGP_CONF_STATUS); 6993446Smrj info.iagp_aperbase = agp_target_get_apbase(st); 7003446Smrj info.iagp_apersize = agp_target_get_apsize(st); 7013446Smrj 7023446Smrj if (ddi_copyout(&info, (void *)data, 7033446Smrj sizeof (i_agp_info_t), mode)) { 7043446Smrj mutex_exit(&st->tsoft_lock); 7053446Smrj return (EFAULT); 7063446Smrj } 7073446Smrj break; 7083446Smrj 7093446Smrj } 7103446Smrj /* 7113446Smrj * This ioctl is only for Intel AGP chipsets. 7123446Smrj * It is not necessary for the AMD8151 AGP bridge, because 7133446Smrj * this register in the AMD8151 does not control any hardware. 7143446Smrj * It is only provided for compatibility with an Intel AGP bridge. 7153446Smrj * Please refer to the <<AMD8151 data sheet>> page 24, 7163446Smrj * AGP device GART pointer. 7173446Smrj */ 7183446Smrj case AGP_TARGET_SET_GATTADDR: 7193446Smrj { 7203446Smrj uint32_t gartaddr; 7213446Smrj 7223446Smrj if (ddi_copyin((void *)data, &gartaddr, 7233446Smrj sizeof (uint32_t), mode)) { 7243446Smrj mutex_exit(&st->tsoft_lock); 7253446Smrj return (EFAULT); 7263446Smrj } 7273446Smrj 7283446Smrj agp_target_set_gartaddr(st, gartaddr); 7293446Smrj break; 7303446Smrj } 7313446Smrj case AGP_TARGET_SETCMD: 7323446Smrj { 7333446Smrj uint32_t command; 7343446Smrj 7353446Smrj if (ddi_copyin((void *)data, &command, 7363446Smrj sizeof (uint32_t), mode)) { 7373446Smrj mutex_exit(&st->tsoft_lock); 7383446Smrj return (EFAULT); 7393446Smrj } 7403446Smrj 7413446Smrj ASSERT(st->tsoft_acaptr); 7423446Smrj 7433446Smrj pci_config_put32(st->tsoft_pcihdl, 7443446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 7453446Smrj command); 7463446Smrj break; 7473446Smrj 7483446Smrj } 7493446Smrj case AGP_TARGET_FLUSH_GTLB: 7503446Smrj { 7513446Smrj uint16_t value; 7523446Smrj 7533446Smrj ASSERT(st->tsoft_acaptr); 7543446Smrj 7553446Smrj value = pci_config_get16(st->tsoft_pcihdl, 7563446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL); 7573446Smrj value &= ~AGPCTRL_GTLBEN; 7583446Smrj pci_config_put16(st->tsoft_pcihdl, 7593446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 7603446Smrj value |= AGPCTRL_GTLBEN; 7613446Smrj pci_config_put16(st->tsoft_pcihdl, 7623446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, value); 7633446Smrj 7643446Smrj break; 7653446Smrj } 7663446Smrj case AGP_TARGET_CONFIGURE: 7673446Smrj { 7683446Smrj uint8_t value; 7693446Smrj 7703446Smrj ASSERT(st->tsoft_acaptr); 7713446Smrj 7725131Sms148562 /* 7735131Sms148562 * In Intel agp bridges, agp misc register offset 7745131Sms148562 * is indexed from 0 instead of capability register. 7755131Sms148562 * AMD agp bridges have no such misc register 7765131Sms148562 * to control the aperture access, and they have 7775131Sms148562 * similar regsiters in CPU gart devices instead. 7785131Sms148562 */ 7795131Sms148562 7805131Sms148562 if (is_intel_br(st)) { 7815131Sms148562 value = pci_config_get8(st->tsoft_pcihdl, 7825131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC); 7835131Sms148562 value |= AGP_MISC_APEN; 7845131Sms148562 pci_config_put8(st->tsoft_pcihdl, 7855131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC, value); 7865131Sms148562 } 7873446Smrj break; 7883446Smrj 7893446Smrj } 7903446Smrj case AGP_TARGET_UNCONFIG: 7913446Smrj { 7923446Smrj uint32_t value1; 7933446Smrj uint8_t value2; 7943446Smrj 7953446Smrj ASSERT(st->tsoft_acaptr); 7963446Smrj 7973446Smrj pci_config_put16(st->tsoft_pcihdl, 7983446Smrj st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 7993446Smrj 8005131Sms148562 if (is_intel_br(st)) { 8015131Sms148562 value2 = pci_config_get8(st->tsoft_pcihdl, 8025131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC); 8035131Sms148562 value2 &= ~AGP_MISC_APEN; 8045131Sms148562 pci_config_put8(st->tsoft_pcihdl, 8055131Sms148562 st->tsoft_acaptr + AGP_CONF_MISC, value2); 8065131Sms148562 } 8073446Smrj 8083446Smrj value1 = pci_config_get32(st->tsoft_pcihdl, 8093446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND); 8103446Smrj value1 &= ~AGPCMD_AGPEN; 8113446Smrj pci_config_put32(st->tsoft_pcihdl, 8123446Smrj st->tsoft_acaptr + AGP_CONF_COMMAND, 8133446Smrj value1); 8143446Smrj 8153446Smrj pci_config_put32(st->tsoft_pcihdl, 8163446Smrj st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 8173446Smrj 8183446Smrj break; 8193446Smrj } 8203446Smrj 82111260SMiao.Chen@Sun.COM case INTEL_CHIPSET_FLUSH_SETUP: 822*11637SEdward.Shu@Sun.COM case INTEL_CHIPSET_FLUSH: 823*11637SEdward.Shu@Sun.COM case INTEL_CHIPSET_FLUSH_FREE: 82411260SMiao.Chen@Sun.COM break; 8253446Smrj default: 8263446Smrj mutex_exit(&st->tsoft_lock); 8273446Smrj return (ENXIO); 8283446Smrj } /* end switch */ 8293446Smrj 8303446Smrj mutex_exit(&st->tsoft_lock); 8313446Smrj 8323446Smrj return (0); 8333446Smrj } 8343446Smrj 8353446Smrj /*ARGSUSED*/ 8363446Smrj static int 8373446Smrj agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 8383446Smrj { 8393446Smrj int instance = DEV2INST(*devp); 8403446Smrj agp_target_softstate_t *st; 8413446Smrj 8423446Smrj if (!(flag & FKLYR)) 8433446Smrj return (ENXIO); 8443446Smrj 8453446Smrj st = GETSOFTC(instance); 8463446Smrj 8473446Smrj if (st == NULL) 8483446Smrj return (ENXIO); 8493446Smrj 8503446Smrj return (0); 8513446Smrj } 8523446Smrj 8533446Smrj /*ARGSUSED*/ 8543446Smrj static int 8553446Smrj agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 8563446Smrj { 8573446Smrj int instance = DEV2INST(dev); 8583446Smrj agp_target_softstate_t *st; 8593446Smrj 8603446Smrj st = GETSOFTC(instance); 8613446Smrj 8623446Smrj if (st == NULL) 8633446Smrj return (ENXIO); 8643446Smrj 8653446Smrj return (0); 8663446Smrj } 8673446Smrj 8683446Smrj static struct cb_ops agp_target_cb_ops = { 8693446Smrj agp_target_open, /* cb_open */ 8703446Smrj agp_target_close, /* cb_close */ 8713446Smrj nodev, /* cb_strategy */ 8723446Smrj nodev, /* cb_print */ 8733446Smrj nodev, /* cb_dump */ 8743446Smrj nodev, /* cb_read() */ 8753446Smrj nodev, /* cb_write() */ 8763446Smrj agp_target_ioctl, /* cb_ioctl */ 8773446Smrj nodev, /* cb_devmap */ 8783446Smrj nodev, /* cb_mmap */ 8793446Smrj nodev, /* cb_segmap */ 8803446Smrj nochpoll, /* cb_chpoll */ 8813446Smrj ddi_prop_op, /* cb_prop_op */ 8823446Smrj 0, /* cb_stream */ 8833446Smrj D_NEW | D_MP, /* cb_flag */ 8843446Smrj CB_REV, /* cb_ops version? */ 8853446Smrj nodev, /* cb_aread() */ 8863446Smrj nodev, /* cb_awrite() */ 8873446Smrj }; 8883446Smrj 8893446Smrj /* device operations */ 8903446Smrj static struct dev_ops agp_target_ops = { 8913446Smrj DEVO_REV, /* devo_rev */ 8923446Smrj 0, /* devo_refcnt */ 8933446Smrj agptarget_getinfo, /* devo_getinfo */ 8943446Smrj nulldev, /* devo_identify */ 8953446Smrj nulldev, /* devo_probe */ 8963446Smrj agp_target_attach, /* devo_attach */ 8973446Smrj agp_target_detach, /* devo_detach */ 8983446Smrj nodev, /* devo_reset */ 8993446Smrj &agp_target_cb_ops, /* devo_cb_ops */ 9003446Smrj 0, /* devo_bus_ops */ 9013446Smrj 0, /* devo_power */ 9028328SMiao.Chen@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */ 9033446Smrj }; 9043446Smrj 9053446Smrj static struct modldrv modldrv = { 9063446Smrj &mod_driverops, 9077130Sms148562 "AGP target driver", 9083446Smrj &agp_target_ops, 9093446Smrj }; 9103446Smrj 9113446Smrj static struct modlinkage modlinkage = { 9123446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 9133446Smrj {&modldrv, NULL, NULL, NULL} 9143446Smrj }; 9153446Smrj 9163446Smrj int 9173446Smrj _init(void) 9183446Smrj { 9193446Smrj int ret; 9203446Smrj 9213446Smrj ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 9223446Smrj sizeof (agp_target_softstate_t), 1); 9233446Smrj 9243446Smrj if (ret) 9253446Smrj goto err1; 9263446Smrj 9273446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 9283446Smrj goto err2; 9293446Smrj } 9303446Smrj 9313446Smrj return (DDI_SUCCESS); 9323446Smrj err2: 9333446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 9343446Smrj err1: 9353446Smrj return (ret); 9363446Smrj } 9373446Smrj 9383446Smrj int 9393446Smrj _info(struct modinfo *modinfop) 9403446Smrj { 9413446Smrj return (mod_info(&modlinkage, modinfop)); 9423446Smrj } 9433446Smrj 9443446Smrj int 9453446Smrj _fini(void) 9463446Smrj { 9473446Smrj int ret; 9483446Smrj 9493446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 9503446Smrj ddi_soft_state_fini(&agptarget_glob_soft_handle); 9513446Smrj } 9523446Smrj return (ret); 9533446Smrj } 954