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