1*3446Smrj /* 2*3446Smrj * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*3446Smrj * Use is subject to license terms. 4*3446Smrj */ 5*3446Smrj 6*3446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 7*3446Smrj 8*3446Smrj #include <sys/conf.h> 9*3446Smrj #include <sys/ddi.h> 10*3446Smrj #include <sys/sunddi.h> 11*3446Smrj #include <sys/modctl.h> 12*3446Smrj #include <sys/stat.h> 13*3446Smrj #include <sys/sunldi.h> 14*3446Smrj #include <sys/file.h> 15*3446Smrj #include <sys/agpgart.h> 16*3446Smrj #include <sys/agp/agpdefs.h> 17*3446Smrj #include <sys/agp/agpamd64gart_io.h> 18*3446Smrj 19*3446Smrj #define MAX_GART_INSTS 8 20*3446Smrj #define GETSOFTC(instance) ((amd64_gart_softstate_t *) \ 21*3446Smrj ddi_get_soft_state(amd64_gart_glob_soft_handle, (instance))); 22*3446Smrj #define DEV2INST(dev) (getminor(dev)) 23*3446Smrj #define INST2NODENUM(inst) (inst) 24*3446Smrj 25*3446Smrj int amd64_debug_var = 0; 26*3446Smrj #define AMD64DB_PRINT1(fmt) if (amd64_debug_var == 1) cmn_err fmt 27*3446Smrj #define AMD64DB_PRINT2(fmt) if (amd64_debug_var >= 1) cmn_err fmt 28*3446Smrj 29*3446Smrj typedef struct amd64_gart_softstate { 30*3446Smrj dev_info_t *gsoft_dip; 31*3446Smrj ddi_acc_handle_t gsoft_pcihdl; 32*3446Smrj kmutex_t gsoft_lock; 33*3446Smrj }amd64_gart_softstate_t; 34*3446Smrj 35*3446Smrj static void *amd64_gart_glob_soft_handle; 36*3446Smrj 37*3446Smrj static uint64_t 38*3446Smrj amd64_get_aperbase(amd64_gart_softstate_t *sc) 39*3446Smrj { 40*3446Smrj uint32_t value; 41*3446Smrj uint64_t aper_base; 42*3446Smrj 43*3446Smrj /* amd64 aperture base support 40 bits and 32M aligned */ 44*3446Smrj value = pci_config_get32(sc->gsoft_pcihdl, 45*3446Smrj AMD64_APERTURE_BASE) & AMD64_APERBASE_MASK; 46*3446Smrj aper_base = (uint64_t)value << AMD64_APERBASE_SHIFT; 47*3446Smrj return (aper_base); 48*3446Smrj } 49*3446Smrj 50*3446Smrj static size_t 51*3446Smrj amd64_get_apersize(amd64_gart_softstate_t *sc) 52*3446Smrj { 53*3446Smrj uint32_t value; 54*3446Smrj size_t size; 55*3446Smrj 56*3446Smrj value = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL); 57*3446Smrj 58*3446Smrj value = (value & AMD64_APERSIZE_MASK) >> 1; 59*3446Smrj 60*3446Smrj /* aper size = 2^value x 32 */ 61*3446Smrj switch (value) { 62*3446Smrj case 0x0: 63*3446Smrj size = 32; 64*3446Smrj break; 65*3446Smrj case 0x1: 66*3446Smrj size = 64; 67*3446Smrj break; 68*3446Smrj case 0x2: 69*3446Smrj size = 128; 70*3446Smrj break; 71*3446Smrj case 0x3: 72*3446Smrj size = 256; 73*3446Smrj break; 74*3446Smrj case 0x4: 75*3446Smrj size = 512; 76*3446Smrj break; 77*3446Smrj case 0x5: 78*3446Smrj size = 1024; 79*3446Smrj break; 80*3446Smrj case 0x6: 81*3446Smrj size = 2048; 82*3446Smrj break; 83*3446Smrj default: /* reserved */ 84*3446Smrj size = 0; 85*3446Smrj }; 86*3446Smrj 87*3446Smrj return (size); 88*3446Smrj } 89*3446Smrj 90*3446Smrj static void 91*3446Smrj amd64_invalidate_gtlb(amd64_gart_softstate_t *sc) 92*3446Smrj { 93*3446Smrj uint32_t value; 94*3446Smrj 95*3446Smrj value = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL); 96*3446Smrj value |= AMD64_INVALID_CACHE; 97*3446Smrj 98*3446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL, value); 99*3446Smrj } 100*3446Smrj 101*3446Smrj static void 102*3446Smrj amd64_enable_gart(amd64_gart_softstate_t *sc, int enable) 103*3446Smrj { 104*3446Smrj uint32_t aper_ctl; 105*3446Smrj uint32_t aper_base; 106*3446Smrj uint32_t gart_ctl; 107*3446Smrj uint32_t gart_base; 108*3446Smrj 109*3446Smrj aper_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL); 110*3446Smrj AMD64DB_PRINT1((CE_NOTE, "before: aper_ctl = %x", aper_ctl)); 111*3446Smrj aper_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_BASE); 112*3446Smrj gart_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL); 113*3446Smrj gart_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_BASE); 114*3446Smrj #ifdef lint 115*3446Smrj aper_base = aper_base; 116*3446Smrj gart_ctl = gart_ctl; 117*3446Smrj gart_base = gart_base; 118*3446Smrj #endif /* lint */ 119*3446Smrj AMD64DB_PRINT1((CE_NOTE, "before: aper_base = %x", aper_base)); 120*3446Smrj AMD64DB_PRINT1((CE_NOTE, "before: gart_ctl = %x", gart_ctl)); 121*3446Smrj AMD64DB_PRINT1((CE_NOTE, "before: gart_base = %x", gart_base)); 122*3446Smrj if (enable) { 123*3446Smrj aper_ctl |= AMD64_GARTEN; 124*3446Smrj aper_ctl &= ~(AMD64_DISGARTCPU | AMD64_DISGARTIO); 125*3446Smrj } else 126*3446Smrj aper_ctl &= (~AMD64_GARTEN); 127*3446Smrj 128*3446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL, aper_ctl); 129*3446Smrj } 130*3446Smrj 131*3446Smrj /*ARGSUSED*/ 132*3446Smrj static int 133*3446Smrj amd64_gart_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 134*3446Smrj void *arg, void **resultp) 135*3446Smrj { 136*3446Smrj amd64_gart_softstate_t *st; 137*3446Smrj int instance, rval = DDI_FAILURE; 138*3446Smrj dev_t dev; 139*3446Smrj 140*3446Smrj switch (cmd) { 141*3446Smrj case DDI_INFO_DEVT2DEVINFO: 142*3446Smrj dev = (dev_t)arg; 143*3446Smrj instance = DEV2INST(dev); 144*3446Smrj st = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 145*3446Smrj if (st != NULL) { 146*3446Smrj mutex_enter(&st->gsoft_lock); 147*3446Smrj *resultp = st->gsoft_dip; 148*3446Smrj mutex_exit(&st->gsoft_lock); 149*3446Smrj rval = DDI_SUCCESS; 150*3446Smrj } else { 151*3446Smrj *resultp = NULL; 152*3446Smrj } 153*3446Smrj 154*3446Smrj break; 155*3446Smrj case DDI_INFO_DEVT2INSTANCE: 156*3446Smrj dev = (dev_t)arg; 157*3446Smrj instance = DEV2INST(dev); 158*3446Smrj *resultp = (void *)(uintptr_t)instance; 159*3446Smrj rval = DDI_SUCCESS; 160*3446Smrj break; 161*3446Smrj default: 162*3446Smrj break; 163*3446Smrj } 164*3446Smrj 165*3446Smrj return (rval); 166*3446Smrj } 167*3446Smrj 168*3446Smrj static int 169*3446Smrj amd64_gart_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 170*3446Smrj { 171*3446Smrj int instance; 172*3446Smrj amd64_gart_softstate_t *sc; 173*3446Smrj int status; 174*3446Smrj char buf[80]; 175*3446Smrj 176*3446Smrj if (cmd != DDI_ATTACH) 177*3446Smrj return (DDI_FAILURE); 178*3446Smrj 179*3446Smrj instance = ddi_get_instance(dip); 180*3446Smrj 181*3446Smrj if (ddi_soft_state_zalloc(amd64_gart_glob_soft_handle, instance) != 182*3446Smrj DDI_SUCCESS) 183*3446Smrj return (DDI_FAILURE); 184*3446Smrj 185*3446Smrj sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 186*3446Smrj mutex_init(&sc->gsoft_lock, NULL, MUTEX_DRIVER, NULL); 187*3446Smrj sc->gsoft_dip = dip; 188*3446Smrj status = pci_config_setup(dip, &sc->gsoft_pcihdl); 189*3446Smrj if (status != DDI_SUCCESS) { 190*3446Smrj ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 191*3446Smrj return (DDI_FAILURE); 192*3446Smrj } 193*3446Smrj (void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance); 194*3446Smrj status = ddi_create_minor_node(dip, buf, S_IFCHR, 195*3446Smrj INST2NODENUM(instance), DDI_NT_AGP_CPUGART, 0); 196*3446Smrj if (status != DDI_SUCCESS) { 197*3446Smrj pci_config_teardown(&sc->gsoft_pcihdl); 198*3446Smrj ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 199*3446Smrj return (DDI_FAILURE); 200*3446Smrj } 201*3446Smrj return (DDI_SUCCESS); 202*3446Smrj } 203*3446Smrj 204*3446Smrj /*ARGSUSED*/ 205*3446Smrj static int 206*3446Smrj amd64_gart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 207*3446Smrj { 208*3446Smrj int instance; 209*3446Smrj amd64_gart_softstate_t *sc; 210*3446Smrj char buf[80]; 211*3446Smrj 212*3446Smrj if (cmd != DDI_DETACH) 213*3446Smrj return (DDI_FAILURE); 214*3446Smrj 215*3446Smrj instance = ddi_get_instance(dip); 216*3446Smrj sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 217*3446Smrj 218*3446Smrj (void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance); 219*3446Smrj ddi_remove_minor_node(dip, buf); 220*3446Smrj pci_config_teardown(&sc->gsoft_pcihdl); 221*3446Smrj mutex_destroy(&sc->gsoft_lock); 222*3446Smrj ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 223*3446Smrj 224*3446Smrj return (DDI_SUCCESS); 225*3446Smrj } 226*3446Smrj 227*3446Smrj /*ARGSUSED*/ 228*3446Smrj static int 229*3446Smrj amd64_gart_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 230*3446Smrj cred_t *cred, int *rval) 231*3446Smrj { 232*3446Smrj int instance; 233*3446Smrj amd64_gart_softstate_t *sc; 234*3446Smrj static char kernel_only[] = 235*3446Smrj "amd64_gart_ioctl: is a kernel only ioctl"; 236*3446Smrj 237*3446Smrj if (!(mode & FKIOCTL)) { 238*3446Smrj AMD64DB_PRINT2((CE_CONT, kernel_only)); 239*3446Smrj return (ENXIO); 240*3446Smrj } 241*3446Smrj instance = DEV2INST(dev); 242*3446Smrj sc = GETSOFTC(instance); 243*3446Smrj 244*3446Smrj if (sc == NULL) 245*3446Smrj return (ENXIO); 246*3446Smrj mutex_enter(&sc->gsoft_lock); 247*3446Smrj 248*3446Smrj switch (cmd) { 249*3446Smrj case AMD64_GET_INFO: 250*3446Smrj { 251*3446Smrj amdgart_info_t info; 252*3446Smrj 253*3446Smrj info.cgart_aperbase = amd64_get_aperbase(sc); 254*3446Smrj info.cgart_apersize = amd64_get_apersize(sc); 255*3446Smrj 256*3446Smrj if (ddi_copyout(&info, (void *)data, 257*3446Smrj sizeof (amdgart_info_t), mode)) { 258*3446Smrj mutex_exit(&sc->gsoft_lock); 259*3446Smrj return (EFAULT); 260*3446Smrj } 261*3446Smrj break; 262*3446Smrj } 263*3446Smrj case AMD64_SET_GART_ADDR: 264*3446Smrj { 265*3446Smrj uint32_t addr; 266*3446Smrj 267*3446Smrj if (ddi_copyin((void *)data, &addr, sizeof (uint32_t), mode)) { 268*3446Smrj mutex_exit(&sc->gsoft_lock); 269*3446Smrj return (EFAULT); 270*3446Smrj } 271*3446Smrj 272*3446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, addr); 273*3446Smrj amd64_enable_gart(sc, 1); 274*3446Smrj 275*3446Smrj break; 276*3446Smrj } 277*3446Smrj case AMD64_FLUSH_GTLB: 278*3446Smrj { 279*3446Smrj amd64_invalidate_gtlb(sc); 280*3446Smrj 281*3446Smrj break; 282*3446Smrj } 283*3446Smrj case AMD64_CONFIGURE: 284*3446Smrj { 285*3446Smrj /* reserved */ 286*3446Smrj break; 287*3446Smrj } 288*3446Smrj case AMD64_UNCONFIG: 289*3446Smrj { 290*3446Smrj amd64_enable_gart(sc, 0); 291*3446Smrj pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, 0x00000000); 292*3446Smrj 293*3446Smrj break; 294*3446Smrj } 295*3446Smrj default: 296*3446Smrj mutex_exit(&sc->gsoft_lock); 297*3446Smrj return (ENXIO); 298*3446Smrj 299*3446Smrj } 300*3446Smrj 301*3446Smrj mutex_exit(&sc->gsoft_lock); 302*3446Smrj 303*3446Smrj return (0); 304*3446Smrj } 305*3446Smrj 306*3446Smrj /*ARGSUSED*/ 307*3446Smrj static int 308*3446Smrj amd64_gart_open(dev_t *dev, int flag, int otyp, cred_t *cred) 309*3446Smrj { 310*3446Smrj int instance; 311*3446Smrj amd64_gart_softstate_t *sc; 312*3446Smrj 313*3446Smrj if (!(flag & FKLYR)) 314*3446Smrj return (ENXIO); 315*3446Smrj 316*3446Smrj instance = DEV2INST(*dev); 317*3446Smrj sc = GETSOFTC(instance); 318*3446Smrj 319*3446Smrj if (sc == NULL) 320*3446Smrj return (ENXIO); 321*3446Smrj 322*3446Smrj return (0); 323*3446Smrj } 324*3446Smrj 325*3446Smrj /*ARGSUSED*/ 326*3446Smrj static int 327*3446Smrj amd64_gart_close(dev_t dev, int flag, int otyp, cred_t *cred) 328*3446Smrj { 329*3446Smrj int instance; 330*3446Smrj amd64_gart_softstate_t *sc; 331*3446Smrj 332*3446Smrj instance = DEV2INST(dev); 333*3446Smrj sc = GETSOFTC(instance); 334*3446Smrj 335*3446Smrj if (sc == NULL) 336*3446Smrj return (ENXIO); 337*3446Smrj 338*3446Smrj return (0); 339*3446Smrj } 340*3446Smrj 341*3446Smrj static struct cb_ops amd64_gart_cb_ops = { 342*3446Smrj amd64_gart_open, /* cb_open() */ 343*3446Smrj amd64_gart_close, /* cb_close() */ 344*3446Smrj nodev, /* cb_strategy() */ 345*3446Smrj nodev, /* cb_print */ 346*3446Smrj nodev, /* cb_dump */ 347*3446Smrj nodev, /* cb_read() */ 348*3446Smrj nodev, /* cb_write() */ 349*3446Smrj amd64_gart_ioctl, /* cb_ioctl */ 350*3446Smrj nodev, /* cb_devmap */ 351*3446Smrj nodev, /* cb_mmap */ 352*3446Smrj nodev, /* cb_segmap */ 353*3446Smrj nochpoll, /* cb_chpoll */ 354*3446Smrj ddi_prop_op, /* cb_prop_op */ 355*3446Smrj 0, /* cb_stream */ 356*3446Smrj D_NEW | D_MP, /* cb_flag */ 357*3446Smrj CB_REV, /* cb_ops version? */ 358*3446Smrj nodev, /* cb_aread() */ 359*3446Smrj nodev, /* cb_awrite() */ 360*3446Smrj }; 361*3446Smrj 362*3446Smrj /* device operations */ 363*3446Smrj static struct dev_ops amd64_gart_ops = { 364*3446Smrj DEVO_REV, /* devo_rev */ 365*3446Smrj 0, /* devo_refcnt */ 366*3446Smrj amd64_gart_getinfo, /* devo_getinfo */ 367*3446Smrj nulldev, /* devo_identify */ 368*3446Smrj nulldev, /* devo_probe */ 369*3446Smrj amd64_gart_attach, /* devo_attach */ 370*3446Smrj amd64_gart_detach, /* devo_detach */ 371*3446Smrj nodev, /* devo_reset */ 372*3446Smrj &amd64_gart_cb_ops, /* devo_cb_ops */ 373*3446Smrj 0, /* devo_bus_ops */ 374*3446Smrj 0, /* devo_power */ 375*3446Smrj }; 376*3446Smrj 377*3446Smrj static struct modldrv modldrv = { 378*3446Smrj &mod_driverops, 379*3446Smrj "AGP AMD gart driver v%I%", 380*3446Smrj &amd64_gart_ops, 381*3446Smrj }; 382*3446Smrj 383*3446Smrj static struct modlinkage modlinkage = { 384*3446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 385*3446Smrj &modldrv, 386*3446Smrj NULL 387*3446Smrj }; 388*3446Smrj 389*3446Smrj 390*3446Smrj int 391*3446Smrj _init(void) 392*3446Smrj { 393*3446Smrj int ret = DDI_SUCCESS; 394*3446Smrj 395*3446Smrj ret = ddi_soft_state_init(&amd64_gart_glob_soft_handle, 396*3446Smrj sizeof (amd64_gart_softstate_t), 397*3446Smrj MAX_GART_INSTS); 398*3446Smrj 399*3446Smrj if (ret) 400*3446Smrj return (ret); 401*3446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 402*3446Smrj ddi_soft_state_fini(&amd64_gart_glob_soft_handle); 403*3446Smrj return (ret); 404*3446Smrj } 405*3446Smrj return (DDI_SUCCESS); 406*3446Smrj } 407*3446Smrj 408*3446Smrj int 409*3446Smrj _info(struct modinfo *modinfop) 410*3446Smrj { 411*3446Smrj return (mod_info(&modlinkage, modinfop)); 412*3446Smrj } 413*3446Smrj 414*3446Smrj int 415*3446Smrj _fini(void) 416*3446Smrj { 417*3446Smrj int ret; 418*3446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 419*3446Smrj ddi_soft_state_fini(&amd64_gart_glob_soft_handle); 420*3446Smrj } 421*3446Smrj return (ret); 422*3446Smrj } 423