1 /* 2 * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2004-2006, Rudolf Cornelissen. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 // TODO: rethink the AGP interface for more than one bridge/device! 9 // (should be done with the new driver API then) 10 11 /* 12 Notes: 13 - currently we just setup all found devices with AGP interface to the same 14 highest common mode, we don't distinquish different AGP busses. 15 TODO: it might be a better idea to just setup one instead. 16 17 - AGP3 defines 'asynchronous request size' and 'calibration cycle' fields 18 in the status and command registers. Currently programming zero's which will 19 make it work, although further optimisation is possible. 20 21 - AGP3.5 also defines isochronous transfers which are not implemented here: 22 the hardware keeps them disabled by default. 23 */ 24 25 26 #include <AGP.h> 27 28 #include <stdlib.h> 29 30 #include <KernelExport.h> 31 #include <PCI.h> 32 33 #include <util/OpenHashTable.h> 34 #ifdef __HAIKU__ 35 # include <kernel/lock.h> 36 # include <vm/vm_page.h> 37 # include <vm/vm_types.h> 38 #endif 39 40 #include <lock.h> 41 42 #ifndef __HAIKU__ 43 # define PCI_capabilities_ptr 0x34 44 # define PCI_status_capabilities 0x0010 45 # define PCI_cap_id_agp 0x02 46 #endif 47 48 #define TRACE_AGP 49 #ifdef TRACE_AGP 50 # define TRACE(x...) dprintf("\33[36mAGP:\33[0m " x) 51 #else 52 # define TRACE(x...) ; 53 #endif 54 #define ERROR(x...) dprintf("\33[36mAGP:\33[0m " x) 55 56 57 #define MAX_DEVICES 8 58 59 #define AGP_ID(address) (address) 60 #define AGP_STATUS(address) (address + 4) 61 #define AGP_COMMAND(address) (address + 8) 62 63 /* read and write to PCI config space */ 64 #define get_pci_config(info, offset, size) \ 65 (sPCI->read_pci_config((info).bus, (info).device, (info).function, \ 66 (offset), (size))) 67 #define set_pci_config(info, offset, size, value) \ 68 (sPCI->write_pci_config((info).bus, (info).device, (info).function, \ 69 (offset), (size), (value))) 70 71 #define RESERVED_APERTURE 0x80000000 72 #define ALLOCATED_APERTURE 0x40000000 73 #define BIND_APERTURE 0x20000000 74 #define APERTURE_PUBLIC_FLAGS_MASK 0x0000ffff 75 76 struct aperture_memory { 77 aperture_memory *next; 78 aperture_memory *hash_link; 79 addr_t base; 80 size_t size; 81 uint32 flags; 82 #if defined(__HAIKU__) && !defined(GART_TEST) 83 union { 84 vm_page **pages; 85 vm_page *page; 86 }; 87 #ifdef DEBUG_PAGE_ACCESS 88 thread_id allocating_thread; 89 #endif 90 #else 91 area_id area; 92 #endif 93 }; 94 95 class Aperture; 96 97 class MemoryHashDefinition { 98 public: 99 typedef addr_t KeyType; 100 typedef aperture_memory ValueType; 101 102 MemoryHashDefinition(aperture_info &info) : fInfo(info) {} 103 104 size_t HashKey(const KeyType &base) const 105 { return (base - fInfo.base) / B_PAGE_SIZE; } 106 size_t Hash(aperture_memory *memory) const 107 { return (memory->base - fInfo.base) / B_PAGE_SIZE; } 108 bool Compare(const KeyType &base, aperture_memory *memory) const 109 { return base == memory->base; } 110 aperture_memory *&GetLink(aperture_memory *memory) const 111 { return memory->hash_link; } 112 113 private: 114 aperture_info &fInfo; 115 }; 116 117 typedef BOpenHashTable<MemoryHashDefinition> MemoryHashTable; 118 119 struct agp_device_info { 120 uint8 address; /* location of AGP interface in PCI capabilities */ 121 agp_info info; 122 }; 123 124 class Aperture { 125 public: 126 Aperture(agp_gart_bus_module_info *module, void *aperture); 127 ~Aperture(); 128 129 status_t InitCheck() const { return fLock.sem >= B_OK ? B_OK : fLock.sem; } 130 131 void DeleteMemory(aperture_memory *memory); 132 aperture_memory *CreateMemory(size_t size, size_t alignment, uint32 flags); 133 134 status_t AllocateMemory(aperture_memory *memory, uint32 flags); 135 136 status_t UnbindMemory(aperture_memory *memory); 137 status_t BindMemory(aperture_memory *memory, addr_t base, size_t size); 138 139 status_t GetInfo(aperture_info *info); 140 141 aperture_memory *GetMemory(addr_t base) { return fHashTable.Lookup(base); } 142 143 addr_t Base() const { return fInfo.base; } 144 addr_t Size() const { return fInfo.size; } 145 int32 ID() const { return fID; } 146 struct lock &Lock() { return fLock; } 147 148 private: 149 bool _AdaptToReserved(addr_t &base, size_t &size, int32 *_offset = NULL); 150 void _Free(aperture_memory *memory); 151 void _Remove(aperture_memory *memory); 152 status_t _Insert(aperture_memory *memory, size_t size, size_t alignment, 153 uint32 flags); 154 155 struct lock fLock; 156 agp_gart_bus_module_info *fModule; 157 int32 fID; 158 aperture_info fInfo; 159 MemoryHashTable fHashTable; 160 aperture_memory *fFirstMemory; 161 void *fPrivateAperture; 162 163 public: 164 Aperture *fNext; 165 }; 166 167 class ApertureHashDefinition { 168 public: 169 typedef int32 KeyType; 170 typedef Aperture ValueType; 171 172 size_t HashKey(const KeyType &id) const 173 { return id; } 174 size_t Hash(Aperture *aperture) const 175 { return aperture->ID(); } 176 bool Compare(const KeyType &id, Aperture *aperture) const 177 { return id == aperture->ID(); } 178 Aperture *&GetLink(Aperture *aperture) const 179 { return aperture->fNext; } 180 }; 181 182 typedef BOpenHashTable<ApertureHashDefinition> ApertureHashTable; 183 184 185 static agp_device_info sDeviceInfos[MAX_DEVICES]; 186 static uint32 sDeviceCount; 187 static pci_module_info *sPCI; 188 static int32 sAcquired; 189 static ApertureHashTable sApertureHashTable; 190 static int32 sNextApertureID; 191 static struct lock sLock; 192 193 194 // #pragma mark - private support functions 195 196 197 /*! Makes sure that all bits lower than the maximum supported rate is set. */ 198 static uint32 199 fix_rate_support(uint32 command) 200 { 201 if ((command & AGP_3_MODE) != 0) { 202 if ((command & AGP_3_8x) != 0) 203 command |= AGP_3_4x; 204 205 command &= ~AGP_RATE_MASK | AGP_3_8x | AGP_3_4x; 206 command |= AGP_SBA; 207 // SBA is required for AGP3 208 } else { 209 /* AGP 2.0 scheme applies */ 210 if ((command & AGP_2_4x) != 0) 211 command |= AGP_2_2x; 212 if ((command & AGP_2_2x) != 0) 213 command |= AGP_2_1x; 214 } 215 216 return command; 217 } 218 219 220 /*! Makes sure that only the highest rate bit is set. */ 221 static uint32 222 fix_rate_command(uint32 command) 223 { 224 if ((command & AGP_3_MODE) != 0) { 225 if ((command & AGP_3_8x) != 0) 226 command &= ~AGP_3_4x; 227 } else { 228 /* AGP 2.0 scheme applies */ 229 if ((command & AGP_2_4x) != 0) 230 command &= ~(AGP_2_2x | AGP_2_1x); 231 if ((command & AGP_2_2x) != 0) 232 command &= ~AGP_2_1x; 233 } 234 235 return command; 236 } 237 238 239 /*! Checks the capabilities of the device, and removes everything from 240 \a command that the device does not support. 241 */ 242 static void 243 check_capabilities(agp_device_info &deviceInfo, uint32 &command) 244 { 245 uint32 agpStatus = deviceInfo.info.interface.status; 246 if (deviceInfo.info.class_base == PCI_bridge) { 247 // make sure the AGP rate support mask is correct 248 // (ie. has the lower bits set) 249 agpStatus = fix_rate_support(agpStatus); 250 } 251 252 TRACE("device %u.%u.%u has AGP capabilities %" B_PRIx32 "\n", deviceInfo.info.bus, 253 deviceInfo.info.device, deviceInfo.info.function, agpStatus); 254 255 // block non-supported AGP modes 256 command &= (agpStatus & (AGP_3_MODE | AGP_RATE_MASK)) 257 | ~(AGP_3_MODE | AGP_RATE_MASK); 258 259 // If no AGP mode is supported at all, nothing remains: 260 // devices exist that have the AGP style connector with AGP style registers, 261 // but not the features! 262 // (confirmed Matrox Millenium II AGP for instance) 263 if ((agpStatus & AGP_RATE_MASK) == 0) 264 command = 0; 265 266 // block side band adressing if not supported 267 if ((agpStatus & AGP_SBA) == 0) 268 command &= ~AGP_SBA; 269 270 // block fast writes if not supported 271 if ((agpStatus & AGP_FAST_WRITE) == 0) 272 command &= ~AGP_FAST_WRITE; 273 274 // adjust maximum request depth to least depth supported 275 // note: this is writable only in the graphics card 276 uint8 requestDepth = ((agpStatus & AGP_REQUEST) >> AGP_REQUEST_SHIFT); 277 if (requestDepth < ((command & AGP_REQUEST) >> AGP_REQUEST_SHIFT)) { 278 command &= ~AGP_REQUEST; 279 command |= (requestDepth << AGP_REQUEST_SHIFT); 280 } 281 } 282 283 284 /*! Checks the PCI capabilities if the device is an AGP device 285 */ 286 static bool 287 is_agp_device(pci_info &info, uint8 *_address) 288 { 289 // Check if device implements a list of capabilities 290 if ((get_pci_config(info, PCI_status, 2) & PCI_status_capabilities) == 0) 291 return false; 292 293 // Get pointer to PCI capabilities list 294 // (AGP devices only, no need to take cardbus into account) 295 uint8 address = get_pci_config(info, PCI_capabilities_ptr, 1); 296 297 while (true) { 298 uint8 id = get_pci_config(info, address, 1); 299 uint8 next = get_pci_config(info, address + 1, 1) & ~0x3; 300 301 if (id == PCI_cap_id_agp) { 302 // is an AGP device 303 if (_address != NULL) 304 *_address = address; 305 return true; 306 } 307 if (next == 0) { 308 // end of list 309 break; 310 } 311 312 address = next; 313 } 314 315 return false; 316 } 317 318 319 static status_t 320 get_next_agp_device(uint32 *_cookie, pci_info &info, agp_device_info &device) 321 { 322 uint32 index = *_cookie; 323 324 // find devices 325 326 for (; sPCI->get_nth_pci_info(index, &info) == B_OK; index++) { 327 // is it a bridge or a graphics card? 328 if ((info.class_base != PCI_bridge || info.class_sub != PCI_host) 329 && info.class_base != PCI_display) 330 continue; 331 332 if (is_agp_device(info, &device.address)) { 333 device.info.vendor_id = info.vendor_id; 334 device.info.device_id = info.device_id; 335 device.info.bus = info.bus; 336 device.info.device = info.device; 337 device.info.function = info.function; 338 device.info.class_sub = info.class_sub; 339 device.info.class_base = info.class_base; 340 341 /* get the contents of the AGP registers from this device */ 342 device.info.interface.capability_id = get_pci_config(info, 343 AGP_ID(device.address), 4); 344 device.info.interface.status = get_pci_config(info, 345 AGP_STATUS(device.address), 4); 346 device.info.interface.command = get_pci_config(info, 347 AGP_COMMAND(device.address), 4); 348 349 *_cookie = index + 1; 350 return B_OK; 351 } 352 } 353 354 return B_ENTRY_NOT_FOUND; 355 } 356 357 358 static void 359 set_agp_command(agp_device_info &deviceInfo, uint32 command) 360 { 361 set_pci_config(deviceInfo.info, AGP_COMMAND(deviceInfo.address), 4, command); 362 deviceInfo.info.interface.command = get_pci_config(deviceInfo.info, 363 AGP_COMMAND(deviceInfo.address), 4); 364 } 365 366 367 static void 368 set_pci_mode() 369 { 370 TRACE("set PCI mode on all AGP capable devices.\n"); 371 372 // First program all graphics cards 373 374 for (uint32 index = 0; index < sDeviceCount; index++) { 375 agp_device_info &deviceInfo = sDeviceInfos[index]; 376 if (deviceInfo.info.class_base != PCI_display) 377 continue; 378 379 set_agp_command(deviceInfo, 0); 380 } 381 382 // Then program all bridges - it's the other around for AGP mode 383 384 for (uint32 index = 0; index < sDeviceCount; index++) { 385 agp_device_info &deviceInfo = sDeviceInfos[index]; 386 if (deviceInfo.info.class_base != PCI_bridge) 387 continue; 388 389 set_agp_command(deviceInfo, 0); 390 } 391 392 // Wait 10mS for the bridges to recover (failsafe!) 393 // Note: some SiS bridge chipsets apparantly require 5mS to recover 394 // or the master (graphics card) cannot be initialized correctly! 395 snooze(10000); 396 } 397 398 399 status_t 400 get_area_base_and_size(area_id area, addr_t &base, size_t &size) 401 { 402 area_info info; 403 status_t status = get_area_info(area, &info); 404 if (status < B_OK) 405 return status; 406 407 base = (addr_t)info.address; 408 size = info.size; 409 return B_OK; 410 } 411 412 413 Aperture * 414 get_aperture(aperture_id id) 415 { 416 Autolock _(sLock); 417 return sApertureHashTable.Lookup(id); 418 } 419 420 421 // #pragma mark - Aperture 422 423 424 Aperture::Aperture(agp_gart_bus_module_info *module, void *aperture) 425 : 426 fModule(module), 427 fHashTable(fInfo), 428 fFirstMemory(NULL), 429 fPrivateAperture(aperture) 430 { 431 fModule->get_aperture_info(fPrivateAperture, &fInfo); 432 fID = atomic_add(&sNextApertureID, 1); 433 init_lock(&fLock, "aperture"); 434 } 435 436 437 Aperture::~Aperture() 438 { 439 while (fFirstMemory != NULL) { 440 DeleteMemory(fFirstMemory); 441 } 442 443 fModule->delete_aperture(fPrivateAperture); 444 put_module(fModule->info.name); 445 } 446 447 448 status_t 449 Aperture::GetInfo(aperture_info *info) 450 { 451 if (info == NULL) 452 return B_BAD_VALUE; 453 454 *info = fInfo; 455 return B_OK; 456 } 457 458 459 void 460 Aperture::DeleteMemory(aperture_memory *memory) 461 { 462 TRACE("delete memory %p\n", memory); 463 464 UnbindMemory(memory); 465 _Free(memory); 466 _Remove(memory); 467 fHashTable.Remove(memory); 468 delete memory; 469 } 470 471 472 aperture_memory * 473 Aperture::CreateMemory(size_t size, size_t alignment, uint32 flags) 474 { 475 aperture_memory *memory = new(std::nothrow) aperture_memory; 476 if (memory == NULL) 477 return NULL; 478 479 status_t status = _Insert(memory, size, alignment, flags); 480 if (status < B_OK) { 481 ERROR("Aperture::CreateMemory(): did not find a free space large for " 482 "this memory object\n"); 483 delete memory; 484 return NULL; 485 } 486 487 TRACE("create memory %p, base %" B_PRIxADDR ", size %" B_PRIxSIZE 488 ", flags %" B_PRIx32 "\n", memory, memory->base, memory->size, flags); 489 490 memory->flags = flags; 491 #if defined(__HAIKU__) && !defined(GART_TEST) 492 memory->pages = NULL; 493 #else 494 memory->area = -1; 495 #endif 496 497 fHashTable.Insert(memory); 498 return memory; 499 } 500 501 502 bool 503 Aperture::_AdaptToReserved(addr_t &base, size_t &size, int32 *_offset) 504 { 505 addr_t reservedEnd = fInfo.base + fInfo.reserved_size; 506 if (reservedEnd <= base) 507 return false; 508 509 if (reservedEnd >= base + size) { 510 size = 0; 511 return true; 512 } 513 514 if (_offset != NULL) 515 *_offset = reservedEnd - base; 516 517 size -= reservedEnd - base; 518 base = reservedEnd; 519 return true; 520 } 521 522 523 status_t 524 Aperture::AllocateMemory(aperture_memory *memory, uint32 flags) 525 { 526 // We don't need to allocate reserved memory - it's 527 // already there for us to use 528 addr_t base = memory->base; 529 size_t size = memory->size; 530 if (_AdaptToReserved(base, size)) { 531 if (size == 0) { 532 TRACE("allocation is made of reserved memory\n"); 533 return B_OK; 534 } 535 536 memset((void *)memory->base, 0, memory->size - size); 537 } 538 TRACE("allocate %ld bytes out of %ld\n", size, memory->size); 539 540 #if defined(__HAIKU__) && !defined(GART_TEST) 541 uint32 count = size / B_PAGE_SIZE; 542 543 if ((flags & B_APERTURE_NEED_PHYSICAL) != 0) { 544 physical_address_restrictions restrictions = {}; 545 #if B_HAIKU_PHYSICAL_BITS > 32 546 restrictions.high_address = (phys_addr_t)1 << 32; 547 // TODO: Work-around until intel_gart can deal with physical 548 // addresses > 4 GB. 549 #endif 550 memory->page = vm_page_allocate_page_run( 551 PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR, count, &restrictions, 552 VM_PRIORITY_SYSTEM); 553 if (memory->page == NULL) { 554 ERROR("Aperture::AllocateMemory(): vm_page_allocate_page_run() " 555 "failed (with B_APERTURE_NEED_PHYSICAL)\n"); 556 return B_NO_MEMORY; 557 } 558 } else { 559 // Allocate table to hold the pages 560 memory->pages = (vm_page **)malloc(count * sizeof(vm_page *)); 561 if (memory->pages == NULL) 562 return B_NO_MEMORY; 563 564 #if B_HAIKU_PHYSICAL_BITS > 32 565 // TODO: Work-around until intel_gart can deal with physical 566 // addresses > 4 GB. 567 physical_address_restrictions restrictions = {}; 568 restrictions.high_address = (phys_addr_t)1 << 32; 569 vm_page* page = vm_page_allocate_page_run( 570 PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR, count, &restrictions, 571 VM_PRIORITY_SYSTEM); 572 if (page == NULL) { 573 ERROR("Aperture::AllocateMemory(): vm_page_allocate_page_run() " 574 "failed (without B_APERTURE_NEED_PHYSICAL)\n"); 575 return B_NO_MEMORY; 576 } 577 578 for (uint32 i = 0; i < count; i++) 579 memory->pages[i] = page + i; 580 #else 581 vm_page_reservation reservation; 582 vm_page_reserve_pages(&reservation, count, VM_PRIORITY_SYSTEM); 583 for (uint32 i = 0; i < count; i++) { 584 memory->pages[i] = vm_page_allocate_page(&reservation, 585 PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR); 586 } 587 vm_page_unreserve_pages(&reservation); 588 #endif 589 } 590 591 #ifdef DEBUG_PAGE_ACCESS 592 memory->allocating_thread = find_thread(NULL); 593 #endif 594 595 #else // !__HAIKU__ || GART_TEST 596 void *address; 597 memory->area = create_area("GART memory", &address, B_ANY_KERNEL_ADDRESS, 598 size, B_FULL_LOCK | ((flags & B_APERTURE_NEED_PHYSICAL) != 0 599 ? B_CONTIGUOUS : 0), 0); 600 if (memory->area < B_OK) { 601 ERROR("Aperture::AllocateMemory(): create_area() failed\n"); 602 return B_NO_MEMORY; 603 } 604 #endif 605 606 memory->flags |= ALLOCATED_APERTURE; 607 return B_OK; 608 } 609 610 611 status_t 612 Aperture::UnbindMemory(aperture_memory *memory) 613 { 614 if ((memory->flags & BIND_APERTURE) == 0) 615 return B_BAD_VALUE; 616 617 // We must not unbind reserved memory 618 addr_t base = memory->base; 619 size_t size = memory->size; 620 if (_AdaptToReserved(base, size) && size == 0) { 621 memory->flags &= ~BIND_APERTURE; 622 return B_OK; 623 } 624 625 addr_t start = base - Base(); 626 TRACE("unbind %ld bytes at %lx\n", size, start); 627 628 for (addr_t offset = 0; offset < memory->size; offset += B_PAGE_SIZE) { 629 status_t status = fModule->unbind_page(fPrivateAperture, start + offset); 630 if (status < B_OK) 631 return status; 632 } 633 634 memory->flags &= ~BIND_APERTURE; 635 fModule->flush_tlbs(fPrivateAperture); 636 return B_OK; 637 } 638 639 640 status_t 641 Aperture::BindMemory(aperture_memory *memory, addr_t address, size_t size) 642 { 643 bool physical = false; 644 645 if ((memory->flags & ALLOCATED_APERTURE) != 0) { 646 // We allocated this memory, get the base and size from there 647 #ifdef __HAIKU__ 648 size = memory->size; 649 physical = true; 650 #else 651 status_t status = get_area_base_and_size(memory->area, address, size); 652 if (status < B_OK) 653 return status; 654 #endif 655 } 656 657 // We don't need to bind reserved memory 658 addr_t base = memory->base; 659 int32 offset; 660 if (_AdaptToReserved(base, size, &offset)) { 661 if (size == 0) { 662 TRACE("reserved memory already bound\n"); 663 memory->flags |= BIND_APERTURE; 664 return B_OK; 665 } 666 667 address += offset; 668 } 669 670 addr_t start = base - Base(); 671 TRACE("bind %ld bytes at %lx\n", size, base); 672 673 for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) { 674 phys_addr_t physicalAddress = 0; 675 status_t status; 676 677 if (!physical) { 678 physical_entry entry; 679 status = get_memory_map((void *)(address + offset), B_PAGE_SIZE, 680 &entry, 1); 681 if (status < B_OK) { 682 ERROR("Aperture::BindMemory(): get_memory_map() failed\n"); 683 return status; 684 } 685 686 physicalAddress = entry.address; 687 } else { 688 #ifdef __HAIKU__ 689 uint32 index = offset >> PAGE_SHIFT; 690 vm_page *page; 691 if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0) 692 page = memory->page + index; 693 else 694 page = memory->pages[index]; 695 696 physicalAddress 697 = (phys_addr_t)page->physical_page_number << PAGE_SHIFT; 698 #endif 699 } 700 701 status = fModule->bind_page(fPrivateAperture, start + offset, 702 physicalAddress); 703 if (status < B_OK) { 704 ERROR("Aperture::BindMemory(): bind_page() failed\n"); 705 return status; 706 } 707 } 708 709 memory->flags |= BIND_APERTURE; 710 fModule->flush_tlbs(fPrivateAperture); 711 return B_OK; 712 } 713 714 715 void 716 Aperture::_Free(aperture_memory *memory) 717 { 718 if ((memory->flags & ALLOCATED_APERTURE) == 0) 719 return; 720 721 #if defined(__HAIKU__) && !defined(GART_TEST) 722 // Remove the stolen area from the allocation 723 size_t size = memory->size; 724 addr_t reservedEnd = fInfo.base + fInfo.reserved_size; 725 if (memory->base < reservedEnd) 726 size -= reservedEnd - memory->base; 727 728 // Free previously allocated pages and page table 729 uint32 count = size / B_PAGE_SIZE; 730 731 if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0) { 732 vm_page *page = memory->page; 733 for (uint32 i = 0; i < count; i++, page++) { 734 DEBUG_PAGE_ACCESS_TRANSFER(page, memory->allocating_thread); 735 vm_page_set_state(page, PAGE_STATE_FREE); 736 } 737 738 memory->page = NULL; 739 } else { 740 for (uint32 i = 0; i < count; i++) { 741 DEBUG_PAGE_ACCESS_TRANSFER(memory->pages[i], 742 memory->allocating_thread); 743 vm_page_set_state(memory->pages[i], PAGE_STATE_FREE); 744 } 745 746 free(memory->pages); 747 memory->pages = NULL; 748 } 749 #else 750 delete_area(memory->area); 751 memory->area = -1; 752 #endif 753 754 memory->flags &= ~ALLOCATED_APERTURE; 755 } 756 757 758 void 759 Aperture::_Remove(aperture_memory *memory) 760 { 761 aperture_memory *current = fFirstMemory, *last = NULL; 762 763 while (current != NULL) { 764 if (memory == current) { 765 if (last != NULL) { 766 last->next = current->next; 767 } else { 768 fFirstMemory = current->next; 769 } 770 break; 771 } 772 773 last = current; 774 current = current->next; 775 } 776 } 777 778 779 status_t 780 Aperture::_Insert(aperture_memory *memory, size_t size, size_t alignment, 781 uint32 flags) 782 { 783 aperture_memory *last = NULL; 784 aperture_memory *next; 785 bool foundSpot = false; 786 787 // do some sanity checking 788 if (size == 0 || size > fInfo.size) 789 return B_BAD_VALUE; 790 791 if (alignment < B_PAGE_SIZE) 792 alignment = B_PAGE_SIZE; 793 794 addr_t start = fInfo.base; 795 if ((flags & (B_APERTURE_NON_RESERVED | B_APERTURE_NEED_PHYSICAL)) != 0) 796 start += fInfo.reserved_size; 797 798 start = ROUNDUP(start, alignment); 799 if (start > fInfo.base - 1 + fInfo.size || start < fInfo.base) 800 return B_NO_MEMORY; 801 802 // walk up to the spot where we should start searching 803 804 next = fFirstMemory; 805 while (next) { 806 if (next->base >= start + size) { 807 // we have a winner 808 break; 809 } 810 last = next; 811 next = next->next; 812 } 813 814 // find a big enough hole 815 if (last == NULL) { 816 // see if we can build it at the beginning of the virtual map 817 if (next == NULL || (next->base >= ROUNDUP(start, alignment) + size)) { 818 memory->base = ROUNDUP(start, alignment); 819 foundSpot = true; 820 } else { 821 last = next; 822 next = next->next; 823 } 824 } 825 826 if (!foundSpot) { 827 // keep walking 828 while (next != NULL) { 829 if (next->base >= ROUNDUP(last->base + last->size, alignment) + size) { 830 // we found a spot (it'll be filled up below) 831 break; 832 } 833 last = next; 834 next = next->next; 835 } 836 837 if ((fInfo.base + (fInfo.size - 1)) >= (ROUNDUP(last->base + last->size, 838 alignment) + (size - 1))) { 839 // got a spot 840 foundSpot = true; 841 memory->base = ROUNDUP(last->base + last->size, alignment); 842 if (memory->base < start) 843 memory->base = start; 844 } 845 846 if (!foundSpot) 847 return B_NO_MEMORY; 848 } 849 850 memory->size = size; 851 if (last) { 852 memory->next = last->next; 853 last->next = memory; 854 } else { 855 memory->next = fFirstMemory; 856 fFirstMemory = memory; 857 } 858 859 return B_OK; 860 } 861 862 863 // #pragma mark - AGP module interface 864 865 866 status_t 867 get_nth_agp_info(uint32 index, agp_info *info) 868 { 869 TRACE("get_nth_agp_info(index %" B_PRIu32 ")\n", index); 870 871 if (index >= sDeviceCount) 872 return B_BAD_VALUE; 873 874 // refresh from the contents of the AGP registers from this device 875 sDeviceInfos[index].info.interface.status = get_pci_config( 876 sDeviceInfos[index].info, AGP_STATUS(sDeviceInfos[index].address), 4); 877 sDeviceInfos[index].info.interface.command = get_pci_config( 878 sDeviceInfos[index].info, AGP_COMMAND(sDeviceInfos[index].address), 4); 879 880 *info = sDeviceInfos[index].info; 881 return B_OK; 882 } 883 884 885 status_t 886 acquire_agp(void) 887 { 888 if (atomic_or(&sAcquired, 1) == 1) 889 return B_BUSY; 890 891 return B_OK; 892 } 893 894 895 void 896 release_agp(void) 897 { 898 atomic_and(&sAcquired, 0); 899 } 900 901 902 uint32 903 set_agp_mode(uint32 command) 904 { 905 TRACE("set_agp_mode(command %" B_PRIx32 ")\n", command); 906 907 if ((command & AGP_ENABLE) == 0) { 908 set_pci_mode(); 909 return 0; 910 } 911 912 // Make sure we accept all modes lower than requested one and we 913 // reset reserved bits 914 command = fix_rate_support(command); 915 916 // iterate through our device list to find the common capabilities supported 917 for (uint32 index = 0; index < sDeviceCount; index++) { 918 agp_device_info &deviceInfo = sDeviceInfos[index]; 919 920 // Refresh from the contents of the AGP capability registers 921 // (note: some graphics driver may have been tweaking, like nvidia) 922 deviceInfo.info.interface.status = get_pci_config(deviceInfo.info, 923 AGP_STATUS(deviceInfo.address), 4); 924 925 check_capabilities(deviceInfo, command); 926 } 927 928 command = fix_rate_command(command); 929 TRACE("set AGP command %" B_PRIx32 " on all capable devices.\n", command); 930 931 // The order of programming differs for enabling/disabling AGP mode 932 // (see AGP specification) 933 934 // First program all bridges (master) 935 936 for (uint32 index = 0; index < sDeviceCount; index++) { 937 agp_device_info &deviceInfo = sDeviceInfos[index]; 938 if (deviceInfo.info.class_base != PCI_bridge) 939 continue; 940 941 set_agp_command(deviceInfo, command); 942 } 943 944 // Wait 10mS for the bridges to recover (failsafe, see set_pci_mode()!) 945 snooze(10000); 946 947 // Then all graphics cards (target) 948 949 for (uint32 index = 0; index < sDeviceCount; index++) { 950 agp_device_info &deviceInfo = sDeviceInfos[index]; 951 if (deviceInfo.info.class_base != PCI_display) 952 continue; 953 954 set_agp_command(deviceInfo, command); 955 } 956 957 return command; 958 } 959 960 961 // #pragma mark - GART module interface 962 963 964 static aperture_id 965 map_aperture(uint8 bus, uint8 device, uint8 function, size_t size, 966 addr_t *_apertureBase) 967 { 968 void *iterator = open_module_list("busses/agp_gart"); 969 status_t status = B_ENTRY_NOT_FOUND; 970 Aperture *aperture = NULL; 971 972 Autolock _(sLock); 973 974 while (true) { 975 char name[256]; 976 size_t nameLength = sizeof(name); 977 if (read_next_module_name(iterator, name, &nameLength) != B_OK) 978 break; 979 980 agp_gart_bus_module_info *module; 981 if (get_module(name, (module_info **)&module) == B_OK) { 982 void *privateAperture; 983 status = module->create_aperture(bus, device, function, size, 984 &privateAperture); 985 if (status < B_OK) { 986 put_module(name); 987 continue; 988 } 989 990 aperture = new(std::nothrow) Aperture(module, privateAperture); 991 status = aperture->InitCheck(); 992 if (status == B_OK) { 993 if (_apertureBase != NULL) 994 *_apertureBase = aperture->Base(); 995 996 sApertureHashTable.Insert(aperture); 997 } else { 998 delete aperture; 999 aperture = NULL; 1000 } 1001 break; 1002 } 1003 } 1004 1005 close_module_list(iterator); 1006 return aperture != NULL ? aperture->ID() : status; 1007 } 1008 1009 1010 static aperture_id 1011 map_custom_aperture(gart_bus_module_info *module, addr_t *_apertureBase) 1012 { 1013 return B_ERROR; 1014 } 1015 1016 1017 static status_t 1018 unmap_aperture(aperture_id id) 1019 { 1020 Autolock _(sLock); 1021 Aperture *aperture = sApertureHashTable.Lookup(id); 1022 if (aperture == NULL) 1023 return B_ENTRY_NOT_FOUND; 1024 1025 sApertureHashTable.Remove(aperture); 1026 delete aperture; 1027 return B_OK; 1028 } 1029 1030 1031 static status_t 1032 get_aperture_info(aperture_id id, aperture_info *info) 1033 { 1034 Aperture *aperture = get_aperture(id); 1035 if (aperture == NULL) 1036 return B_ENTRY_NOT_FOUND; 1037 1038 Autolock _(aperture->Lock()); 1039 return aperture->GetInfo(info); 1040 } 1041 1042 1043 static status_t 1044 allocate_memory(aperture_id id, size_t size, size_t alignment, uint32 flags, 1045 addr_t *_apertureBase, phys_addr_t *_physicalBase) 1046 { 1047 if ((flags & ~APERTURE_PUBLIC_FLAGS_MASK) != 0 || _apertureBase == NULL) 1048 return B_BAD_VALUE; 1049 1050 Aperture *aperture = get_aperture(id); 1051 if (aperture == NULL) 1052 return B_ENTRY_NOT_FOUND; 1053 1054 size = ROUNDUP(size, B_PAGE_SIZE); 1055 1056 Autolock _(aperture->Lock()); 1057 1058 aperture_memory *memory = aperture->CreateMemory(size, alignment, flags); 1059 if (memory == NULL) 1060 return B_NO_MEMORY; 1061 1062 status_t status = aperture->AllocateMemory(memory, flags); 1063 if (status == B_OK) 1064 status = aperture->BindMemory(memory, 0, 0); 1065 if (status < B_OK) { 1066 aperture->DeleteMemory(memory); 1067 return status; 1068 } 1069 1070 if (_physicalBase != NULL && (flags & B_APERTURE_NEED_PHYSICAL) != 0) { 1071 #if defined(__HAIKU__) && !defined(GART_TEST) 1072 *_physicalBase 1073 = (phys_addr_t)memory->page->physical_page_number * B_PAGE_SIZE; 1074 #else 1075 physical_entry entry; 1076 status = get_memory_map((void *)memory->base, B_PAGE_SIZE, &entry, 1); 1077 if (status < B_OK) { 1078 aperture->DeleteMemory(memory); 1079 return status; 1080 } 1081 1082 *_physicalBase = entry.address; 1083 #endif 1084 } 1085 1086 *_apertureBase = memory->base; 1087 return B_OK; 1088 } 1089 1090 1091 static status_t 1092 free_memory(aperture_id id, addr_t base) 1093 { 1094 Aperture *aperture = get_aperture(id); 1095 if (aperture == NULL) 1096 return B_ENTRY_NOT_FOUND; 1097 1098 Autolock _(aperture->Lock()); 1099 aperture_memory *memory = aperture->GetMemory(base); 1100 if (memory == NULL) 1101 return B_BAD_VALUE; 1102 1103 aperture->DeleteMemory(memory); 1104 return B_OK; 1105 } 1106 1107 1108 static status_t 1109 reserve_aperture(aperture_id id, size_t size, addr_t *_apertureBase) 1110 { 1111 Aperture *aperture = get_aperture(id); 1112 if (aperture == NULL) 1113 return B_ENTRY_NOT_FOUND; 1114 1115 return B_ERROR; 1116 } 1117 1118 1119 static status_t 1120 unreserve_aperture(aperture_id id, addr_t apertureBase) 1121 { 1122 Aperture *aperture = get_aperture(id); 1123 if (aperture == NULL) 1124 return B_ENTRY_NOT_FOUND; 1125 1126 return B_ERROR; 1127 } 1128 1129 1130 static status_t 1131 bind_aperture(aperture_id id, area_id area, addr_t base, size_t size, 1132 size_t alignment, addr_t reservedBase, addr_t *_apertureBase) 1133 { 1134 Aperture *aperture = get_aperture(id); 1135 if (aperture == NULL) 1136 return B_ENTRY_NOT_FOUND; 1137 1138 if (area < 0) { 1139 if (size == 0 || size > aperture->Size() 1140 || (base & (B_PAGE_SIZE - 1)) != 0 1141 || base == 0) 1142 return B_BAD_VALUE; 1143 1144 size = ROUNDUP(size, B_PAGE_SIZE); 1145 } 1146 1147 if (area >= 0) { 1148 status_t status = get_area_base_and_size(area, base, size); 1149 if (status < B_OK) 1150 return status; 1151 } 1152 1153 Autolock _(aperture->Lock()); 1154 aperture_memory *memory = NULL; 1155 if (reservedBase != 0) { 1156 // use reserved aperture to bind the pages 1157 memory = aperture->GetMemory(reservedBase); 1158 if (memory == NULL) 1159 return B_BAD_VALUE; 1160 } else { 1161 // create new memory object 1162 memory = aperture->CreateMemory(size, alignment, 1163 B_APERTURE_NON_RESERVED); 1164 if (memory == NULL) 1165 return B_NO_MEMORY; 1166 } 1167 1168 // just bind the physical pages backing the memory into the GART 1169 1170 status_t status = aperture->BindMemory(memory, base, size); 1171 if (status < B_OK) { 1172 if (reservedBase < 0) 1173 aperture->DeleteMemory(memory); 1174 1175 return status; 1176 } 1177 1178 if (_apertureBase != NULL) 1179 *_apertureBase = memory->base; 1180 1181 return B_OK; 1182 } 1183 1184 1185 static status_t 1186 unbind_aperture(aperture_id id, addr_t base) 1187 { 1188 Aperture *aperture = get_aperture(id); 1189 if (aperture == NULL) 1190 return B_ENTRY_NOT_FOUND; 1191 1192 Autolock _(aperture->Lock()); 1193 aperture_memory *memory = aperture->GetMemory(base); 1194 if (memory == NULL || (memory->flags & BIND_APERTURE) == 0) 1195 return B_BAD_VALUE; 1196 1197 if ((memory->flags & ALLOCATED_APERTURE) != 0) 1198 panic("unbind memory %lx (%p) allocated by agp_gart.", base, memory); 1199 1200 status_t status = aperture->UnbindMemory(memory); 1201 if (status < B_OK) 1202 return status; 1203 1204 if ((memory->flags & RESERVED_APERTURE) == 0) 1205 aperture->DeleteMemory(memory); 1206 1207 return B_OK; 1208 } 1209 1210 1211 // #pragma mark - 1212 1213 1214 static status_t 1215 agp_init(void) 1216 { 1217 TRACE("bus manager init\n"); 1218 1219 if (get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI) != B_OK) 1220 return B_ERROR; 1221 1222 uint32 cookie = 0; 1223 sDeviceCount = 0; 1224 pci_info info; 1225 while (get_next_agp_device(&cookie, info, sDeviceInfos[sDeviceCount]) 1226 == B_OK) { 1227 sDeviceCount++; 1228 } 1229 1230 TRACE("found %" B_PRId32 " AGP devices\n", sDeviceCount); 1231 1232 // Since there can be custom aperture modules (for memory management only), 1233 // we always succeed if we could get the resources we need. 1234 1235 new(&sApertureHashTable) ApertureHashTable(); 1236 return init_lock(&sLock, "agp_gart"); 1237 } 1238 1239 1240 void 1241 agp_uninit(void) 1242 { 1243 TRACE("bus manager uninit\n"); 1244 1245 ApertureHashTable::Iterator iterator = sApertureHashTable.GetIterator(); 1246 while (iterator.HasNext()) { 1247 Aperture *aperture = iterator.Next(); 1248 sApertureHashTable.Remove(aperture); 1249 delete aperture; 1250 } 1251 1252 put_module(B_PCI_MODULE_NAME); 1253 } 1254 1255 1256 static int32 1257 agp_std_ops(int32 op, ...) 1258 { 1259 switch (op) { 1260 case B_MODULE_INIT: 1261 return agp_init(); 1262 case B_MODULE_UNINIT: 1263 agp_uninit(); 1264 return B_OK; 1265 } 1266 1267 return B_BAD_VALUE; 1268 } 1269 1270 1271 static struct agp_gart_module_info sAGPModuleInfo = { 1272 { 1273 { 1274 B_AGP_GART_MODULE_NAME, 1275 B_KEEP_LOADED, // Keep loaded, even if no driver requires it 1276 agp_std_ops 1277 }, 1278 NULL // the rescan function 1279 }, 1280 get_nth_agp_info, 1281 acquire_agp, 1282 release_agp, 1283 set_agp_mode, 1284 1285 map_aperture, 1286 map_custom_aperture, 1287 unmap_aperture, 1288 get_aperture_info, 1289 allocate_memory, 1290 free_memory, 1291 reserve_aperture, 1292 unreserve_aperture, 1293 bind_aperture, 1294 unbind_aperture, 1295 }; 1296 1297 module_info *modules[] = { 1298 (module_info *)&sAGPModuleInfo, 1299 NULL 1300 }; 1301