1 /* 2 * Copyright 2005 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 if (cmd != DDI_ATTACH) 177 return (DDI_FAILURE); 178 179 instance = ddi_get_instance(dip); 180 181 if (ddi_soft_state_zalloc(amd64_gart_glob_soft_handle, instance) != 182 DDI_SUCCESS) 183 return (DDI_FAILURE); 184 185 sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 186 mutex_init(&sc->gsoft_lock, NULL, MUTEX_DRIVER, NULL); 187 sc->gsoft_dip = dip; 188 status = pci_config_setup(dip, &sc->gsoft_pcihdl); 189 if (status != DDI_SUCCESS) { 190 ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 191 return (DDI_FAILURE); 192 } 193 (void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance); 194 status = ddi_create_minor_node(dip, buf, S_IFCHR, 195 INST2NODENUM(instance), DDI_NT_AGP_CPUGART, 0); 196 if (status != DDI_SUCCESS) { 197 pci_config_teardown(&sc->gsoft_pcihdl); 198 ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 199 return (DDI_FAILURE); 200 } 201 return (DDI_SUCCESS); 202 } 203 204 /*ARGSUSED*/ 205 static int 206 amd64_gart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 207 { 208 int instance; 209 amd64_gart_softstate_t *sc; 210 char buf[80]; 211 212 if (cmd != DDI_DETACH) 213 return (DDI_FAILURE); 214 215 instance = ddi_get_instance(dip); 216 sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance); 217 218 (void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance); 219 ddi_remove_minor_node(dip, buf); 220 pci_config_teardown(&sc->gsoft_pcihdl); 221 mutex_destroy(&sc->gsoft_lock); 222 ddi_soft_state_free(amd64_gart_glob_soft_handle, instance); 223 224 return (DDI_SUCCESS); 225 } 226 227 /*ARGSUSED*/ 228 static int 229 amd64_gart_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 230 cred_t *cred, int *rval) 231 { 232 int instance; 233 amd64_gart_softstate_t *sc; 234 static char kernel_only[] = 235 "amd64_gart_ioctl: is a kernel only ioctl"; 236 237 if (!(mode & FKIOCTL)) { 238 AMD64DB_PRINT2((CE_CONT, kernel_only)); 239 return (ENXIO); 240 } 241 instance = DEV2INST(dev); 242 sc = GETSOFTC(instance); 243 244 if (sc == NULL) 245 return (ENXIO); 246 mutex_enter(&sc->gsoft_lock); 247 248 switch (cmd) { 249 case AMD64_GET_INFO: 250 { 251 amdgart_info_t info; 252 253 info.cgart_aperbase = amd64_get_aperbase(sc); 254 info.cgart_apersize = amd64_get_apersize(sc); 255 256 if (ddi_copyout(&info, (void *)data, 257 sizeof (amdgart_info_t), mode)) { 258 mutex_exit(&sc->gsoft_lock); 259 return (EFAULT); 260 } 261 break; 262 } 263 case AMD64_SET_GART_ADDR: 264 { 265 uint32_t addr; 266 267 if (ddi_copyin((void *)data, &addr, sizeof (uint32_t), mode)) { 268 mutex_exit(&sc->gsoft_lock); 269 return (EFAULT); 270 } 271 272 pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, addr); 273 amd64_enable_gart(sc, 1); 274 275 break; 276 } 277 case AMD64_FLUSH_GTLB: 278 { 279 amd64_invalidate_gtlb(sc); 280 281 break; 282 } 283 case AMD64_CONFIGURE: 284 { 285 /* reserved */ 286 break; 287 } 288 case AMD64_UNCONFIG: 289 { 290 amd64_enable_gart(sc, 0); 291 pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, 0x00000000); 292 293 break; 294 } 295 default: 296 mutex_exit(&sc->gsoft_lock); 297 return (ENXIO); 298 299 } 300 301 mutex_exit(&sc->gsoft_lock); 302 303 return (0); 304 } 305 306 /*ARGSUSED*/ 307 static int 308 amd64_gart_open(dev_t *dev, int flag, int otyp, cred_t *cred) 309 { 310 int instance; 311 amd64_gart_softstate_t *sc; 312 313 if (!(flag & FKLYR)) 314 return (ENXIO); 315 316 instance = DEV2INST(*dev); 317 sc = GETSOFTC(instance); 318 319 if (sc == NULL) 320 return (ENXIO); 321 322 return (0); 323 } 324 325 /*ARGSUSED*/ 326 static int 327 amd64_gart_close(dev_t dev, int flag, int otyp, cred_t *cred) 328 { 329 int instance; 330 amd64_gart_softstate_t *sc; 331 332 instance = DEV2INST(dev); 333 sc = GETSOFTC(instance); 334 335 if (sc == NULL) 336 return (ENXIO); 337 338 return (0); 339 } 340 341 static struct cb_ops amd64_gart_cb_ops = { 342 amd64_gart_open, /* cb_open() */ 343 amd64_gart_close, /* cb_close() */ 344 nodev, /* cb_strategy() */ 345 nodev, /* cb_print */ 346 nodev, /* cb_dump */ 347 nodev, /* cb_read() */ 348 nodev, /* cb_write() */ 349 amd64_gart_ioctl, /* cb_ioctl */ 350 nodev, /* cb_devmap */ 351 nodev, /* cb_mmap */ 352 nodev, /* cb_segmap */ 353 nochpoll, /* cb_chpoll */ 354 ddi_prop_op, /* cb_prop_op */ 355 0, /* cb_stream */ 356 D_NEW | D_MP, /* cb_flag */ 357 CB_REV, /* cb_ops version? */ 358 nodev, /* cb_aread() */ 359 nodev, /* cb_awrite() */ 360 }; 361 362 /* device operations */ 363 static struct dev_ops amd64_gart_ops = { 364 DEVO_REV, /* devo_rev */ 365 0, /* devo_refcnt */ 366 amd64_gart_getinfo, /* devo_getinfo */ 367 nulldev, /* devo_identify */ 368 nulldev, /* devo_probe */ 369 amd64_gart_attach, /* devo_attach */ 370 amd64_gart_detach, /* devo_detach */ 371 nodev, /* devo_reset */ 372 &amd64_gart_cb_ops, /* devo_cb_ops */ 373 0, /* devo_bus_ops */ 374 0, /* devo_power */ 375 }; 376 377 static struct modldrv modldrv = { 378 &mod_driverops, 379 "AGP AMD gart driver v%I%", 380 &amd64_gart_ops, 381 }; 382 383 static struct modlinkage modlinkage = { 384 MODREV_1, /* MODREV_1 is indicated by manual */ 385 &modldrv, 386 NULL 387 }; 388 389 390 int 391 _init(void) 392 { 393 int ret = DDI_SUCCESS; 394 395 ret = ddi_soft_state_init(&amd64_gart_glob_soft_handle, 396 sizeof (amd64_gart_softstate_t), 397 MAX_GART_INSTS); 398 399 if (ret) 400 return (ret); 401 if ((ret = mod_install(&modlinkage)) != 0) { 402 ddi_soft_state_fini(&amd64_gart_glob_soft_handle); 403 return (ret); 404 } 405 return (DDI_SUCCESS); 406 } 407 408 int 409 _info(struct modinfo *modinfop) 410 { 411 return (mod_info(&modlinkage, modinfop)); 412 } 413 414 int 415 _fini(void) 416 { 417 int ret; 418 if ((ret = mod_remove(&modlinkage)) == 0) { 419 ddi_soft_state_fini(&amd64_gart_glob_soft_handle); 420 } 421 return (ret); 422 } 423