1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #include <sys/systm.h> 29 #include <sys/conf.h> 30 #include <sys/modctl.h> 31 #include <sys/file.h> 32 #include <sys/stat.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/modctl.h> 36 #include <sys/sunldi.h> 37 #include <sys/pci.h> 38 #include <sys/agpgart.h> 39 #include <sys/agp/agpdefs.h> 40 #include <sys/agp/agptarget_io.h> 41 42 int agptarget_debug_var = 0; 43 #define TARGETDB_PRINT2(fmt) if (agptarget_debug_var >= 1) cmn_err fmt 44 #define INST2NODENUM(inst) (inst) 45 #define DEV2INST(dev) (getminor(dev)) 46 47 typedef struct agp_target_softstate { 48 dev_info_t *tsoft_dip; 49 ddi_acc_handle_t tsoft_pcihdl; 50 uint32_t tsoft_devid; 51 /* The offset of the ACAPID register */ 52 off_t tsoft_acaptr; 53 kmutex_t tsoft_lock; 54 int tsoft_gms_off; /* GMS offset in config */ 55 uint32_t tsoft_gms; 56 }agp_target_softstate_t; 57 58 /* 59 * To get the pre-allocated graphics mem size using Graphics Mode Select 60 * (GMS) value. 61 */ 62 typedef struct gms_mode { 63 uint32_t gm_devid; /* bridge vendor + device id */ 64 off_t gm_regoff; /* mode selection register offset */ 65 uint32_t gm_mask; /* GMS mask */ 66 uint32_t gm_num; /* number of modes in gm_vec */ 67 int *gm_vec; /* modes array */ 68 } gms_mode_t; 69 70 static void *agptarget_glob_soft_handle; 71 72 #define GETSOFTC(instance) ((agp_target_softstate_t *) \ 73 ddi_get_soft_state(agptarget_glob_soft_handle, instance)); 74 75 /* 76 * The AMD8151 bridge is the only supported 64 bit hardware 77 */ 78 static int 79 is_64bit_aper(agp_target_softstate_t *softstate) 80 { 81 return (softstate->tsoft_devid == AMD_BR_8151); 82 } 83 84 /* 85 * Check if it is an intel bridge 86 */ 87 static int 88 is_intel_br(agp_target_softstate_t *softstate) 89 { 90 return ((softstate->tsoft_devid & VENDOR_ID_MASK) == 91 INTEL_VENDOR_ID); 92 } 93 94 /* 95 * agp_target_cap_find() 96 * 97 * Description: 98 * This function searches the linked capability list to find the offset 99 * of the AGP capability register. When it was not found, return 0. 100 * This works for standard AGP chipsets, but not for some Intel chipsets, 101 * like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for 102 * these chipsets even if AGP is supported. So the offset of acapid 103 * should be set manually in thoses cases. 104 * 105 * Arguments: 106 * pci_handle ddi acc handle of pci config 107 * 108 * Returns: 109 * 0 No capability pointer register found 110 * nexcap The AGP capability pointer register offset 111 */ 112 static off_t 113 agp_target_cap_find(ddi_acc_handle_t pci_handle) 114 { 115 off_t nextcap = 0; 116 uint32_t ncapid = 0; 117 uint8_t value = 0; 118 119 /* Check if this device supports the capability pointer */ 120 value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT) 121 & PCI_CONF_CAP_MASK); 122 123 if (!value) 124 return (0); 125 /* Get the offset of the first capability pointer from CAPPTR */ 126 nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR)); 127 128 /* Check the AGP capability from the first capability pointer */ 129 while (nextcap) { 130 ncapid = pci_config_get32(pci_handle, nextcap); 131 /* 132 * AGP3.0 rev1.0 127 the capid was assigned by the PCI SIG, 133 * 845 data sheet page 69 134 */ 135 if ((ncapid & PCI_CONF_CAPID_MASK) == 136 AGP_CAP_ID) /* The AGP cap was found */ 137 break; 138 139 nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 140 } 141 142 return (nextcap); 143 144 } 145 146 /* 147 * agp_target_get_aperbase() 148 * 149 * Description: 150 * This function gets the AGP aperture base address from the AGP target 151 * register, the AGP aperture base register was programmed by the BIOS. 152 * 153 * Arguments: 154 * softstate driver soft state pointer 155 * 156 * Returns: 157 * aper_base AGP aperture base address 158 * 159 * Notes: 160 * If a 64bit bridge device is available, the AGP aperture base address 161 * can be 64 bit. 162 */ 163 static uint64_t 164 agp_target_get_apbase(agp_target_softstate_t *softstate) 165 { 166 uint64_t aper_base; 167 168 if (is_intel_br(softstate)) { 169 aper_base = pci_config_get32(softstate->tsoft_pcihdl, 170 AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK; 171 } else if (is_64bit_aper(softstate)) { 172 aper_base = pci_config_get64(softstate->tsoft_pcihdl, 173 AGP_CONF_APERBASE); 174 /* 32-bit or 64-bit aperbase base pointer */ 175 if ((aper_base & AGP_APER_TYPE_MASK) == 0) 176 aper_base &= AGP_32_APERBASE_MASK; 177 else 178 aper_base &= AGP_64_APERBASE_MASK; 179 } 180 181 return (aper_base); 182 } 183 184 /* 185 * agp_target_get_apsize() 186 * 187 * Description: 188 * This function gets the AGP aperture size by reading the AGP aperture 189 * size register. 190 * Arguments: 191 * softstate driver soft state pointer 192 * 193 * Return: 194 * size The AGP aperture size in megabytes 195 * 0 an unexpected error 196 */ 197 static size_t 198 agp_target_get_apsize(agp_target_softstate_t *softstate) 199 { 200 off_t cap; 201 uint16_t value; 202 size_t size, regsize; 203 204 ASSERT(softstate->tsoft_acaptr); 205 cap = softstate->tsoft_acaptr; 206 207 if (is_intel_br(softstate)) { 208 /* extend this value to 16 bit for later tests */ 209 value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl, 210 cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK; 211 } else if (is_64bit_aper(softstate)) { 212 value = pci_config_get16(softstate->tsoft_pcihdl, 213 cap + AGP_CONF_APERSIZE); 214 } 215 216 if (value & AGP_APER_128M_MASK) { 217 switch (value & AGP_APER_128M_MASK) { 218 case AGP_APER_4M: 219 size = 4; /* 4M */ 220 break; 221 case AGP_APER_8M: 222 size = 8; /* 8M */ 223 break; 224 case AGP_APER_16M: 225 size = 16; /* 16M */ 226 break; 227 case AGP_APER_32M: 228 size = 32; /* 32M */ 229 break; 230 case AGP_APER_64M: 231 size = 64; /* 64M */ 232 break; 233 case AGP_APER_128M: 234 size = 128; /* 128M */ 235 break; 236 default: 237 size = 0; /* not true */ 238 } 239 } else { 240 switch (value & AGP_APER_4G_MASK) { 241 case AGP_APER_256M: 242 size = 256; /* 256 M */ 243 break; 244 case AGP_APER_512M: 245 size = 512; /* 512 M */ 246 break; 247 case AGP_APER_1024M: 248 size = 1024; /* 1024 M */ 249 break; 250 case AGP_APER_2048M: 251 size = 2048; /* 2048 M */ 252 break; 253 case AGP_APER_4G: 254 size = 4096; /* 4096 M */ 255 break; 256 default: 257 size = 0; /* not true */ 258 } 259 } 260 /* 261 * In some cases, there is no APSIZE register, so the size value 262 * of 256M could be wrong. Check the value by reading the size of 263 * the first register which was set in the PCI configuration space. 264 */ 265 if (size == 256) { 266 if (ddi_dev_regsize(softstate->tsoft_dip, 267 AGP_TARGET_BAR1, (off_t *)®size) == DDI_FAILURE) 268 return (0); 269 270 if (MB2BYTES(size) != regsize) { 271 TARGETDB_PRINT2((CE_WARN, 272 "APSIZE 256M doesn't match regsize %lx", 273 regsize)); 274 TARGETDB_PRINT2((CE_WARN, "Use regsize instead")); 275 size = BYTES2MB(regsize); 276 } 277 } 278 279 return (size); 280 } 281 282 static void 283 agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr) 284 { 285 ASSERT(softstate->tsoft_acaptr); 286 287 /* Disable the GTLB for Intel chipsets */ 288 pci_config_put16(softstate->tsoft_pcihdl, 289 softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000); 290 291 pci_config_put32(softstate->tsoft_pcihdl, 292 softstate->tsoft_acaptr + AGP_CONF_ATTBASE, 293 gartaddr & AGP_ATTBASE_MASK); 294 } 295 296 /* 297 * Pre-allocated graphics memory for every type of Intel north bridge, mem size 298 * are specified in kbytes. 299 */ 300 #define GMS_MB(n) ((n) * 1024) 301 #define GMS_SHIFT 4 302 #define GMS_SIZE(a) (sizeof (a) / sizeof (int)) 303 304 /* 305 * Since value zero always means "No memory pre-allocated", value of (GMS - 1) 306 * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb) 307 * that GMS value 0x1 corresponding to. 308 * 309 * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics 310 * memory, unless some special BIOS settings exist. 311 */ 312 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)}; 313 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)}; 314 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 315 GMS_MB(32)}; 316 /* There is no modes for 16M in datasheet, but some BIOS add it. */ 317 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)}; 318 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)}; 319 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 320 GMS_MB(32), GMS_MB(48), GMS_MB(64)}; 321 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16), 322 GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)}; 323 static int gms_G4X[13] = {0, 0, 0, 0, 324 GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256), 325 GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)}; 326 327 static gms_mode_t gms_modes[] = { 328 {INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK, 329 GMS_SIZE(gms_810), gms_810}, 330 {INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK, 331 GMS_SIZE(gms_810), gms_810}, 332 {INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK, 333 GMS_SIZE(gms_810), gms_810}, 334 {INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 335 GMS_SIZE(gms_830_845), gms_830_845}, 336 {INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 337 GMS_SIZE(gms_830_845), gms_830_845}, 338 {INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 339 GMS_SIZE(gms_855GM), gms_855GM}, 340 {INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 341 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 342 {INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 343 GMS_SIZE(gms_865_915GM), gms_865_915GM}, 344 {INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 345 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 346 {INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 347 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 348 {INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 349 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 350 {INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 351 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 352 {INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 353 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 354 {INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 355 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 356 {INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 357 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 358 {INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 359 GMS_SIZE(gms_915_945_965), gms_915_945_965}, 360 {INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 361 GMS_SIZE(gms_965GM), gms_965GM}, 362 {INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 363 GMS_SIZE(gms_965GM), gms_965GM}, 364 {INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK, 365 GMS_SIZE(gms_X33), gms_X33}, 366 {INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 367 GMS_SIZE(gms_X33), gms_X33}, 368 {INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK, 369 GMS_SIZE(gms_X33), gms_X33}, 370 {INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 371 GMS_SIZE(gms_965GM), gms_965GM}, 372 {INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 373 GMS_SIZE(gms_G4X), gms_G4X}, 374 {INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 375 GMS_SIZE(gms_G4X), gms_G4X}, 376 {INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 377 GMS_SIZE(gms_G4X), gms_G4X}, 378 {INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 379 GMS_SIZE(gms_G4X), gms_G4X} 380 }; 381 static int 382 get_chip_gms(uint32_t devid) 383 { 384 int num_modes; 385 int i; 386 387 num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); 388 389 for (i = 0; i < num_modes; i++) { 390 if (gms_modes[i].gm_devid == devid) 391 break; 392 } 393 394 return ((i == num_modes) ? -1 : i); 395 } 396 397 /* Returns the size (kbytes) of pre-allocated graphics memory */ 398 static size_t 399 i8xx_biosmem_detect(agp_target_softstate_t *softstate) 400 { 401 uint8_t memval; 402 size_t kbytes; 403 int gms_off; 404 405 kbytes = 0; 406 gms_off = softstate->tsoft_gms_off; 407 408 /* fetch the GMS value from DRAM controller */ 409 memval = pci_config_get8(softstate->tsoft_pcihdl, 410 gms_modes[gms_off].gm_regoff); 411 TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval)); 412 memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT; 413 /* assuming zero byte for 0 or "reserved" GMS values */ 414 if (memval == 0 || memval > gms_modes[gms_off].gm_num) { 415 TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: " 416 "devid = %x, GMS = %x. assuming zero byte of " 417 "pre-allocated memory", 418 gms_modes[gms_off].gm_devid, memval)); 419 goto done; 420 } 421 memval--; /* use (GMS_value - 1) as index */ 422 kbytes = (gms_modes[gms_off].gm_vec)[memval]; 423 424 done: 425 TARGETDB_PRINT2((CE_NOTE, 426 "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected", 427 kbytes)); 428 return (kbytes); 429 } 430 431 /*ARGSUSED*/ 432 static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 433 void *arg, void **resultp) 434 { 435 agp_target_softstate_t *st; 436 int instance, rval = DDI_FAILURE; 437 dev_t dev; 438 439 switch (cmd) { 440 case DDI_INFO_DEVT2DEVINFO: 441 dev = (dev_t)arg; 442 instance = DEV2INST(dev); 443 st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 444 if (st != NULL) { 445 mutex_enter(&st->tsoft_lock); 446 *resultp = st->tsoft_dip; 447 mutex_exit(&st->tsoft_lock); 448 rval = DDI_SUCCESS; 449 } else 450 *resultp = NULL; 451 452 break; 453 case DDI_INFO_DEVT2INSTANCE: 454 dev = (dev_t)arg; 455 instance = DEV2INST(dev); 456 *resultp = (void *)(uintptr_t)instance; 457 rval = DDI_SUCCESS; 458 default: 459 break; 460 } 461 462 return (rval); 463 } 464 465 static int 466 intel_br_resume(agp_target_softstate_t *softstate) 467 { 468 int gms_off; 469 470 gms_off = softstate->tsoft_gms_off; 471 472 /* 473 * We recover the gmch graphics control register here 474 */ 475 pci_config_put16(softstate->tsoft_pcihdl, 476 gms_modes[gms_off].gm_regoff, softstate->tsoft_gms); 477 478 return (DDI_SUCCESS); 479 } 480 static int 481 intel_br_suspend(agp_target_softstate_t *softstate) 482 { 483 int gms_off; 484 485 gms_off = softstate->tsoft_gms_off; 486 softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl, 487 gms_modes[gms_off].gm_regoff); 488 489 return (DDI_SUCCESS); 490 } 491 492 static int 493 agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 494 { 495 agp_target_softstate_t *softstate; 496 int instance; 497 int status; 498 499 instance = ddi_get_instance(dip); 500 501 switch (cmd) { 502 case DDI_ATTACH: 503 break; 504 case DDI_RESUME: 505 softstate = 506 ddi_get_soft_state(agptarget_glob_soft_handle, instance); 507 return (intel_br_resume(softstate)); 508 default: 509 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 510 "only attach and resume ops are supported")); 511 return (DDI_FAILURE); 512 } 513 514 if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, 515 instance) != DDI_SUCCESS) { 516 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 517 "soft state zalloc failed")); 518 return (DDI_FAILURE); 519 } 520 521 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 522 mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 523 softstate->tsoft_dip = dip; 524 status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 525 if (status != DDI_SUCCESS) { 526 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 527 "pci config setup failed")); 528 ddi_soft_state_free(agptarget_glob_soft_handle, 529 instance); 530 return (DDI_FAILURE); 531 } 532 533 softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 534 PCI_CONF_VENID); 535 softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid); 536 if (softstate->tsoft_gms_off < 0) { 537 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 538 "read gms offset failed")); 539 pci_config_teardown(&softstate->tsoft_pcihdl); 540 ddi_soft_state_free(agptarget_glob_soft_handle, 541 instance); 542 return (DDI_FAILURE); 543 } 544 softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 545 if (softstate->tsoft_acaptr == 0) { 546 /* Make a correction for some Intel chipsets */ 547 if (is_intel_br(softstate)) 548 softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 549 else { 550 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 551 "Not a supposed corretion")); 552 pci_config_teardown(&softstate->tsoft_pcihdl); 553 ddi_soft_state_free(agptarget_glob_soft_handle, 554 instance); 555 return (DDI_FAILURE); 556 } 557 } 558 559 status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 560 INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 561 562 if (status != DDI_SUCCESS) { 563 TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" 564 "Create minor node failed")); 565 pci_config_teardown(&softstate->tsoft_pcihdl); 566 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 567 return (DDI_FAILURE); 568 } 569 570 return (DDI_SUCCESS); 571 } 572 573 /*ARGSUSED*/ 574 static int 575 agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 576 { 577 int instance; 578 agp_target_softstate_t *softstate; 579 580 instance = ddi_get_instance(dip); 581 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 582 583 if (cmd == DDI_SUSPEND) { 584 /* get GMS modes list entry */ 585 return (intel_br_suspend(softstate)); 586 } 587 588 if (cmd != DDI_DETACH) { 589 TARGETDB_PRINT2((CE_WARN, "agp_target_detach:" 590 "only detach and suspend ops are supported")); 591 return (DDI_FAILURE); 592 } 593 594 ddi_remove_minor_node(dip, AGPTARGET_NAME); 595 pci_config_teardown(&softstate->tsoft_pcihdl); 596 mutex_destroy(&softstate->tsoft_lock); 597 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 598 return (DDI_SUCCESS); 599 } 600 601 /*ARGSUSED*/ 602 static int 603 agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 604 cred_t *cred, int *rval) 605 { 606 int instance = DEV2INST(dev); 607 agp_target_softstate_t *st; 608 static char kernel_only[] = 609 "amd64_gart_ioctl: is a kernel only ioctl"; 610 611 if (!(mode & FKIOCTL)) { 612 TARGETDB_PRINT2((CE_CONT, kernel_only)); 613 return (ENXIO); 614 } 615 st = GETSOFTC(instance); 616 617 if (st == NULL) 618 return (ENXIO); 619 620 mutex_enter(&st->tsoft_lock); 621 622 switch (cmd) { 623 case CHIP_DETECT: 624 { 625 int type = 0; 626 627 if (is_intel_br(st)) 628 type = CHIP_IS_INTEL; 629 else if (is_64bit_aper(st)) 630 type = CHIP_IS_AMD; 631 else { 632 type = 0; 633 TARGETDB_PRINT2((CE_WARN, "Unknown bridge!")); 634 } 635 636 if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 637 mutex_exit(&st->tsoft_lock); 638 return (EFAULT); 639 } 640 641 break; 642 } 643 case I8XX_GET_PREALLOC_SIZE: 644 { 645 size_t prealloc_size; 646 647 if (!is_intel_br(st)) { 648 mutex_exit(&st->tsoft_lock); 649 return (EINVAL); 650 } 651 652 prealloc_size = i8xx_biosmem_detect(st); 653 if (ddi_copyout(&prealloc_size, (void *)data, 654 sizeof (size_t), mode)) { 655 mutex_exit(&st->tsoft_lock); 656 return (EFAULT); 657 } 658 659 break; 660 } 661 case AGP_TARGET_GETINFO: 662 { 663 i_agp_info_t info; 664 uint32_t value; 665 off_t cap; 666 667 ASSERT(st->tsoft_acaptr); 668 669 cap = st->tsoft_acaptr; 670 value = pci_config_get32(st->tsoft_pcihdl, cap); 671 info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 672 info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 673 info.iagp_devid = st->tsoft_devid; 674 info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 675 cap + AGP_CONF_STATUS); 676 info.iagp_aperbase = agp_target_get_apbase(st); 677 info.iagp_apersize = agp_target_get_apsize(st); 678 679 if (ddi_copyout(&info, (void *)data, 680 sizeof (i_agp_info_t), mode)) { 681 mutex_exit(&st->tsoft_lock); 682 return (EFAULT); 683 } 684 break; 685 686 } 687 /* 688 * This ioctl is only for Intel AGP chipsets. 689 * It is not necessary for the AMD8151 AGP bridge, because 690 * this register in the AMD8151 does not control any hardware. 691 * It is only provided for compatibility with an Intel AGP bridge. 692 * Please refer to the <<AMD8151 data sheet>> page 24, 693 * AGP device GART pointer. 694 */ 695 case AGP_TARGET_SET_GATTADDR: 696 { 697 uint32_t gartaddr; 698 699 if (ddi_copyin((void *)data, &gartaddr, 700 sizeof (uint32_t), mode)) { 701 mutex_exit(&st->tsoft_lock); 702 return (EFAULT); 703 } 704 705 agp_target_set_gartaddr(st, gartaddr); 706 break; 707 } 708 case AGP_TARGET_SETCMD: 709 { 710 uint32_t command; 711 712 if (ddi_copyin((void *)data, &command, 713 sizeof (uint32_t), mode)) { 714 mutex_exit(&st->tsoft_lock); 715 return (EFAULT); 716 } 717 718 ASSERT(st->tsoft_acaptr); 719 720 pci_config_put32(st->tsoft_pcihdl, 721 st->tsoft_acaptr + AGP_CONF_COMMAND, 722 command); 723 break; 724 725 } 726 case AGP_TARGET_FLUSH_GTLB: 727 { 728 uint16_t value; 729 730 ASSERT(st->tsoft_acaptr); 731 732 value = pci_config_get16(st->tsoft_pcihdl, 733 st->tsoft_acaptr + AGP_CONF_CONTROL); 734 value &= ~AGPCTRL_GTLBEN; 735 pci_config_put16(st->tsoft_pcihdl, 736 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 737 value |= AGPCTRL_GTLBEN; 738 pci_config_put16(st->tsoft_pcihdl, 739 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 740 741 break; 742 } 743 case AGP_TARGET_CONFIGURE: 744 { 745 uint8_t value; 746 747 ASSERT(st->tsoft_acaptr); 748 749 /* 750 * In Intel agp bridges, agp misc register offset 751 * is indexed from 0 instead of capability register. 752 * AMD agp bridges have no such misc register 753 * to control the aperture access, and they have 754 * similar regsiters in CPU gart devices instead. 755 */ 756 757 if (is_intel_br(st)) { 758 value = pci_config_get8(st->tsoft_pcihdl, 759 st->tsoft_acaptr + AGP_CONF_MISC); 760 value |= AGP_MISC_APEN; 761 pci_config_put8(st->tsoft_pcihdl, 762 st->tsoft_acaptr + AGP_CONF_MISC, value); 763 } 764 break; 765 766 } 767 case AGP_TARGET_UNCONFIG: 768 { 769 uint32_t value1; 770 uint8_t value2; 771 772 ASSERT(st->tsoft_acaptr); 773 774 pci_config_put16(st->tsoft_pcihdl, 775 st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 776 777 if (is_intel_br(st)) { 778 value2 = pci_config_get8(st->tsoft_pcihdl, 779 st->tsoft_acaptr + AGP_CONF_MISC); 780 value2 &= ~AGP_MISC_APEN; 781 pci_config_put8(st->tsoft_pcihdl, 782 st->tsoft_acaptr + AGP_CONF_MISC, value2); 783 } 784 785 value1 = pci_config_get32(st->tsoft_pcihdl, 786 st->tsoft_acaptr + AGP_CONF_COMMAND); 787 value1 &= ~AGPCMD_AGPEN; 788 pci_config_put32(st->tsoft_pcihdl, 789 st->tsoft_acaptr + AGP_CONF_COMMAND, 790 value1); 791 792 pci_config_put32(st->tsoft_pcihdl, 793 st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 794 795 break; 796 } 797 798 default: 799 mutex_exit(&st->tsoft_lock); 800 return (ENXIO); 801 } /* end switch */ 802 803 mutex_exit(&st->tsoft_lock); 804 805 return (0); 806 } 807 808 /*ARGSUSED*/ 809 static int 810 agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 811 { 812 int instance = DEV2INST(*devp); 813 agp_target_softstate_t *st; 814 815 if (!(flag & FKLYR)) 816 return (ENXIO); 817 818 st = GETSOFTC(instance); 819 820 if (st == NULL) 821 return (ENXIO); 822 823 return (0); 824 } 825 826 /*ARGSUSED*/ 827 static int 828 agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 829 { 830 int instance = DEV2INST(dev); 831 agp_target_softstate_t *st; 832 833 st = GETSOFTC(instance); 834 835 if (st == NULL) 836 return (ENXIO); 837 838 return (0); 839 } 840 841 static struct cb_ops agp_target_cb_ops = { 842 agp_target_open, /* cb_open */ 843 agp_target_close, /* cb_close */ 844 nodev, /* cb_strategy */ 845 nodev, /* cb_print */ 846 nodev, /* cb_dump */ 847 nodev, /* cb_read() */ 848 nodev, /* cb_write() */ 849 agp_target_ioctl, /* cb_ioctl */ 850 nodev, /* cb_devmap */ 851 nodev, /* cb_mmap */ 852 nodev, /* cb_segmap */ 853 nochpoll, /* cb_chpoll */ 854 ddi_prop_op, /* cb_prop_op */ 855 0, /* cb_stream */ 856 D_NEW | D_MP, /* cb_flag */ 857 CB_REV, /* cb_ops version? */ 858 nodev, /* cb_aread() */ 859 nodev, /* cb_awrite() */ 860 }; 861 862 /* device operations */ 863 static struct dev_ops agp_target_ops = { 864 DEVO_REV, /* devo_rev */ 865 0, /* devo_refcnt */ 866 agptarget_getinfo, /* devo_getinfo */ 867 nulldev, /* devo_identify */ 868 nulldev, /* devo_probe */ 869 agp_target_attach, /* devo_attach */ 870 agp_target_detach, /* devo_detach */ 871 nodev, /* devo_reset */ 872 &agp_target_cb_ops, /* devo_cb_ops */ 873 0, /* devo_bus_ops */ 874 0, /* devo_power */ 875 ddi_quiesce_not_needed, /* devo_quiesce */ 876 }; 877 878 static struct modldrv modldrv = { 879 &mod_driverops, 880 "AGP target driver", 881 &agp_target_ops, 882 }; 883 884 static struct modlinkage modlinkage = { 885 MODREV_1, /* MODREV_1 is indicated by manual */ 886 {&modldrv, NULL, NULL, NULL} 887 }; 888 889 int 890 _init(void) 891 { 892 int ret; 893 894 ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 895 sizeof (agp_target_softstate_t), 1); 896 897 if (ret) 898 goto err1; 899 900 if ((ret = mod_install(&modlinkage)) != 0) { 901 goto err2; 902 } 903 904 return (DDI_SUCCESS); 905 err2: 906 ddi_soft_state_fini(&agptarget_glob_soft_handle); 907 err1: 908 return (ret); 909 } 910 911 int 912 _info(struct modinfo *modinfop) 913 { 914 return (mod_info(&modlinkage, modinfop)); 915 } 916 917 int 918 _fini(void) 919 { 920 int ret; 921 922 if ((ret = mod_remove(&modlinkage)) == 0) { 923 ddi_soft_state_fini(&agptarget_glob_soft_handle); 924 } 925 return (ret); 926 } 927