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