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