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