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