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