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
is_64bit_aper(agp_target_softstate_t * softstate)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
is_intel_br(agp_target_softstate_t * softstate)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
agp_target_cap_find(ddi_acc_handle_t pci_handle)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
agp_target_get_apbase(agp_target_softstate_t * softstate)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
agp_target_get_apsize(agp_target_softstate_t * softstate)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
agp_target_set_gartaddr(agp_target_softstate_t * softstate,uint32_t gartaddr)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
get_chip_gms(uint32_t devid)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
i8xx_biosmem_detect(agp_target_softstate_t * softstate)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*/
agptarget_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
intel_br_resume(agp_target_softstate_t * softstate)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
intel_br_suspend(agp_target_softstate_t * softstate)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
agp_target_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
agp_target_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
agp_target_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval)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
agp_target_open(dev_t * devp,int flag,int otyp,cred_t * cred)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
agp_target_close(dev_t dev,int flag,int otyp,cred_t * cred)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
_init(void)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
_info(struct modinfo * modinfop)9393446Smrj _info(struct modinfo *modinfop)
9403446Smrj {
9413446Smrj return (mod_info(&modlinkage, modinfop));
9423446Smrj }
9433446Smrj
9443446Smrj int
_fini(void)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