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