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