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