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