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
amd64_get_aperbase(amd64_gart_softstate_t * sc)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
amd64_get_apersize(amd64_gart_softstate_t * sc)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
amd64_invalidate_gtlb(amd64_gart_softstate_t * sc)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
amd64_enable_gart(amd64_gart_softstate_t * sc,int enable)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
amd64_gart_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
amd64_gart_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
amd64_gart_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
amd64_gart_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval)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
amd64_gart_open(dev_t * dev,int flag,int otyp,cred_t * cred)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
amd64_gart_close(dev_t dev,int flag,int otyp,cred_t * cred)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
_init(void)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
_info(struct modinfo * modinfop)4263446Smrj _info(struct modinfo *modinfop)
4273446Smrj {
4283446Smrj return (mod_info(&modlinkage, modinfop));
4293446Smrj }
4303446Smrj
4313446Smrj int
_fini(void)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