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 /* 30 * Misc module for AGP master device support 31 */ 32 33 #include <sys/modctl.h> 34 #include <sys/pci.h> 35 #include <sys/stat.h> 36 #include <sys/file.h> 37 #include <sys/types.h> 38 #include <sys/dditypes.h> 39 #include <sys/sunddi.h> 40 #include <sys/agpgart.h> 41 #include <sys/agp/agpdefs.h> 42 #include <sys/agp/agpmaster_io.h> 43 44 #define PGTBL_CTL 0x2020 /* Page table control register */ 45 #define I8XX_FB_BAR 1 46 #define I8XX_MMIO_BAR 2 47 #define I8XX_PTE_OFFSET 0x10000 48 #define I915_MMADR 1 /* mem-mapped registers BAR */ 49 #define I915_GMADR 3 /* graphics mem BAR */ 50 #define I915_GTTADDR 4 /* GTT BAR */ 51 #define I965_GTTMMADR 1 /* mem-mapped registers BAR + GTT */ 52 #define I965_GMADR 2 /* graphics mem BAR */ 53 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */ 54 #define I965_GTT_OFFSET 0x80000 55 #define GTT_SIZE_MASK 0xe 56 #define GTT_512KB (0 << 1) 57 #define GTT_256KB (1 << 1) 58 #define GTT_128KB (2 << 1) 59 60 #define MMIO_BASE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_base 61 #define MMIO_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_handle 62 #define GTT_ADDR(x) (x)->agpm_data.agpm_gtt.gtt_addr 63 #define APER_BASE(x) (x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase 64 65 #define AGPM_WRITE(x, off, val) \ 66 ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val)); 67 68 #define AGPM_READ(x, off) \ 69 ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off))); 70 71 #ifdef DEBUG 72 #define CONFIRM(value) ASSERT(value) 73 #else 74 #define CONFIRM(value) if (!(value)) return (EINVAL) 75 #endif 76 77 int agpm_debug = 0; 78 #define AGPM_DEBUG(args) if (agpm_debug >= 1) cmn_err args 79 80 /* 81 * Whether it is a Intel integrated graphics card 82 */ 83 #define IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \ 84 (agpmaster->agpm_dev_type == DEVICE_IS_I830)) 85 86 87 /* Intel 915 and 945 series */ 88 #define IS_INTEL_915(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_915) || \ 89 (agpmaster->agpm_id == INTEL_IGD_915GM) || \ 90 (agpmaster->agpm_id == INTEL_IGD_945) || \ 91 (agpmaster->agpm_id == INTEL_IGD_945GM)) 92 93 /* Intel 965 series */ 94 #define IS_INTEL_965(agpmaster) ((agpmaster->agpm_id == INTEL_IGD_946GZ) || \ 95 (agpmaster->agpm_id == INTEL_IGD_965G1) || \ 96 (agpmaster->agpm_id == INTEL_IGD_965Q) || \ 97 (agpmaster->agpm_id == INTEL_IGD_965G2) || \ 98 (agpmaster->agpm_id == INTEL_IGD_965GM) || \ 99 (agpmaster->agpm_id == INTEL_IGD_965GME)) 100 101 static struct modlmisc modlmisc = { 102 &mod_miscops, "AGP master interfaces v%I%" 103 }; 104 105 static struct modlinkage modlinkage = { 106 MODREV_1, (void *)&modlmisc, NULL 107 }; 108 109 static ddi_device_acc_attr_t i8xx_dev_access = { 110 DDI_DEVICE_ATTR_V0, 111 DDI_NEVERSWAP_ACC, 112 DDI_STRICTORDER_ACC 113 }; 114 115 static off_t agpmaster_cap_find(ddi_acc_handle_t); 116 static int detect_i8xx_device(agp_master_softc_t *); 117 static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t); 118 static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t); 119 static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t); 120 121 int 122 _init(void) 123 { 124 int err; 125 126 if ((err = mod_install(&modlinkage)) != 0) 127 return (err); 128 129 return (0); 130 } 131 132 int 133 _fini(void) 134 { 135 int err; 136 137 if ((err = mod_remove(&modlinkage)) != 0) 138 return (err); 139 140 return (0); 141 } 142 143 int 144 _info(struct modinfo *modinfop) 145 { 146 return (mod_info(&modlinkage, modinfop)); 147 } 148 149 /* 150 * Minor node is not removed here, since the caller (xx_attach) is 151 * responsible for removing all nodes. 152 */ 153 void 154 agpmaster_detach(agp_master_softc_t **master_softcp) 155 { 156 agp_master_softc_t *master_softc; 157 158 ASSERT(master_softcp); 159 master_softc = *master_softcp; 160 161 /* intel integrated device */ 162 if (IS_IGD(master_softc)) { 163 if (MMIO_HANDLE(master_softc) != NULL) { 164 ddi_regs_map_free(&MMIO_HANDLE(master_softc)); 165 } 166 } 167 168 kmem_free(master_softc, sizeof (agp_master_softc_t)); 169 master_softc = NULL; 170 171 return; 172 173 } 174 175 /* 176 * 965 has a fixed GTT table size (512KB), so check to see the actual aperture 177 * size. Aperture size = GTT table size * 1024. 178 */ 179 static off_t 180 i965_apersize(agp_master_softc_t *agpmaster) 181 { 182 off_t apersize; 183 184 apersize = AGPM_READ(agpmaster, PGTBL_CTL); 185 AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize)); 186 switch (apersize & GTT_SIZE_MASK) { 187 case GTT_512KB: 188 apersize = 512; 189 break; 190 case GTT_256KB: 191 apersize = 256; 192 break; 193 case GTT_128KB: 194 apersize = 128; 195 break; 196 default: 197 AGPM_DEBUG((CE_WARN, 198 "i965_apersize: invalid GTT size in PGTBL_CTL")); 199 } 200 apersize = MB2BYTES(apersize); 201 return (apersize); 202 } 203 204 #define CHECK_STATUS(status) \ 205 if (status != DDI_SUCCESS) { \ 206 AGPM_DEBUG((CE_WARN, \ 207 "set_gtt_mmio: regs_map_setup error")); \ 208 return (-1); \ 209 } 210 /* 211 * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid 212 * according to chipset. 213 */ 214 static int 215 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster, ddi_acc_handle_t 216 pci_acc_hdl) 217 { 218 off_t apersize; 219 uint32_t value; 220 off_t conf_off; /* offset in PCI conf space for aperture */ 221 int status; 222 223 if (IS_INTEL_965(agpmaster)) { 224 status = ddi_regs_map_setup(devi, I965_GTTMMADR, 225 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 226 &MMIO_HANDLE(agpmaster)); 227 CHECK_STATUS(status); 228 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I965_GTT_OFFSET; 229 230 conf_off = I915_CONF_GMADR; 231 apersize = i965_apersize(agpmaster); 232 /* make this the last line, to clear follow-up status check */ 233 status = DDI_SUCCESS; 234 235 } else if (IS_INTEL_915(agpmaster)) { 236 status = ddi_regs_map_setup(devi, I915_GTTADDR, 237 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access, 238 &MMIO_HANDLE(agpmaster)); 239 CHECK_STATUS(status); 240 241 status = ddi_regs_map_setup(devi, I915_MMADR, 242 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 243 &MMIO_HANDLE(agpmaster)); 244 CHECK_STATUS(status); 245 246 conf_off = I915_CONF_GMADR; 247 status = ddi_dev_regsize(devi, I915_GMADR, &apersize); 248 } else { 249 /* I8XX series */ 250 status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR, 251 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access, 252 &MMIO_HANDLE(agpmaster)); 253 CHECK_STATUS(status); 254 255 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET; 256 conf_off = I8XX_CONF_GMADR; 257 status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize); 258 CHECK_STATUS(status); 259 } 260 261 /* 262 * if memory size is smaller than a certain value, it means 263 * the register set number for graphics memory range might 264 * be wrong 265 */ 266 if (status != DDI_SUCCESS || apersize < 0x400000) { 267 AGPM_DEBUG((CE_WARN, 268 "set_gtt_mmio: ddi_dev_regsize error")); 269 return (-1); 270 } 271 272 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = 273 BYTES2MB(apersize); 274 275 /* get GTT base */ 276 value = pci_config_get32(pci_acc_hdl, conf_off); 277 278 APER_BASE(agpmaster) = value & GTT_BASE_MASK; 279 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid = 280 agpmaster->agpm_id; 281 AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = %x, apersize = %lx, " 282 "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize, 283 (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster))); 284 return (0); 285 } 286 287 /* 288 * Try to initialize agp master. 289 * 0 is returned if the device is successfully initialized. AGP master soft 290 * state is returned in master_softcp if needed. 291 * Otherwise -1 is returned and *master_softcp is set to NULL. 292 */ 293 int 294 agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp, 295 ddi_acc_handle_t pci_acc_hdl, minor_t minor) 296 { 297 int instance; 298 int status; 299 agp_master_softc_t *agpmaster; 300 char buf[80]; 301 302 303 ASSERT(pci_acc_hdl); 304 *master_softcp = NULL; 305 agpmaster = (agp_master_softc_t *) 306 kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP); 307 308 agpmaster->agpm_id = 309 pci_config_get32(pci_acc_hdl, PCI_CONF_VENID); 310 agpmaster->agpm_acc_hdl = pci_acc_hdl; 311 312 if (!detect_i8xx_device(agpmaster)) { 313 /* Intel 8XX, 915, 945 and 965 series */ 314 if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0) 315 goto fail; 316 } else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) { 317 /* non IGD or AGP devices, AMD64 gart */ 318 AGPM_DEBUG((CE_WARN, 319 "agpmaster_attach: neither IGD or AGP devices exists")); 320 agpmaster_detach(&agpmaster); 321 return (0); 322 } 323 324 /* create minor node for IGD or AGP device */ 325 instance = ddi_get_instance(devi); 326 327 (void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance); 328 status = ddi_create_minor_node(devi, buf, S_IFCHR, minor, 329 DDI_NT_AGP_MASTER, 0); 330 331 if (status != DDI_SUCCESS) { 332 AGPM_DEBUG((CE_WARN, 333 "agpmaster_attach: create agpmaster node failed")); 334 goto fail; 335 } 336 337 *master_softcp = agpmaster; 338 return (0); 339 fail: 340 agpmaster_detach(&agpmaster); 341 return (-1); 342 } 343 344 /* 345 * Currently, it handles ioctl requests related with agp master device for 346 * layered driver (agpgart) only. 347 */ 348 /*ARGSUSED*/ 349 int 350 agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred, 351 int *rval, agp_master_softc_t *softc) 352 { 353 uint32_t base; 354 uint32_t addr; 355 igd_gtt_seg_t seg; 356 agp_info_t info; 357 uint32_t value; 358 off_t cap; 359 uint32_t command; 360 static char kernel_only[] = 361 "agpmaster_ioctl: %s is a kernel only ioctl"; 362 363 CONFIRM(softc); 364 365 switch (cmd) { 366 case DEVICE_DETECT: 367 if (!(mode & FKIOCTL)) { 368 AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT")); 369 return (ENXIO); 370 } 371 372 if (ddi_copyout(&softc->agpm_dev_type, 373 (void *)data, sizeof (int), mode)) 374 return (EFAULT); 375 break; 376 case AGP_MASTER_SETCMD: 377 if (!(mode & FKIOCTL)) { 378 AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD")); 379 return (ENXIO); 380 } 381 382 CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP); 383 CONFIRM(softc->agpm_data.agpm_acaptr); 384 385 if (ddi_copyin((void *)data, &command, 386 sizeof (uint32_t), mode)) 387 return (EFAULT); 388 389 pci_config_put32(softc->agpm_acc_hdl, 390 softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND, 391 command); 392 break; 393 case AGP_MASTER_GETINFO: 394 if (!(mode & FKIOCTL)) { 395 AGPM_DEBUG((CE_CONT, kernel_only, 396 "AGP_MASTER_GETINFO")); 397 return (ENXIO); 398 } 399 400 CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP); 401 CONFIRM(softc->agpm_data.agpm_acaptr); 402 403 cap = softc->agpm_data.agpm_acaptr; 404 value = pci_config_get32(softc->agpm_acc_hdl, cap); 405 info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf); 406 info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf); 407 info.agpi_devid = softc->agpm_id; 408 info.agpi_mode = pci_config_get32( 409 softc->agpm_acc_hdl, cap + AGP_CONF_STATUS); 410 411 if (ddi_copyout(&info, (void *)data, 412 sizeof (agp_info_t), mode)) 413 return (EFAULT); 414 break; 415 case I810_SET_GTT_BASE: 416 if (!(mode & FKIOCTL)) { 417 AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR")); 418 return (ENXIO); 419 } 420 421 CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810); 422 423 if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode)) 424 return (EFAULT); 425 426 /* enables page table */ 427 addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID; 428 429 AGPM_WRITE(softc, PGTBL_CTL, addr); 430 break; 431 case I8XX_GET_INFO: 432 if (!(mode & FKIOCTL)) { 433 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO")); 434 return (ENXIO); 435 } 436 437 CONFIRM(IS_IGD(softc)); 438 439 if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info, 440 (void *)data, sizeof (igd_info_t), mode)) 441 return (EFAULT); 442 break; 443 case I8XX_ADD2GTT: 444 if (!(mode & FKIOCTL)) { 445 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT")); 446 return (ENXIO); 447 } 448 449 CONFIRM(IS_IGD(softc)); 450 451 if (ddi_copyin((void *)data, &seg, 452 sizeof (igd_gtt_seg_t), mode)) 453 return (EFAULT); 454 455 if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg)) 456 return (EINVAL); 457 break; 458 case I8XX_REM_GTT: 459 if (!(mode & FKIOCTL)) { 460 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT")); 461 return (ENXIO); 462 } 463 464 CONFIRM(IS_IGD(softc)); 465 466 if (ddi_copyin((void *)data, &seg, 467 sizeof (igd_gtt_seg_t), mode)) 468 return (EFAULT); 469 470 i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg); 471 break; 472 case I8XX_UNCONFIG: 473 if (!(mode & FKIOCTL)) { 474 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG")); 475 return (ENXIO); 476 } 477 478 CONFIRM(IS_IGD(softc)); 479 480 if (softc->agpm_dev_type == DEVICE_IS_I810) 481 AGPM_WRITE(softc, PGTBL_CTL, 0); 482 /* 483 * may need to clear all gtt entries here for i830 series, 484 * but may not be necessary 485 */ 486 break; 487 } 488 return (0); 489 } 490 491 /* 492 * If AGP cap pointer is successfully found, none-zero value is returned. 493 * Otherwise 0 is returned. 494 */ 495 static off_t 496 agpmaster_cap_find(ddi_acc_handle_t acc_handle) 497 { 498 off_t nextcap; 499 uint32_t ncapid; 500 uint8_t value; 501 502 /* check if this device supports capibility pointer */ 503 value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT) 504 & PCI_CONF_CAP_MASK); 505 506 if (!value) 507 return (0); 508 /* get the offset of the first capability pointer from CAPPTR */ 509 nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR)); 510 511 /* check AGP capability from the first capability pointer */ 512 while (nextcap) { 513 ncapid = pci_config_get32(acc_handle, nextcap); 514 if ((ncapid & PCI_CONF_CAPID_MASK) 515 == AGP_CAP_ID) /* find AGP cap */ 516 break; 517 518 nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 519 } 520 521 return (nextcap); 522 523 } 524 525 /* 526 * If i8xx device is successfully detected, 0 is returned. 527 * Otherwise -1 is returned. 528 */ 529 static int 530 detect_i8xx_device(agp_master_softc_t *master_softc) 531 { 532 533 switch (master_softc->agpm_id) { 534 case INTEL_IGD_810: 535 case INTEL_IGD_810DC: 536 case INTEL_IGD_810E: 537 case INTEL_IGD_815: 538 master_softc->agpm_dev_type = DEVICE_IS_I810; 539 break; 540 case INTEL_IGD_830M: 541 case INTEL_IGD_845G: 542 case INTEL_IGD_855GM: 543 case INTEL_IGD_865G: 544 case INTEL_IGD_915: 545 case INTEL_IGD_915GM: 546 case INTEL_IGD_945: 547 case INTEL_IGD_945GM: 548 case INTEL_IGD_946GZ: 549 case INTEL_IGD_965G1: 550 case INTEL_IGD_965G2: 551 case INTEL_IGD_965GM: 552 case INTEL_IGD_965GME: 553 case INTEL_IGD_965Q: 554 master_softc->agpm_dev_type = DEVICE_IS_I830; 555 break; 556 default: /* unknown id */ 557 return (-1); 558 } 559 560 return (0); 561 } 562 563 /* 564 * If agp master is succssfully detected, 0 is returned. 565 * Otherwise -1 is returned. 566 */ 567 static int 568 detect_agp_devcice(agp_master_softc_t *master_softc, 569 ddi_acc_handle_t acc_handle) 570 { 571 off_t cap; 572 573 cap = agpmaster_cap_find(acc_handle); 574 if (cap) { 575 master_softc->agpm_dev_type = DEVICE_IS_AGP; 576 master_softc->agpm_data.agpm_acaptr = cap; 577 return (0); 578 } else { 579 return (-1); 580 } 581 582 } 583 584 /* 585 * Please refer to GART and GTT entry format table in agpdefs.h for 586 * intel GTT entry format. 587 */ 588 static int 589 phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry) 590 { 591 uint32_t value; 592 593 switch (type) { 594 case AGP_PHYSICAL: 595 case AGP_NORMAL: 596 value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID; 597 break; 598 default: 599 return (-1); 600 } 601 602 *entry = value; 603 604 return (0); 605 } 606 607 static int 608 i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 609 { 610 int i; 611 uint32_t *paddr; 612 uint32_t entry; 613 uint32_t maxpages; 614 615 maxpages = gtt->gtt_info.igd_apersize; 616 maxpages = GTT_MB_TO_PAGES(maxpages); 617 618 paddr = seg.igs_phyaddr; 619 620 /* check if gtt max page number is reached */ 621 if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 622 return (-1); 623 624 paddr = seg.igs_phyaddr; 625 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); 626 i++, paddr++) { 627 if (phys2entry(seg.igs_type, *paddr, &entry)) 628 return (-1); 629 ddi_put32(gtt->gtt_mmio_handle, 630 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 631 entry); 632 } 633 634 return (0); 635 } 636 637 static void 638 i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 639 { 640 int i; 641 uint32_t maxpages; 642 643 maxpages = gtt->gtt_info.igd_apersize; 644 maxpages = GTT_MB_TO_PAGES(maxpages); 645 646 /* check if gtt max page number is reached */ 647 if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 648 return; 649 650 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) { 651 ddi_put32(gtt->gtt_mmio_handle, 652 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 0); 653 } 654 } 655