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