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