xref: /haiku/src/add-ons/kernel/bus_managers/agp_gart/agp_gart.cpp (revision a5bf12376daeded4049521eb17a6cc41192250d9)
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 		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 			return B_NO_MEMORY;
548 	} else {
549 		// Allocate table to hold the pages
550 		memory->pages = (vm_page **)malloc(count * sizeof(vm_page *));
551 		if (memory->pages == NULL)
552 			return B_NO_MEMORY;
553 
554 		vm_page_reservation reservation;
555 		vm_page_reserve_pages(&reservation, count, VM_PRIORITY_SYSTEM);
556 		for (uint32 i = 0; i < count; i++) {
557 			memory->pages[i] = vm_page_allocate_page(&reservation,
558 				PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
559 		}
560 		vm_page_unreserve_pages(&reservation);
561 	}
562 
563 #ifdef DEBUG_PAGE_ACCESS
564 	memory->allocating_thread = find_thread(NULL);
565 #endif
566 
567 #else
568 	void *address;
569 	memory->area = create_area("GART memory", &address, B_ANY_KERNEL_ADDRESS,
570 		size, B_FULL_LOCK | ((flags & B_APERTURE_NEED_PHYSICAL) != 0
571 			? B_CONTIGUOUS : 0), 0);
572 	if (memory->area < B_OK)
573 		return B_NO_MEMORY;
574 #endif
575 
576 	memory->flags |= ALLOCATED_APERTURE;
577 	return B_OK;
578 }
579 
580 
581 status_t
582 Aperture::UnbindMemory(aperture_memory *memory)
583 {
584 	if ((memory->flags & BIND_APERTURE) == 0)
585 		return B_BAD_VALUE;
586 
587 	// We must not unbind reserved memory
588 	addr_t base = memory->base;
589 	size_t size = memory->size;
590 	if (_AdaptToReserved(base, size) && size == 0) {
591 		memory->flags &= ~BIND_APERTURE;
592 		return B_OK;
593 	}
594 
595 	addr_t start = base - Base();
596 	TRACE("unbind %ld bytes at %lx\n", size, start);
597 
598 	for (addr_t offset = 0; offset < memory->size; offset += B_PAGE_SIZE) {
599 		status_t status = fModule->unbind_page(fPrivateAperture, start + offset);
600 		if (status < B_OK)
601 			return status;
602 	}
603 
604 	memory->flags &= ~BIND_APERTURE;
605 	fModule->flush_tlbs(fPrivateAperture);
606 	return B_OK;
607 }
608 
609 
610 status_t
611 Aperture::BindMemory(aperture_memory *memory, addr_t address, size_t size)
612 {
613 	bool physical = false;
614 
615 	if ((memory->flags & ALLOCATED_APERTURE) != 0) {
616 		// We allocated this memory, get the base and size from there
617 #ifdef __HAIKU__
618 		size = memory->size;
619 		physical = true;
620 #else
621 		status_t status = get_area_base_and_size(memory->area, address, size);
622 		if (status < B_OK)
623 			return status;
624 #endif
625 	}
626 
627 	// We don't need to bind reserved memory
628 	addr_t base = memory->base;
629 	int32 offset;
630 	if (_AdaptToReserved(base, size, &offset)) {
631 		if (size == 0) {
632 			TRACE("reserved memory already bound\n");
633 			memory->flags |= BIND_APERTURE;
634 			return B_OK;
635 		}
636 
637 		address += offset;
638 	}
639 
640 	addr_t start = base - Base();
641 	TRACE("bind %ld bytes at %lx\n", size, base);
642 
643 	for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) {
644 		phys_addr_t physicalAddress = 0;
645 		status_t status;
646 
647 		if (!physical) {
648 			physical_entry entry;
649 			status = get_memory_map((void *)(address + offset), B_PAGE_SIZE,
650 				&entry, 1);
651 			if (status < B_OK)
652 				return status;
653 
654 			physicalAddress = entry.address;
655 		} else {
656 #ifdef __HAIKU__
657 			uint32 index = offset >> PAGE_SHIFT;
658 			vm_page *page;
659 			if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0)
660 				page = memory->page + index;
661 			else
662 				page = memory->pages[index];
663 
664 			physicalAddress
665 				= (phys_addr_t)page->physical_page_number << PAGE_SHIFT;
666 #endif
667 		}
668 
669 		status = fModule->bind_page(fPrivateAperture, start + offset,
670 			physicalAddress);
671 		if (status < B_OK)
672 			return status;
673 	}
674 
675 	memory->flags |= BIND_APERTURE;
676 	fModule->flush_tlbs(fPrivateAperture);
677 	return B_OK;
678 }
679 
680 
681 void
682 Aperture::_Free(aperture_memory *memory)
683 {
684 	if ((memory->flags & ALLOCATED_APERTURE) == 0)
685 		return;
686 
687 #if defined(__HAIKU__) && !defined(GART_TEST)
688 	// Remove the stolen area from the allocation
689 	size_t size = memory->size;
690 	addr_t reservedEnd = fInfo.base + fInfo.reserved_size;
691 	if (memory->base < reservedEnd)
692 		size -= reservedEnd - memory->base;
693 
694 	// Free previously allocated pages and page table
695 	uint32 count = size / B_PAGE_SIZE;
696 
697 	if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0) {
698 		vm_page *page = memory->page;
699 		for (uint32 i = 0; i < count; i++, page++) {
700 			DEBUG_PAGE_ACCESS_TRANSFER(page, memory->allocating_thread);
701 			vm_page_set_state(page, PAGE_STATE_FREE);
702 		}
703 
704 		memory->page = NULL;
705 	} else {
706 		for (uint32 i = 0; i < count; i++) {
707 			DEBUG_PAGE_ACCESS_TRANSFER(memory->pages[i],
708 				memory->allocating_thread);
709 			vm_page_set_state(memory->pages[i], PAGE_STATE_FREE);
710 		}
711 
712 		free(memory->pages);
713 		memory->pages = NULL;
714 	}
715 #else
716 	delete_area(memory->area);
717 	memory->area = -1;
718 #endif
719 
720 	memory->flags &= ~ALLOCATED_APERTURE;
721 }
722 
723 
724 void
725 Aperture::_Remove(aperture_memory *memory)
726 {
727 	aperture_memory *current = fFirstMemory, *last = NULL;
728 
729 	while (current != NULL) {
730 		if (memory == current) {
731 			if (last != NULL) {
732 				last->next = current->next;
733 			} else {
734 				fFirstMemory = current->next;
735 			}
736 			break;
737 		}
738 
739 		last = current;
740 		current = current->next;
741 	}
742 }
743 
744 
745 status_t
746 Aperture::_Insert(aperture_memory *memory, size_t size, size_t alignment,
747 	uint32 flags)
748 {
749 	aperture_memory *last = NULL;
750 	aperture_memory *next;
751 	bool foundSpot = false;
752 
753 	// do some sanity checking
754 	if (size == 0 || size > fInfo.size)
755 		return B_BAD_VALUE;
756 
757 	if (alignment < B_PAGE_SIZE)
758 		alignment = B_PAGE_SIZE;
759 
760 	addr_t start = fInfo.base;
761 	if ((flags & (B_APERTURE_NON_RESERVED | B_APERTURE_NEED_PHYSICAL)) != 0)
762 		start += fInfo.reserved_size;
763 
764 	start = ROUNDUP(start, alignment);
765 	if (start > fInfo.base - 1 + fInfo.size || start < fInfo.base)
766 		return B_NO_MEMORY;
767 
768 	// walk up to the spot where we should start searching
769 
770 	next = fFirstMemory;
771 	while (next) {
772 		if (next->base >= start + size) {
773 			// we have a winner
774 			break;
775 		}
776 		last = next;
777 		next = next->next;
778 	}
779 
780 	// find a big enough hole
781 	if (last == NULL) {
782 		// see if we can build it at the beginning of the virtual map
783 		if (next == NULL || (next->base >= ROUNDUP(start, alignment) + size)) {
784 			memory->base = ROUNDUP(start, alignment);
785 			foundSpot = true;
786 		} else {
787 			last = next;
788 			next = next->next;
789 		}
790 	}
791 
792 	if (!foundSpot) {
793 		// keep walking
794 		while (next != NULL) {
795 			if (next->base >= ROUNDUP(last->base + last->size, alignment) + size) {
796 				// we found a spot (it'll be filled up below)
797 				break;
798 			}
799 			last = next;
800 			next = next->next;
801 		}
802 
803 		if ((fInfo.base + (fInfo.size - 1)) >= (ROUNDUP(last->base + last->size,
804 				alignment) + (size - 1))) {
805 			// got a spot
806 			foundSpot = true;
807 			memory->base = ROUNDUP(last->base + last->size, alignment);
808 			if (memory->base < start)
809 				memory->base = start;
810 		}
811 
812 		if (!foundSpot)
813 			return B_NO_MEMORY;
814 	}
815 
816 	memory->size = size;
817 	if (last) {
818 		memory->next = last->next;
819 		last->next = memory;
820 	} else {
821 		memory->next = fFirstMemory;
822 		fFirstMemory = memory;
823 	}
824 
825 	return B_OK;
826 }
827 
828 
829 //	#pragma mark - AGP module interface
830 
831 
832 status_t
833 get_nth_agp_info(uint32 index, agp_info *info)
834 {
835 	TRACE("get_nth_agp_info(index %lu)\n", index);
836 
837 	if (index >= sDeviceCount)
838 		return B_BAD_VALUE;
839 
840 	// refresh from the contents of the AGP registers from this device
841 	sDeviceInfos[index].info.interface.status = get_pci_config(
842 		sDeviceInfos[index].info, AGP_STATUS(sDeviceInfos[index].address), 4);
843 	sDeviceInfos[index].info.interface.command = get_pci_config(
844 		sDeviceInfos[index].info, AGP_COMMAND(sDeviceInfos[index].address), 4);
845 
846 	*info = sDeviceInfos[index].info;
847 	return B_OK;
848 }
849 
850 
851 status_t
852 acquire_agp(void)
853 {
854 	if (atomic_or(&sAcquired, 1) == 1)
855 		return B_BUSY;
856 
857 	return B_OK;
858 }
859 
860 
861 void
862 release_agp(void)
863 {
864 	atomic_and(&sAcquired, 0);
865 }
866 
867 
868 uint32
869 set_agp_mode(uint32 command)
870 {
871 	TRACE("set_agp_mode(command %lx)\n", command);
872 
873 	if ((command & AGP_ENABLE) == 0) {
874 		set_pci_mode();
875 		return 0;
876 	}
877 
878 	// Make sure we accept all modes lower than requested one and we
879 	// reset reserved bits
880 	command = fix_rate_support(command);
881 
882 	// iterate through our device list to find the common capabilities supported
883 	for (uint32 index = 0; index < sDeviceCount; index++) {
884 		agp_device_info &deviceInfo = sDeviceInfos[index];
885 
886 		// Refresh from the contents of the AGP capability registers
887 		// (note: some graphics driver may have been tweaking, like nvidia)
888 		deviceInfo.info.interface.status = get_pci_config(deviceInfo.info,
889 			AGP_STATUS(deviceInfo.address), 4);
890 
891 		check_capabilities(deviceInfo, command);
892 	}
893 
894 	command = fix_rate_command(command);
895 	TRACE("set AGP command %lx on all capable devices.\n", command);
896 
897 	// The order of programming differs for enabling/disabling AGP mode
898 	// (see AGP specification)
899 
900 	// First program all bridges (master)
901 
902 	for (uint32 index = 0; index < sDeviceCount; index++) {
903 		agp_device_info &deviceInfo = sDeviceInfos[index];
904 		if (deviceInfo.info.class_base != PCI_bridge)
905 			continue;
906 
907 		set_agp_command(deviceInfo, command);
908 	}
909 
910 	// Wait 10mS for the bridges to recover (failsafe, see set_pci_mode()!)
911 	snooze(10000);
912 
913 	// Then all graphics cards (target)
914 
915 	for (uint32 index = 0; index < sDeviceCount; index++) {
916 		agp_device_info &deviceInfo = sDeviceInfos[index];
917 		if (deviceInfo.info.class_base != PCI_display)
918 			continue;
919 
920 		set_agp_command(deviceInfo, command);
921 	}
922 
923 	return command;
924 }
925 
926 
927 //	#pragma mark - GART module interface
928 
929 
930 static aperture_id
931 map_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
932 	addr_t *_apertureBase)
933 {
934 	void *iterator = open_module_list("busses/agp_gart");
935 	status_t status = B_ENTRY_NOT_FOUND;
936 	Aperture *aperture = NULL;
937 
938 	Autolock _(sLock);
939 
940 	while (true) {
941 		char name[256];
942 		size_t nameLength = sizeof(name);
943 		if (read_next_module_name(iterator, name, &nameLength) != B_OK)
944 			break;
945 
946 		agp_gart_bus_module_info *module;
947 		if (get_module(name, (module_info **)&module) == B_OK) {
948 			void *privateAperture;
949 			status = module->create_aperture(bus, device, function, size,
950 				&privateAperture);
951 			if (status < B_OK) {
952 				put_module(name);
953 				continue;
954 			}
955 
956 			aperture = new(std::nothrow) Aperture(module, privateAperture);
957 			status = aperture->InitCheck();
958 			if (status == B_OK) {
959 				if (_apertureBase != NULL)
960 					*_apertureBase = aperture->Base();
961 
962 				sApertureHashTable.Insert(aperture);
963 			} else {
964 				delete aperture;
965 				aperture = NULL;
966 			}
967 			break;
968 		}
969 	}
970 
971 	close_module_list(iterator);
972 	return aperture != NULL ? aperture->ID() : status;
973 }
974 
975 
976 static aperture_id
977 map_custom_aperture(gart_bus_module_info *module, addr_t *_apertureBase)
978 {
979 	return B_ERROR;
980 }
981 
982 
983 static status_t
984 unmap_aperture(aperture_id id)
985 {
986 	Autolock _(sLock);
987 	Aperture *aperture = sApertureHashTable.Lookup(id);
988 	if (aperture == NULL)
989 		return B_ENTRY_NOT_FOUND;
990 
991 	sApertureHashTable.Remove(aperture);
992 	delete aperture;
993 	return B_OK;
994 }
995 
996 
997 static status_t
998 get_aperture_info(aperture_id id, aperture_info *info)
999 {
1000 	Aperture *aperture = get_aperture(id);
1001 	if (aperture == NULL)
1002 		return B_ENTRY_NOT_FOUND;
1003 
1004 	Autolock _(aperture->Lock());
1005 	return aperture->GetInfo(info);
1006 }
1007 
1008 
1009 static status_t
1010 allocate_memory(aperture_id id, size_t size, size_t alignment, uint32 flags,
1011 	addr_t *_apertureBase, phys_addr_t *_physicalBase)
1012 {
1013 	if ((flags & ~APERTURE_PUBLIC_FLAGS_MASK) != 0 || _apertureBase == NULL)
1014 		return B_BAD_VALUE;
1015 
1016 	Aperture *aperture = get_aperture(id);
1017 	if (aperture == NULL)
1018 		return B_ENTRY_NOT_FOUND;
1019 
1020 	size = ROUNDUP(size, B_PAGE_SIZE);
1021 
1022 	Autolock _(aperture->Lock());
1023 
1024 	aperture_memory *memory = aperture->CreateMemory(size, alignment, flags);
1025 	if (memory == NULL)
1026 		return B_NO_MEMORY;
1027 
1028 	status_t status = aperture->AllocateMemory(memory, flags);
1029 	if (status == B_OK)
1030 		status = aperture->BindMemory(memory, 0, 0);
1031 	if (status < B_OK) {
1032 		aperture->DeleteMemory(memory);
1033 		return status;
1034 	}
1035 
1036 	if (_physicalBase != NULL && (flags & B_APERTURE_NEED_PHYSICAL) != 0) {
1037 #if defined(__HAIKU__) && !defined(GART_TEST)
1038 		*_physicalBase
1039 			= (phys_addr_t)memory->page->physical_page_number * B_PAGE_SIZE;
1040 #else
1041 		physical_entry entry;
1042 		status = get_memory_map((void *)memory->base, B_PAGE_SIZE, &entry, 1);
1043 		if (status < B_OK) {
1044 			aperture->DeleteMemory(memory);
1045 			return status;
1046 		}
1047 
1048 		*_physicalBase = entry.address;
1049 #endif
1050 	}
1051 
1052 	*_apertureBase = memory->base;
1053 	return B_OK;
1054 }
1055 
1056 
1057 static status_t
1058 free_memory(aperture_id id, addr_t base)
1059 {
1060 	Aperture *aperture = get_aperture(id);
1061 	if (aperture == NULL)
1062 		return B_ENTRY_NOT_FOUND;
1063 
1064 	Autolock _(aperture->Lock());
1065 	aperture_memory *memory = aperture->GetMemory(base);
1066 	if (memory == NULL)
1067 		return B_BAD_VALUE;
1068 
1069 	aperture->DeleteMemory(memory);
1070 	return B_OK;
1071 }
1072 
1073 
1074 static status_t
1075 reserve_aperture(aperture_id id, size_t size, addr_t *_apertureBase)
1076 {
1077 	Aperture *aperture = get_aperture(id);
1078 	if (aperture == NULL)
1079 		return B_ENTRY_NOT_FOUND;
1080 
1081 	return B_ERROR;
1082 }
1083 
1084 
1085 static status_t
1086 unreserve_aperture(aperture_id id, addr_t apertureBase)
1087 {
1088 	Aperture *aperture = get_aperture(id);
1089 	if (aperture == NULL)
1090 		return B_ENTRY_NOT_FOUND;
1091 
1092 	return B_ERROR;
1093 }
1094 
1095 
1096 static status_t
1097 bind_aperture(aperture_id id, area_id area, addr_t base, size_t size,
1098 	size_t alignment, addr_t reservedBase, addr_t *_apertureBase)
1099 {
1100 	Aperture *aperture = get_aperture(id);
1101 	if (aperture == NULL)
1102 		return B_ENTRY_NOT_FOUND;
1103 
1104 	if (area < 0) {
1105 		if (size == 0 || size > aperture->Size()
1106 			|| (base & (B_PAGE_SIZE - 1)) != 0
1107 			|| base == 0)
1108 			return B_BAD_VALUE;
1109 
1110 		size = ROUNDUP(size, B_PAGE_SIZE);
1111 	}
1112 
1113 	if (area >= 0) {
1114 		status_t status = get_area_base_and_size(area, base, size);
1115 		if (status < B_OK)
1116 			return status;
1117 	}
1118 
1119 	Autolock _(aperture->Lock());
1120 	aperture_memory *memory = NULL;
1121 	if (reservedBase != 0) {
1122 		// use reserved aperture to bind the pages
1123 		memory = aperture->GetMemory(reservedBase);
1124 		if (memory == NULL)
1125 			return B_BAD_VALUE;
1126 	} else {
1127 		// create new memory object
1128 		memory = aperture->CreateMemory(size, alignment,
1129 			B_APERTURE_NON_RESERVED);
1130 		if (memory == NULL)
1131 			return B_NO_MEMORY;
1132 	}
1133 
1134 	// just bind the physical pages backing the memory into the GART
1135 
1136 	status_t status = aperture->BindMemory(memory, base, size);
1137 	if (status < B_OK) {
1138 		if (reservedBase < 0)
1139 			aperture->DeleteMemory(memory);
1140 
1141 		return status;
1142 	}
1143 
1144 	if (_apertureBase != NULL)
1145 		*_apertureBase = memory->base;
1146 
1147 	return B_OK;
1148 }
1149 
1150 
1151 static status_t
1152 unbind_aperture(aperture_id id, addr_t base)
1153 {
1154 	Aperture *aperture = get_aperture(id);
1155 	if (aperture == NULL)
1156 		return B_ENTRY_NOT_FOUND;
1157 
1158 	Autolock _(aperture->Lock());
1159 	aperture_memory *memory = aperture->GetMemory(base);
1160 	if (memory == NULL || (memory->flags & BIND_APERTURE) == 0)
1161 		return B_BAD_VALUE;
1162 
1163 	if ((memory->flags & ALLOCATED_APERTURE) != 0)
1164 		panic("unbind memory %lx (%p) allocated by agp_gart.", base, memory);
1165 
1166 	status_t status = aperture->UnbindMemory(memory);
1167 	if (status < B_OK)
1168 		return status;
1169 
1170 	if ((memory->flags & RESERVED_APERTURE) == 0)
1171 		aperture->DeleteMemory(memory);
1172 
1173 	return B_OK;
1174 }
1175 
1176 
1177 //	#pragma mark -
1178 
1179 
1180 static status_t
1181 agp_init(void)
1182 {
1183 	TRACE("bus manager init\n");
1184 
1185 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI) != B_OK)
1186 		return B_ERROR;
1187 
1188 	uint32 cookie = 0;
1189 	sDeviceCount = 0;
1190 	pci_info info;
1191 	while (get_next_agp_device(&cookie, info, sDeviceInfos[sDeviceCount])
1192 			== B_OK) {
1193 		sDeviceCount++;
1194 	}
1195 
1196 	TRACE("found %ld AGP devices\n", sDeviceCount);
1197 
1198 	// Since there can be custom aperture modules (for memory management only),
1199 	// we always succeed if we could get the resources we need.
1200 
1201 	new(&sApertureHashTable) ApertureHashTable();
1202 	return init_lock(&sLock, "agp_gart");
1203 }
1204 
1205 
1206 void
1207 agp_uninit(void)
1208 {
1209 	TRACE("bus manager uninit\n");
1210 
1211 	ApertureHashTable::Iterator iterator = sApertureHashTable.GetIterator();
1212 	while (iterator.HasNext()) {
1213 		Aperture *aperture = iterator.Next();
1214 		sApertureHashTable.Remove(aperture);
1215 		delete aperture;
1216 	}
1217 
1218 	put_module(B_PCI_MODULE_NAME);
1219 }
1220 
1221 
1222 static int32
1223 agp_std_ops(int32 op, ...)
1224 {
1225 	switch (op) {
1226 		case B_MODULE_INIT:
1227 			return agp_init();
1228 		case B_MODULE_UNINIT:
1229 			agp_uninit();
1230 			return B_OK;
1231 	}
1232 
1233 	return B_BAD_VALUE;
1234 }
1235 
1236 
1237 static struct agp_gart_module_info sAGPModuleInfo = {
1238 	{
1239 		{
1240 			B_AGP_GART_MODULE_NAME,
1241 			B_KEEP_LOADED,		// Keep loaded, even if no driver requires it
1242 			agp_std_ops
1243 		},
1244 		NULL 					// the rescan function
1245 	},
1246 	get_nth_agp_info,
1247 	acquire_agp,
1248 	release_agp,
1249 	set_agp_mode,
1250 
1251 	map_aperture,
1252 	map_custom_aperture,
1253 	unmap_aperture,
1254 	get_aperture_info,
1255 	allocate_memory,
1256 	free_memory,
1257 	reserve_aperture,
1258 	unreserve_aperture,
1259 	bind_aperture,
1260 	unbind_aperture,
1261 };
1262 
1263 module_info *modules[] = {
1264 	(module_info *)&sAGPModuleInfo,
1265 	NULL
1266 };
1267