13446Smrj /* 27542SRichard.Bean@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 33446Smrj * Use is subject to license terms. 43446Smrj */ 53446Smrj 63446Smrj #include <sys/conf.h> 73446Smrj #include <sys/ddi.h> 83446Smrj #include <sys/sunddi.h> 93446Smrj #include <sys/modctl.h> 103446Smrj #include <sys/stat.h> 113446Smrj #include <sys/sunldi.h> 123446Smrj #include <sys/file.h> 133446Smrj #include <sys/agpgart.h> 143446Smrj #include <sys/agp/agpdefs.h> 153446Smrj #include <sys/agp/agpamd64gart_io.h> 163446Smrj 173446Smrj #define MAX_GART_INSTS 8 183446Smrj #define GETSOFTC(instance) ((amd64_gart_softstate_t *) \ 193446Smrj ddi_get_soft_state(amd64_gart_glob_soft_handle, (instance))); 203446Smrj #define DEV2INST(dev) (getminor(dev)) 213446Smrj #define INST2NODENUM(inst) (inst) 223446Smrj 233446Smrj int amd64_debug_var = 0; 243446Smrj #define AMD64DB_PRINT1(fmt) if (amd64_debug_var == 1) cmn_err fmt 253446Smrj #define AMD64DB_PRINT2(fmt) if (amd64_debug_var >= 1) cmn_err fmt 263446Smrj 273446Smrj typedef struct amd64_gart_softstate { 283446Smrj dev_info_t *gsoft_dip; 293446Smrj ddi_acc_handle_t gsoft_pcihdl; 303446Smrj kmutex_t gsoft_lock; 313446Smrj }amd64_gart_softstate_t; 323446Smrj 333446Smrj static void *amd64_gart_glob_soft_handle; 343446Smrj 353446Smrj static uint64_t 363446Smrj amd64_get_aperbase(amd64_gart_softstate_t *sc) 373446Smrj { 383446Smrj uint32_t value; 393446Smrj uint64_t aper_base; 403446Smrj 413446Smrj /* amd64 aperture base support 40 bits and 32M aligned */ 423446Smrj value = pci_config_get32(sc->gsoft_pcihdl, 433446Smrj AMD64_APERTURE_BASE) & AMD64_APERBASE_MASK; 443446Smrj aper_base = (uint64_t)value << AMD64_APERBASE_SHIFT; 453446Smrj return (aper_base); 463446Smrj } 473446Smrj 483446Smrj static size_t 493446Smrj amd64_get_apersize(amd64_gart_softstate_t *sc) 503446Smrj { 513446Smrj uint32_t value; 523446Smrj size_t size; 533446Smrj 543446Smrj value = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL); 553446Smrj 563446Smrj value = (value & AMD64_APERSIZE_MASK) >> 1; 573446Smrj 583446Smrj /* aper size = 2^value x 32 */ 593446Smrj switch (value) { 603446Smrj case 0x0: 613446Smrj size = 32; 623446Smrj break; 633446Smrj case 0x1: 643446Smrj size = 64; 653446Smrj break; 663446Smrj case 0x2: 673446Smrj size = 128; 683446Smrj break; 693446Smrj case 0x3: 703446Smrj size = 256; 713446Smrj break; 723446Smrj case 0x4: 733446Smrj size = 512; 743446Smrj break; 753446Smrj case 0x5: 763446Smrj size = 1024; 773446Smrj break; 783446Smrj case 0x6: 793446Smrj size = 2048; 803446Smrj break; 813446Smrj default: /* reserved */ 823446Smrj size = 0; 833446Smrj }; 843446Smrj 853446Smrj return (size); 863446Smrj } 873446Smrj 883446Smrj static void 893446Smrj amd64_invalidate_gtlb(amd64_gart_softstate_t *sc) 903446Smrj { 913446Smrj uint32_t value; 923446Smrj 933446Smrj value = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL); 943446Smrj value |= AMD64_INVALID_CACHE; 953446Smrj 963446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL, value); 973446Smrj } 983446Smrj 993446Smrj static void 1003446Smrj amd64_enable_gart(amd64_gart_softstate_t *sc, int enable) 1013446Smrj { 1023446Smrj uint32_t aper_ctl; 1033446Smrj uint32_t aper_base; 1043446Smrj uint32_t gart_ctl; 1053446Smrj uint32_t gart_base; 1063446Smrj 1073446Smrj aper_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL); 1083446Smrj AMD64DB_PRINT1((CE_NOTE, "before: aper_ctl = %x", aper_ctl)); 1093446Smrj aper_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_BASE); 1103446Smrj gart_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL); 1113446Smrj gart_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_BASE); 1123446Smrj #ifdef lint 1133446Smrj aper_base = aper_base; 1143446Smrj gart_ctl = gart_ctl; 1153446Smrj gart_base = gart_base; 1163446Smrj #endif /* lint */ 1173446Smrj AMD64DB_PRINT1((CE_NOTE, "before: aper_base = %x", aper_base)); 1183446Smrj AMD64DB_PRINT1((CE_NOTE, "before: gart_ctl = %x", gart_ctl)); 1193446Smrj AMD64DB_PRINT1((CE_NOTE, "before: gart_base = %x", gart_base)); 1203446Smrj if (enable) { 1213446Smrj aper_ctl |= AMD64_GARTEN; 1223446Smrj aper_ctl &= ~(AMD64_DISGARTCPU | AMD64_DISGARTIO); 1233446Smrj } else 1243446Smrj aper_ctl &= (~AMD64_GARTEN); 1253446Smrj 1263446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL, aper_ctl); 1273446Smrj } 1283446Smrj 1293446Smrj /*ARGSUSED*/ 1303446Smrj static int 1313446Smrj amd64_gart_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 1323446Smrj void *arg, void **resultp) 1333446Smrj { 1343446Smrj amd64_gart_softstate_t *st; 1353446Smrj int instance, rval = DDI_FAILURE; 1363446Smrj dev_t dev; 1373446Smrj 1383446Smrj switch (cmd) { 1393446Smrj case DDI_INFO_DEVT2DEVINFO: 1403446Smrj dev = (dev_t)arg; 1413446Smrj instance = DEV2INST(dev); 1423446Smrj st = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 1433446Smrj if (st != NULL) { 1443446Smrj mutex_enter(&st->gsoft_lock); 1453446Smrj *resultp = st->gsoft_dip; 1463446Smrj mutex_exit(&st->gsoft_lock); 1473446Smrj rval = DDI_SUCCESS; 1483446Smrj } else { 1493446Smrj *resultp = NULL; 1503446Smrj } 1513446Smrj 1523446Smrj break; 1533446Smrj case DDI_INFO_DEVT2INSTANCE: 1543446Smrj dev = (dev_t)arg; 1553446Smrj instance = DEV2INST(dev); 1563446Smrj *resultp = (void *)(uintptr_t)instance; 1573446Smrj rval = DDI_SUCCESS; 1583446Smrj break; 1593446Smrj default: 1603446Smrj break; 1613446Smrj } 1623446Smrj 1633446Smrj return (rval); 1643446Smrj } 1653446Smrj 1663446Smrj static int 1673446Smrj amd64_gart_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1683446Smrj { 1693446Smrj int instance; 1703446Smrj amd64_gart_softstate_t *sc; 1713446Smrj int status; 1723446Smrj char buf[80]; 1733446Smrj 1745295Srandyf switch (cmd) { 1755295Srandyf default: 1763446Smrj return (DDI_FAILURE); 1773446Smrj 1785295Srandyf case DDI_RESUME: 1795295Srandyf /* Nothing special is needed for resume. */ 1805295Srandyf return (DDI_SUCCESS); 1815295Srandyf 1825295Srandyf case DDI_ATTACH: 1835295Srandyf break; 1845295Srandyf } 1855295Srandyf 1863446Smrj instance = ddi_get_instance(dip); 1873446Smrj 1883446Smrj if (ddi_soft_state_zalloc(amd64_gart_glob_soft_handle, instance) != 1893446Smrj DDI_SUCCESS) 1903446Smrj return (DDI_FAILURE); 1913446Smrj 1923446Smrj sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 1933446Smrj mutex_init(&sc->gsoft_lock, NULL, MUTEX_DRIVER, NULL); 1943446Smrj sc->gsoft_dip = dip; 1953446Smrj status = pci_config_setup(dip, &sc->gsoft_pcihdl); 1963446Smrj if (status != DDI_SUCCESS) { 1973446Smrj ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 1983446Smrj return (DDI_FAILURE); 1993446Smrj } 2003446Smrj (void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance); 2013446Smrj status = ddi_create_minor_node(dip, buf, S_IFCHR, 2023446Smrj INST2NODENUM(instance), DDI_NT_AGP_CPUGART, 0); 2033446Smrj if (status != DDI_SUCCESS) { 2043446Smrj pci_config_teardown(&sc->gsoft_pcihdl); 2053446Smrj ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 2063446Smrj return (DDI_FAILURE); 2073446Smrj } 2083446Smrj return (DDI_SUCCESS); 2093446Smrj } 2103446Smrj 2113446Smrj /*ARGSUSED*/ 2123446Smrj static int 2133446Smrj amd64_gart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2143446Smrj { 2153446Smrj int instance; 2163446Smrj amd64_gart_softstate_t *sc; 2173446Smrj char buf[80]; 2183446Smrj 2195295Srandyf switch (cmd) { 2205295Srandyf default: 2213446Smrj return (DDI_FAILURE); 2223446Smrj 2235295Srandyf case DDI_SUSPEND: 2245295Srandyf /* Nothing special is needed for suspend */ 2255295Srandyf return (DDI_SUCCESS); 2265295Srandyf 2275295Srandyf case DDI_DETACH: 2285295Srandyf break; 2295295Srandyf } 2305295Srandyf 2313446Smrj instance = ddi_get_instance(dip); 2323446Smrj sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 2333446Smrj 2343446Smrj (void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance); 2353446Smrj ddi_remove_minor_node(dip, buf); 2363446Smrj pci_config_teardown(&sc->gsoft_pcihdl); 2373446Smrj mutex_destroy(&sc->gsoft_lock); 2383446Smrj ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 2393446Smrj 2403446Smrj return (DDI_SUCCESS); 2413446Smrj } 2423446Smrj 2433446Smrj /*ARGSUSED*/ 2443446Smrj static int 2453446Smrj amd64_gart_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 2463446Smrj cred_t *cred, int *rval) 2473446Smrj { 2483446Smrj int instance; 2493446Smrj amd64_gart_softstate_t *sc; 2503446Smrj static char kernel_only[] = 2513446Smrj "amd64_gart_ioctl: is a kernel only ioctl"; 2523446Smrj 2533446Smrj if (!(mode & FKIOCTL)) { 2543446Smrj AMD64DB_PRINT2((CE_CONT, kernel_only)); 2553446Smrj return (ENXIO); 2563446Smrj } 2573446Smrj instance = DEV2INST(dev); 2583446Smrj sc = GETSOFTC(instance); 2593446Smrj 2603446Smrj if (sc == NULL) 2613446Smrj return (ENXIO); 2623446Smrj mutex_enter(&sc->gsoft_lock); 2633446Smrj 2643446Smrj switch (cmd) { 2653446Smrj case AMD64_GET_INFO: 2663446Smrj { 2673446Smrj amdgart_info_t info; 2683446Smrj 2693446Smrj info.cgart_aperbase = amd64_get_aperbase(sc); 2703446Smrj info.cgart_apersize = amd64_get_apersize(sc); 2713446Smrj 2723446Smrj if (ddi_copyout(&info, (void *)data, 2733446Smrj sizeof (amdgart_info_t), mode)) { 2743446Smrj mutex_exit(&sc->gsoft_lock); 2753446Smrj return (EFAULT); 2763446Smrj } 2773446Smrj break; 2783446Smrj } 2793446Smrj case AMD64_SET_GART_ADDR: 2803446Smrj { 2813446Smrj uint32_t addr; 2823446Smrj 2833446Smrj if (ddi_copyin((void *)data, &addr, sizeof (uint32_t), mode)) { 2843446Smrj mutex_exit(&sc->gsoft_lock); 2853446Smrj return (EFAULT); 2863446Smrj } 2873446Smrj 2883446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, addr); 2893446Smrj amd64_enable_gart(sc, 1); 2903446Smrj 2913446Smrj break; 2923446Smrj } 2933446Smrj case AMD64_FLUSH_GTLB: 2943446Smrj { 2953446Smrj amd64_invalidate_gtlb(sc); 2963446Smrj 2973446Smrj break; 2983446Smrj } 2993446Smrj case AMD64_CONFIGURE: 3003446Smrj { 3013446Smrj /* reserved */ 3023446Smrj break; 3033446Smrj } 3043446Smrj case AMD64_UNCONFIG: 3053446Smrj { 3063446Smrj amd64_enable_gart(sc, 0); 3073446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, 0x00000000); 3083446Smrj 3093446Smrj break; 3103446Smrj } 3113446Smrj default: 3123446Smrj mutex_exit(&sc->gsoft_lock); 3133446Smrj return (ENXIO); 3143446Smrj 3153446Smrj } 3163446Smrj 3173446Smrj mutex_exit(&sc->gsoft_lock); 3183446Smrj 3193446Smrj return (0); 3203446Smrj } 3213446Smrj 3223446Smrj /*ARGSUSED*/ 3233446Smrj static int 3243446Smrj amd64_gart_open(dev_t *dev, int flag, int otyp, cred_t *cred) 3253446Smrj { 3263446Smrj int instance; 3273446Smrj amd64_gart_softstate_t *sc; 3283446Smrj 3293446Smrj if (!(flag & FKLYR)) 3303446Smrj return (ENXIO); 3313446Smrj 3323446Smrj instance = DEV2INST(*dev); 3333446Smrj sc = GETSOFTC(instance); 3343446Smrj 3353446Smrj if (sc == NULL) 3363446Smrj return (ENXIO); 3373446Smrj 3383446Smrj return (0); 3393446Smrj } 3403446Smrj 3413446Smrj /*ARGSUSED*/ 3423446Smrj static int 3433446Smrj amd64_gart_close(dev_t dev, int flag, int otyp, cred_t *cred) 3443446Smrj { 3453446Smrj int instance; 3463446Smrj amd64_gart_softstate_t *sc; 3473446Smrj 3483446Smrj instance = DEV2INST(dev); 3493446Smrj sc = GETSOFTC(instance); 3503446Smrj 3513446Smrj if (sc == NULL) 3523446Smrj return (ENXIO); 3533446Smrj 3543446Smrj return (0); 3553446Smrj } 3563446Smrj 3573446Smrj static struct cb_ops amd64_gart_cb_ops = { 3583446Smrj amd64_gart_open, /* cb_open() */ 3593446Smrj amd64_gart_close, /* cb_close() */ 3603446Smrj nodev, /* cb_strategy() */ 3613446Smrj nodev, /* cb_print */ 3623446Smrj nodev, /* cb_dump */ 3633446Smrj nodev, /* cb_read() */ 3643446Smrj nodev, /* cb_write() */ 3653446Smrj amd64_gart_ioctl, /* cb_ioctl */ 3663446Smrj nodev, /* cb_devmap */ 3673446Smrj nodev, /* cb_mmap */ 3683446Smrj nodev, /* cb_segmap */ 3693446Smrj nochpoll, /* cb_chpoll */ 3703446Smrj ddi_prop_op, /* cb_prop_op */ 3713446Smrj 0, /* cb_stream */ 3723446Smrj D_NEW | D_MP, /* cb_flag */ 3733446Smrj CB_REV, /* cb_ops version? */ 3743446Smrj nodev, /* cb_aread() */ 3753446Smrj nodev, /* cb_awrite() */ 3763446Smrj }; 3773446Smrj 3783446Smrj /* device operations */ 3793446Smrj static struct dev_ops amd64_gart_ops = { 3803446Smrj DEVO_REV, /* devo_rev */ 3813446Smrj 0, /* devo_refcnt */ 3823446Smrj amd64_gart_getinfo, /* devo_getinfo */ 3833446Smrj nulldev, /* devo_identify */ 3843446Smrj nulldev, /* devo_probe */ 3853446Smrj amd64_gart_attach, /* devo_attach */ 3863446Smrj amd64_gart_detach, /* devo_detach */ 3873446Smrj nodev, /* devo_reset */ 3883446Smrj &amd64_gart_cb_ops, /* devo_cb_ops */ 3893446Smrj 0, /* devo_bus_ops */ 3903446Smrj 0, /* devo_power */ 391*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */ 3923446Smrj }; 3933446Smrj 3943446Smrj static struct modldrv modldrv = { 3953446Smrj &mod_driverops, 3967542SRichard.Bean@Sun.COM "AGP AMD gart driver", 3973446Smrj &amd64_gart_ops, 3983446Smrj }; 3993446Smrj 4003446Smrj static struct modlinkage modlinkage = { 4013446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 4023446Smrj &modldrv, 4033446Smrj NULL 4043446Smrj }; 4053446Smrj 4063446Smrj 4073446Smrj int 4083446Smrj _init(void) 4093446Smrj { 4103446Smrj int ret = DDI_SUCCESS; 4113446Smrj 4123446Smrj ret = ddi_soft_state_init(&amd64_gart_glob_soft_handle, 4133446Smrj sizeof (amd64_gart_softstate_t), 4143446Smrj MAX_GART_INSTS); 4153446Smrj 4163446Smrj if (ret) 4173446Smrj return (ret); 4183446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 4193446Smrj ddi_soft_state_fini(&amd64_gart_glob_soft_handle); 4203446Smrj return (ret); 4213446Smrj } 4223446Smrj return (DDI_SUCCESS); 4233446Smrj } 4243446Smrj 4253446Smrj int 4263446Smrj _info(struct modinfo *modinfop) 4273446Smrj { 4283446Smrj return (mod_info(&modlinkage, modinfop)); 4293446Smrj } 4303446Smrj 4313446Smrj int 4323446Smrj _fini(void) 4333446Smrj { 4343446Smrj int ret; 4353446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 4363446Smrj ddi_soft_state_fini(&amd64_gart_glob_soft_handle); 4373446Smrj } 4383446Smrj return (ret); 4393446Smrj } 440