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 }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 {INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, 364 GMS_SIZE(gms_965GM), gms_965GM} 365 }; 366 367 /* Returns the size (kbytes) of pre-allocated graphics memory */ 368 static size_t 369 i8xx_biosmem_detect(agp_target_softstate_t *softstate) 370 { 371 uint8_t memval; 372 size_t kbytes; 373 int i; 374 int num_modes; 375 376 kbytes = 0; 377 /* get GMS modes list entry */ 378 num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); 379 for (i = 0; i < num_modes; i++) { 380 if (gms_modes[i].gm_devid == softstate->tsoft_devid) 381 break; 382 } 383 if (i == num_modes) 384 goto done; 385 /* fetch the GMS value from DRAM controller */ 386 memval = pci_config_get8(softstate->tsoft_pcihdl, 387 gms_modes[i].gm_regoff); 388 TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval)); 389 memval = (memval & gms_modes[i].gm_mask) >> GMS_SHIFT; 390 /* assuming zero byte for 0 or "reserved" GMS values */ 391 if (memval == 0 || memval > gms_modes[i].gm_num) { 392 TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: " 393 "devid = %x, GMS = %x. assuming zero byte of " 394 "pre-allocated memory", gms_modes[i].gm_devid, memval)); 395 goto done; 396 } 397 memval--; /* use (GMS_value - 1) as index */ 398 kbytes = (gms_modes[i].gm_vec)[memval]; 399 400 done: 401 TARGETDB_PRINT2((CE_NOTE, 402 "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected", 403 kbytes)); 404 return (kbytes); 405 } 406 407 /*ARGSUSED*/ 408 static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 409 void *arg, void **resultp) 410 { 411 agp_target_softstate_t *st; 412 int instance, rval = DDI_FAILURE; 413 dev_t dev; 414 415 switch (cmd) { 416 case DDI_INFO_DEVT2DEVINFO: 417 dev = (dev_t)arg; 418 instance = DEV2INST(dev); 419 st = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 420 if (st != NULL) { 421 mutex_enter(&st->tsoft_lock); 422 *resultp = st->tsoft_dip; 423 mutex_exit(&st->tsoft_lock); 424 rval = DDI_SUCCESS; 425 } else 426 *resultp = NULL; 427 428 break; 429 case DDI_INFO_DEVT2INSTANCE: 430 dev = (dev_t)arg; 431 instance = DEV2INST(dev); 432 *resultp = (void *)(uintptr_t)instance; 433 rval = DDI_SUCCESS; 434 default: 435 break; 436 } 437 438 return (rval); 439 } 440 441 static int 442 agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 443 { 444 agp_target_softstate_t *softstate; 445 int instance; 446 int status; 447 448 if (cmd != DDI_ATTACH) 449 return (DDI_FAILURE); 450 451 instance = ddi_get_instance(dip); 452 453 if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) != 454 DDI_SUCCESS) 455 return (DDI_FAILURE); 456 457 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 458 mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); 459 softstate->tsoft_dip = dip; 460 status = pci_config_setup(dip, &softstate->tsoft_pcihdl); 461 if (status != DDI_SUCCESS) { 462 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 463 return (DDI_FAILURE); 464 } 465 466 softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, 467 PCI_CONF_VENID); 468 softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); 469 if (softstate->tsoft_acaptr == 0) { 470 /* Make a correction for some Intel chipsets */ 471 if (is_intel_br(softstate)) 472 softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; 473 else 474 return (DDI_FAILURE); 475 } 476 477 status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, 478 INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); 479 480 if (status != DDI_SUCCESS) { 481 pci_config_teardown(&softstate->tsoft_pcihdl); 482 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 483 return (DDI_FAILURE); 484 } 485 486 return (DDI_SUCCESS); 487 } 488 489 /*ARGSUSED*/ 490 static int 491 agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 492 { 493 int instance; 494 agp_target_softstate_t *softstate; 495 496 if (cmd != DDI_DETACH) 497 return (DDI_FAILURE); 498 499 instance = ddi_get_instance(dip); 500 501 softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); 502 503 ddi_remove_minor_node(dip, AGPTARGET_NAME); 504 pci_config_teardown(&softstate->tsoft_pcihdl); 505 mutex_destroy(&softstate->tsoft_lock); 506 ddi_soft_state_free(agptarget_glob_soft_handle, instance); 507 return (DDI_SUCCESS); 508 } 509 510 /*ARGSUSED*/ 511 static int 512 agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 513 cred_t *cred, int *rval) 514 { 515 int instance = DEV2INST(dev); 516 agp_target_softstate_t *st; 517 static char kernel_only[] = 518 "amd64_gart_ioctl: is a kernel only ioctl"; 519 520 if (!(mode & FKIOCTL)) { 521 TARGETDB_PRINT2((CE_CONT, kernel_only)); 522 return (ENXIO); 523 } 524 st = GETSOFTC(instance); 525 526 if (st == NULL) 527 return (ENXIO); 528 529 mutex_enter(&st->tsoft_lock); 530 531 switch (cmd) { 532 case CHIP_DETECT: 533 { 534 int type = 0; 535 536 if (is_intel_br(st)) 537 type = CHIP_IS_INTEL; 538 else if (is_64bit_aper(st)) 539 type = CHIP_IS_AMD; 540 else { 541 type = 0; 542 TARGETDB_PRINT2((CE_WARN, "Unknown bridge!")); 543 } 544 545 if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) { 546 mutex_exit(&st->tsoft_lock); 547 return (EFAULT); 548 } 549 550 break; 551 } 552 case I8XX_GET_PREALLOC_SIZE: 553 { 554 size_t prealloc_size; 555 556 if (!is_intel_br(st)) { 557 mutex_exit(&st->tsoft_lock); 558 return (EINVAL); 559 } 560 561 prealloc_size = i8xx_biosmem_detect(st); 562 if (ddi_copyout(&prealloc_size, (void *)data, 563 sizeof (size_t), mode)) { 564 mutex_exit(&st->tsoft_lock); 565 return (EFAULT); 566 } 567 568 break; 569 } 570 case AGP_TARGET_GETINFO: 571 { 572 i_agp_info_t info; 573 uint32_t value; 574 off_t cap; 575 576 ASSERT(st->tsoft_acaptr); 577 578 cap = st->tsoft_acaptr; 579 value = pci_config_get32(st->tsoft_pcihdl, cap); 580 info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf); 581 info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf); 582 info.iagp_devid = st->tsoft_devid; 583 info.iagp_mode = pci_config_get32(st->tsoft_pcihdl, 584 cap + AGP_CONF_STATUS); 585 info.iagp_aperbase = agp_target_get_apbase(st); 586 info.iagp_apersize = agp_target_get_apsize(st); 587 588 if (ddi_copyout(&info, (void *)data, 589 sizeof (i_agp_info_t), mode)) { 590 mutex_exit(&st->tsoft_lock); 591 return (EFAULT); 592 } 593 break; 594 595 } 596 /* 597 * This ioctl is only for Intel AGP chipsets. 598 * It is not necessary for the AMD8151 AGP bridge, because 599 * this register in the AMD8151 does not control any hardware. 600 * It is only provided for compatibility with an Intel AGP bridge. 601 * Please refer to the <<AMD8151 data sheet>> page 24, 602 * AGP device GART pointer. 603 */ 604 case AGP_TARGET_SET_GATTADDR: 605 { 606 uint32_t gartaddr; 607 608 if (ddi_copyin((void *)data, &gartaddr, 609 sizeof (uint32_t), mode)) { 610 mutex_exit(&st->tsoft_lock); 611 return (EFAULT); 612 } 613 614 agp_target_set_gartaddr(st, gartaddr); 615 break; 616 } 617 case AGP_TARGET_SETCMD: 618 { 619 uint32_t command; 620 621 if (ddi_copyin((void *)data, &command, 622 sizeof (uint32_t), mode)) { 623 mutex_exit(&st->tsoft_lock); 624 return (EFAULT); 625 } 626 627 ASSERT(st->tsoft_acaptr); 628 629 pci_config_put32(st->tsoft_pcihdl, 630 st->tsoft_acaptr + AGP_CONF_COMMAND, 631 command); 632 break; 633 634 } 635 case AGP_TARGET_FLUSH_GTLB: 636 { 637 uint16_t value; 638 639 ASSERT(st->tsoft_acaptr); 640 641 value = pci_config_get16(st->tsoft_pcihdl, 642 st->tsoft_acaptr + AGP_CONF_CONTROL); 643 value &= ~AGPCTRL_GTLBEN; 644 pci_config_put16(st->tsoft_pcihdl, 645 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 646 value |= AGPCTRL_GTLBEN; 647 pci_config_put16(st->tsoft_pcihdl, 648 st->tsoft_acaptr + AGP_CONF_CONTROL, value); 649 650 break; 651 } 652 case AGP_TARGET_CONFIGURE: 653 { 654 uint8_t value; 655 656 ASSERT(st->tsoft_acaptr); 657 658 /* 659 * In Intel agp bridges, agp misc register offset 660 * is indexed from 0 instead of capability register. 661 * AMD agp bridges have no such misc register 662 * to control the aperture access, and they have 663 * similar regsiters in CPU gart devices instead. 664 */ 665 666 if (is_intel_br(st)) { 667 value = pci_config_get8(st->tsoft_pcihdl, 668 st->tsoft_acaptr + AGP_CONF_MISC); 669 value |= AGP_MISC_APEN; 670 pci_config_put8(st->tsoft_pcihdl, 671 st->tsoft_acaptr + AGP_CONF_MISC, value); 672 } 673 break; 674 675 } 676 case AGP_TARGET_UNCONFIG: 677 { 678 uint32_t value1; 679 uint8_t value2; 680 681 ASSERT(st->tsoft_acaptr); 682 683 pci_config_put16(st->tsoft_pcihdl, 684 st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0); 685 686 if (is_intel_br(st)) { 687 value2 = pci_config_get8(st->tsoft_pcihdl, 688 st->tsoft_acaptr + AGP_CONF_MISC); 689 value2 &= ~AGP_MISC_APEN; 690 pci_config_put8(st->tsoft_pcihdl, 691 st->tsoft_acaptr + AGP_CONF_MISC, value2); 692 } 693 694 value1 = pci_config_get32(st->tsoft_pcihdl, 695 st->tsoft_acaptr + AGP_CONF_COMMAND); 696 value1 &= ~AGPCMD_AGPEN; 697 pci_config_put32(st->tsoft_pcihdl, 698 st->tsoft_acaptr + AGP_CONF_COMMAND, 699 value1); 700 701 pci_config_put32(st->tsoft_pcihdl, 702 st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0); 703 704 break; 705 } 706 707 default: 708 mutex_exit(&st->tsoft_lock); 709 return (ENXIO); 710 } /* end switch */ 711 712 mutex_exit(&st->tsoft_lock); 713 714 return (0); 715 } 716 717 /*ARGSUSED*/ 718 static int 719 agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred) 720 { 721 int instance = DEV2INST(*devp); 722 agp_target_softstate_t *st; 723 724 if (!(flag & FKLYR)) 725 return (ENXIO); 726 727 st = GETSOFTC(instance); 728 729 if (st == NULL) 730 return (ENXIO); 731 732 return (0); 733 } 734 735 /*ARGSUSED*/ 736 static int 737 agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred) 738 { 739 int instance = DEV2INST(dev); 740 agp_target_softstate_t *st; 741 742 st = GETSOFTC(instance); 743 744 if (st == NULL) 745 return (ENXIO); 746 747 return (0); 748 } 749 750 static struct cb_ops agp_target_cb_ops = { 751 agp_target_open, /* cb_open */ 752 agp_target_close, /* cb_close */ 753 nodev, /* cb_strategy */ 754 nodev, /* cb_print */ 755 nodev, /* cb_dump */ 756 nodev, /* cb_read() */ 757 nodev, /* cb_write() */ 758 agp_target_ioctl, /* cb_ioctl */ 759 nodev, /* cb_devmap */ 760 nodev, /* cb_mmap */ 761 nodev, /* cb_segmap */ 762 nochpoll, /* cb_chpoll */ 763 ddi_prop_op, /* cb_prop_op */ 764 0, /* cb_stream */ 765 D_NEW | D_MP, /* cb_flag */ 766 CB_REV, /* cb_ops version? */ 767 nodev, /* cb_aread() */ 768 nodev, /* cb_awrite() */ 769 }; 770 771 /* device operations */ 772 static struct dev_ops agp_target_ops = { 773 DEVO_REV, /* devo_rev */ 774 0, /* devo_refcnt */ 775 agptarget_getinfo, /* devo_getinfo */ 776 nulldev, /* devo_identify */ 777 nulldev, /* devo_probe */ 778 agp_target_attach, /* devo_attach */ 779 agp_target_detach, /* devo_detach */ 780 nodev, /* devo_reset */ 781 &agp_target_cb_ops, /* devo_cb_ops */ 782 0, /* devo_bus_ops */ 783 0, /* devo_power */ 784 }; 785 786 static struct modldrv modldrv = { 787 &mod_driverops, 788 "AGP target driver v%I%", 789 &agp_target_ops, 790 }; 791 792 static struct modlinkage modlinkage = { 793 MODREV_1, /* MODREV_1 is indicated by manual */ 794 {&modldrv, NULL, NULL, NULL} 795 }; 796 797 int 798 _init(void) 799 { 800 int ret; 801 802 ret = ddi_soft_state_init(&agptarget_glob_soft_handle, 803 sizeof (agp_target_softstate_t), 1); 804 805 if (ret) 806 goto err1; 807 808 if ((ret = mod_install(&modlinkage)) != 0) { 809 goto err2; 810 } 811 812 return (DDI_SUCCESS); 813 err2: 814 ddi_soft_state_fini(&agptarget_glob_soft_handle); 815 err1: 816 return (ret); 817 } 818 819 int 820 _info(struct modinfo *modinfop) 821 { 822 return (mod_info(&modlinkage, modinfop)); 823 } 824 825 int 826 _fini(void) 827 { 828 int ret; 829 830 if ((ret = mod_remove(&modlinkage)) == 0) { 831 ddi_soft_state_fini(&agptarget_glob_soft_handle); 832 } 833 return (ret); 834 } 835