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