xref: /haiku/src/add-ons/kernel/bus_managers/agp_gart/agp_gart.cpp (revision 3c6e2dd68577c34d93e17f19711f6245bf6d0915)
1 /*
2  * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2004-2006, Rudolf Cornelissen. All rights reserved.
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 // TODO: rethink the AGP interface for more than one bridge/device!
9 //	(should be done with the new driver API then)
10 
11 /*
12 	Notes:
13 	- currently we just setup all found devices with AGP interface to the same
14 	highest common mode, we don't distinquish different AGP busses.
15 	TODO: it might be a better idea to just setup one instead.
16 
17 	- AGP3 defines 'asynchronous request size' and 'calibration cycle' fields
18 	in the status and command registers. Currently programming zero's which will
19 	make it work, although further optimisation is possible.
20 
21 	- AGP3.5 also defines isochronous transfers which are not implemented here:
22 	the hardware keeps them disabled by default.
23 */
24 
25 
26 #include <AGP.h>
27 
28 #include <stdlib.h>
29 
30 #include <KernelExport.h>
31 #include <PCI.h>
32 
33 #include <util/OpenHashTable.h>
34 #ifdef __HAIKU__
35 #	include <kernel/lock.h>
36 #	include <vm/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 		memory->page = vm_page_allocate_page_run(PAGE_STATE_CLEAR, 0, count);
543 		if (memory->page == NULL)
544 			return B_NO_MEMORY;
545 	} else {
546 		// Allocate table to hold the pages
547 		memory->pages = (vm_page **)malloc(count * sizeof(vm_page *));
548 		if (memory->pages == NULL)
549 			return B_NO_MEMORY;
550 
551 		vm_page_reserve_pages(count);
552 		for (uint32 i = 0; i < count; i++)
553 			memory->pages[i] = vm_page_allocate_page(PAGE_STATE_CLEAR);
554 		vm_page_unreserve_pages(count);
555 	}
556 
557 #ifdef DEBUG_PAGE_ACCESS
558 	memory->allocating_thread = find_thread(NULL);
559 #endif
560 
561 #else
562 	void *address;
563 	memory->area = create_area("GART memory", &address, B_ANY_KERNEL_ADDRESS,
564 		size, B_FULL_LOCK | ((flags & B_APERTURE_NEED_PHYSICAL) != 0
565 			? B_CONTIGUOUS : 0), 0);
566 	if (memory->area < B_OK)
567 		return B_NO_MEMORY;
568 #endif
569 
570 	memory->flags |= ALLOCATED_APERTURE;
571 	return B_OK;
572 }
573 
574 
575 status_t
576 Aperture::UnbindMemory(aperture_memory *memory)
577 {
578 	if ((memory->flags & BIND_APERTURE) == 0)
579 		return B_BAD_VALUE;
580 
581 	// We must not unbind reserved memory
582 	addr_t base = memory->base;
583 	size_t size = memory->size;
584 	if (_AdaptToReserved(base, size) && size == 0) {
585 		memory->flags &= ~BIND_APERTURE;
586 		return B_OK;
587 	}
588 
589 	addr_t start = base - Base();
590 	TRACE("unbind %ld bytes at %lx\n", size, start);
591 
592 	for (addr_t offset = 0; offset < memory->size; offset += B_PAGE_SIZE) {
593 		status_t status = fModule->unbind_page(fPrivateAperture, start + offset);
594 		if (status < B_OK)
595 			return status;
596 	}
597 
598 	memory->flags &= ~BIND_APERTURE;
599 	fModule->flush_tlbs(fPrivateAperture);
600 	return B_OK;
601 }
602 
603 
604 status_t
605 Aperture::BindMemory(aperture_memory *memory, addr_t address, size_t size)
606 {
607 	bool physical = false;
608 
609 	if ((memory->flags & ALLOCATED_APERTURE) != 0) {
610 		// We allocated this memory, get the base and size from there
611 #ifdef __HAIKU__
612 		size = memory->size;
613 		physical = true;
614 #else
615 		status_t status = get_area_base_and_size(memory->area, address, size);
616 		if (status < B_OK)
617 			return status;
618 #endif
619 	}
620 
621 	// We don't need to bind reserved memory
622 	addr_t base = memory->base;
623 	int32 offset;
624 	if (_AdaptToReserved(base, size, &offset)) {
625 		if (size == 0) {
626 			TRACE("reserved memory already bound\n");
627 			memory->flags |= BIND_APERTURE;
628 			return B_OK;
629 		}
630 
631 		address += offset;
632 	}
633 
634 	addr_t start = base - Base();
635 	TRACE("bind %ld bytes at %lx\n", size, base);
636 
637 	for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) {
638 		addr_t physicalAddress = 0;
639 		status_t status;
640 
641 		if (!physical) {
642 			physical_entry entry;
643 			status = get_memory_map((void *)(address + offset), B_PAGE_SIZE,
644 				&entry, 1);
645 			if (status < B_OK)
646 				return status;
647 
648 			physicalAddress = (addr_t)entry.address;
649 		} else {
650 #ifdef __HAIKU__
651 			uint32 index = offset >> PAGE_SHIFT;
652 			vm_page *page;
653 			if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0)
654 				page = memory->page + index;
655 			else
656 				page = memory->pages[index];
657 
658 			physicalAddress = page->physical_page_number << PAGE_SHIFT;
659 #endif
660 		}
661 
662 		status = fModule->bind_page(fPrivateAperture, start + offset,
663 			physicalAddress);
664 		if (status < B_OK)
665 			return status;
666 	}
667 
668 	memory->flags |= BIND_APERTURE;
669 	fModule->flush_tlbs(fPrivateAperture);
670 	return B_OK;
671 }
672 
673 
674 void
675 Aperture::_Free(aperture_memory *memory)
676 {
677 	if ((memory->flags & ALLOCATED_APERTURE) == 0)
678 		return;
679 
680 #if defined(__HAIKU__) && !defined(GART_TEST)
681 	// Remove the stolen area from the allocation
682 	size_t size = memory->size;
683 	addr_t reservedEnd = fInfo.base + fInfo.reserved_size;
684 	if (memory->base < reservedEnd)
685 		size -= reservedEnd - memory->base;
686 
687 	// Free previously allocated pages and page table
688 	uint32 count = size / B_PAGE_SIZE;
689 
690 	if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0) {
691 		vm_page *page = memory->page;
692 		for (uint32 i = 0; i < count; i++, page++) {
693 			DEBUG_PAGE_ACCESS_TRANSFER(page, memory->allocating_thread);
694 			vm_page_set_state(page, PAGE_STATE_FREE);
695 		}
696 
697 		memory->page = NULL;
698 	} else {
699 		for (uint32 i = 0; i < count; i++) {
700 			DEBUG_PAGE_ACCESS_TRANSFER(memory->pages[i],
701 				memory->allocating_thread);
702 			vm_page_set_state(memory->pages[i], PAGE_STATE_FREE);
703 		}
704 
705 		free(memory->pages);
706 		memory->pages = NULL;
707 	}
708 #else
709 	delete_area(memory->area);
710 	memory->area = -1;
711 #endif
712 
713 	memory->flags &= ~ALLOCATED_APERTURE;
714 }
715 
716 
717 void
718 Aperture::_Remove(aperture_memory *memory)
719 {
720 	aperture_memory *current = fFirstMemory, *last = NULL;
721 
722 	while (current != NULL) {
723 		if (memory == current) {
724 			if (last != NULL) {
725 				last->next = current->next;
726 			} else {
727 				fFirstMemory = current->next;
728 			}
729 			break;
730 		}
731 
732 		last = current;
733 		current = current->next;
734 	}
735 }
736 
737 
738 status_t
739 Aperture::_Insert(aperture_memory *memory, size_t size, size_t alignment,
740 	uint32 flags)
741 {
742 	aperture_memory *last = NULL;
743 	aperture_memory *next;
744 	bool foundSpot = false;
745 
746 	// do some sanity checking
747 	if (size == 0 || size > fInfo.size)
748 		return B_BAD_VALUE;
749 
750 	if (alignment < B_PAGE_SIZE)
751 		alignment = B_PAGE_SIZE;
752 
753 	addr_t start = fInfo.base;
754 	if ((flags & (B_APERTURE_NON_RESERVED | B_APERTURE_NEED_PHYSICAL)) != 0)
755 		start += fInfo.reserved_size;
756 
757 	start = ROUNDUP(start, alignment);
758 	if (start > fInfo.base - 1 + fInfo.size || start < fInfo.base)
759 		return B_NO_MEMORY;
760 
761 	// walk up to the spot where we should start searching
762 
763 	next = fFirstMemory;
764 	while (next) {
765 		if (next->base >= start + size) {
766 			// we have a winner
767 			break;
768 		}
769 		last = next;
770 		next = next->next;
771 	}
772 
773 	// find a big enough hole
774 	if (last == NULL) {
775 		// see if we can build it at the beginning of the virtual map
776 		if (next == NULL || (next->base >= ROUNDUP(start, alignment) + size)) {
777 			memory->base = ROUNDUP(start, alignment);
778 			foundSpot = true;
779 		} else {
780 			last = next;
781 			next = next->next;
782 		}
783 	}
784 
785 	if (!foundSpot) {
786 		// keep walking
787 		while (next != NULL) {
788 			if (next->base >= ROUNDUP(last->base + last->size, alignment) + size) {
789 				// we found a spot (it'll be filled up below)
790 				break;
791 			}
792 			last = next;
793 			next = next->next;
794 		}
795 
796 		if ((fInfo.base + (fInfo.size - 1)) >= (ROUNDUP(last->base + last->size,
797 				alignment) + (size - 1))) {
798 			// got a spot
799 			foundSpot = true;
800 			memory->base = ROUNDUP(last->base + last->size, alignment);
801 			if (memory->base < start)
802 				memory->base = start;
803 		}
804 
805 		if (!foundSpot)
806 			return B_NO_MEMORY;
807 	}
808 
809 	memory->size = size;
810 	if (last) {
811 		memory->next = last->next;
812 		last->next = memory;
813 	} else {
814 		memory->next = fFirstMemory;
815 		fFirstMemory = memory;
816 	}
817 
818 	return B_OK;
819 }
820 
821 
822 //	#pragma mark - AGP module interface
823 
824 
825 status_t
826 get_nth_agp_info(uint32 index, agp_info *info)
827 {
828 	TRACE("get_nth_agp_info(index %lu)\n", index);
829 
830 	if (index >= sDeviceCount)
831 		return B_BAD_VALUE;
832 
833 	// refresh from the contents of the AGP registers from this device
834 	sDeviceInfos[index].info.interface.status = get_pci_config(
835 		sDeviceInfos[index].info, AGP_STATUS(sDeviceInfos[index].address), 4);
836 	sDeviceInfos[index].info.interface.command = get_pci_config(
837 		sDeviceInfos[index].info, AGP_COMMAND(sDeviceInfos[index].address), 4);
838 
839 	*info = sDeviceInfos[index].info;
840 	return B_OK;
841 }
842 
843 
844 status_t
845 acquire_agp(void)
846 {
847 	if (atomic_or(&sAcquired, 1) == 1)
848 		return B_BUSY;
849 
850 	return B_OK;
851 }
852 
853 
854 void
855 release_agp(void)
856 {
857 	atomic_and(&sAcquired, 0);
858 }
859 
860 
861 uint32
862 set_agp_mode(uint32 command)
863 {
864 	TRACE("set_agp_mode(command %lx)\n", command);
865 
866 	if ((command & AGP_ENABLE) == 0) {
867 		set_pci_mode();
868 		return 0;
869 	}
870 
871 	// Make sure we accept all modes lower than requested one and we
872 	// reset reserved bits
873 	command = fix_rate_support(command);
874 
875 	// iterate through our device list to find the common capabilities supported
876 	for (uint32 index = 0; index < sDeviceCount; index++) {
877 		agp_device_info &deviceInfo = sDeviceInfos[index];
878 
879 		// Refresh from the contents of the AGP capability registers
880 		// (note: some graphics driver may have been tweaking, like nvidia)
881 		deviceInfo.info.interface.status = get_pci_config(deviceInfo.info,
882 			AGP_STATUS(deviceInfo.address), 4);
883 
884 		check_capabilities(deviceInfo, command);
885 	}
886 
887 	command = fix_rate_command(command);
888 	TRACE("set AGP command %lx on all capable devices.\n", command);
889 
890 	// The order of programming differs for enabling/disabling AGP mode
891 	// (see AGP specification)
892 
893 	// First program all bridges (master)
894 
895 	for (uint32 index = 0; index < sDeviceCount; index++) {
896 		agp_device_info &deviceInfo = sDeviceInfos[index];
897 		if (deviceInfo.info.class_base != PCI_bridge)
898 			continue;
899 
900 		set_agp_command(deviceInfo, command);
901 	}
902 
903 	// Wait 10mS for the bridges to recover (failsafe, see set_pci_mode()!)
904 	snooze(10000);
905 
906 	// Then all graphics cards (target)
907 
908 	for (uint32 index = 0; index < sDeviceCount; index++) {
909 		agp_device_info &deviceInfo = sDeviceInfos[index];
910 		if (deviceInfo.info.class_base != PCI_display)
911 			continue;
912 
913 		set_agp_command(deviceInfo, command);
914 	}
915 
916 	return command;
917 }
918 
919 
920 //	#pragma mark - GART module interface
921 
922 
923 static aperture_id
924 map_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
925 	addr_t *_apertureBase)
926 {
927 	void *iterator = open_module_list("busses/agp_gart");
928 	status_t status = B_ENTRY_NOT_FOUND;
929 	Aperture *aperture = NULL;
930 
931 	Autolock _(sLock);
932 
933 	while (true) {
934 		char name[256];
935 		size_t nameLength = sizeof(name);
936 		if (read_next_module_name(iterator, name, &nameLength) != B_OK)
937 			break;
938 
939 		agp_gart_bus_module_info *module;
940 		if (get_module(name, (module_info **)&module) == B_OK) {
941 			void *privateAperture;
942 			status = module->create_aperture(bus, device, function, size,
943 				&privateAperture);
944 			if (status < B_OK) {
945 				put_module(name);
946 				continue;
947 			}
948 
949 			aperture = new(std::nothrow) Aperture(module, privateAperture);
950 			status = aperture->InitCheck();
951 			if (status == B_OK) {
952 				if (_apertureBase != NULL)
953 					*_apertureBase = aperture->Base();
954 
955 				sApertureHashTable.Insert(aperture);
956 			} else {
957 				delete aperture;
958 				aperture = NULL;
959 			}
960 			break;
961 		}
962 	}
963 
964 	close_module_list(iterator);
965 	return aperture != NULL ? aperture->ID() : status;
966 }
967 
968 
969 static aperture_id
970 map_custom_aperture(gart_bus_module_info *module, addr_t *_apertureBase)
971 {
972 	return B_ERROR;
973 }
974 
975 
976 static status_t
977 unmap_aperture(aperture_id id)
978 {
979 	Autolock _(sLock);
980 	Aperture *aperture = sApertureHashTable.Lookup(id);
981 	if (aperture == NULL)
982 		return B_ENTRY_NOT_FOUND;
983 
984 	sApertureHashTable.Remove(aperture);
985 	delete aperture;
986 	return B_OK;
987 }
988 
989 
990 static status_t
991 get_aperture_info(aperture_id id, aperture_info *info)
992 {
993 	Aperture *aperture = get_aperture(id);
994 	if (aperture == NULL)
995 		return B_ENTRY_NOT_FOUND;
996 
997 	Autolock _(aperture->Lock());
998 	return aperture->GetInfo(info);
999 }
1000 
1001 
1002 static status_t
1003 allocate_memory(aperture_id id, size_t size, size_t alignment, uint32 flags,
1004 	addr_t *_apertureBase, addr_t *_physicalBase)
1005 {
1006 	if ((flags & ~APERTURE_PUBLIC_FLAGS_MASK) != 0 || _apertureBase == NULL)
1007 		return B_BAD_VALUE;
1008 
1009 	Aperture *aperture = get_aperture(id);
1010 	if (aperture == NULL)
1011 		return B_ENTRY_NOT_FOUND;
1012 
1013 	size = ROUNDUP(size, B_PAGE_SIZE);
1014 
1015 	Autolock _(aperture->Lock());
1016 
1017 	aperture_memory *memory = aperture->CreateMemory(size, alignment, flags);
1018 	if (memory == NULL)
1019 		return B_NO_MEMORY;
1020 
1021 	status_t status = aperture->AllocateMemory(memory, flags);
1022 	if (status == B_OK)
1023 		status = aperture->BindMemory(memory, 0, 0);
1024 	if (status < B_OK) {
1025 		aperture->DeleteMemory(memory);
1026 		return status;
1027 	}
1028 
1029 	if (_physicalBase != NULL && (flags & B_APERTURE_NEED_PHYSICAL) != 0) {
1030 #if defined(__HAIKU__) && !defined(GART_TEST)
1031 		*_physicalBase = memory->page->physical_page_number * B_PAGE_SIZE;
1032 #else
1033 		physical_entry entry;
1034 		status = get_memory_map((void *)memory->base, B_PAGE_SIZE, &entry, 1);
1035 		if (status < B_OK) {
1036 			aperture->DeleteMemory(memory);
1037 			return status;
1038 		}
1039 
1040 		*_physicalBase = (addr_t)entry.address;
1041 #endif
1042 	}
1043 
1044 	*_apertureBase = memory->base;
1045 	return B_OK;
1046 }
1047 
1048 
1049 static status_t
1050 free_memory(aperture_id id, addr_t base)
1051 {
1052 	Aperture *aperture = get_aperture(id);
1053 	if (aperture == NULL)
1054 		return B_ENTRY_NOT_FOUND;
1055 
1056 	Autolock _(aperture->Lock());
1057 	aperture_memory *memory = aperture->GetMemory(base);
1058 	if (memory == NULL)
1059 		return B_BAD_VALUE;
1060 
1061 	aperture->DeleteMemory(memory);
1062 	return B_OK;
1063 }
1064 
1065 
1066 static status_t
1067 reserve_aperture(aperture_id id, size_t size, addr_t *_apertureBase)
1068 {
1069 	Aperture *aperture = get_aperture(id);
1070 	if (aperture == NULL)
1071 		return B_ENTRY_NOT_FOUND;
1072 
1073 	return B_ERROR;
1074 }
1075 
1076 
1077 static status_t
1078 unreserve_aperture(aperture_id id, addr_t apertureBase)
1079 {
1080 	Aperture *aperture = get_aperture(id);
1081 	if (aperture == NULL)
1082 		return B_ENTRY_NOT_FOUND;
1083 
1084 	return B_ERROR;
1085 }
1086 
1087 
1088 static status_t
1089 bind_aperture(aperture_id id, area_id area, addr_t base, size_t size,
1090 	size_t alignment, addr_t reservedBase, addr_t *_apertureBase)
1091 {
1092 	Aperture *aperture = get_aperture(id);
1093 	if (aperture == NULL)
1094 		return B_ENTRY_NOT_FOUND;
1095 
1096 	if (area < 0) {
1097 		if (size == 0 || size > aperture->Size()
1098 			|| (base & (B_PAGE_SIZE - 1)) != 0
1099 			|| base == 0)
1100 			return B_BAD_VALUE;
1101 
1102 		size = ROUNDUP(size, B_PAGE_SIZE);
1103 	}
1104 
1105 	if (area >= 0) {
1106 		status_t status = get_area_base_and_size(area, base, size);
1107 		if (status < B_OK)
1108 			return status;
1109 	}
1110 
1111 	Autolock _(aperture->Lock());
1112 	aperture_memory *memory = NULL;
1113 	if (reservedBase != 0) {
1114 		// use reserved aperture to bind the pages
1115 		memory = aperture->GetMemory(reservedBase);
1116 		if (memory == NULL)
1117 			return B_BAD_VALUE;
1118 	} else {
1119 		// create new memory object
1120 		memory = aperture->CreateMemory(size, alignment,
1121 			B_APERTURE_NON_RESERVED);
1122 		if (memory == NULL)
1123 			return B_NO_MEMORY;
1124 	}
1125 
1126 	// just bind the physical pages backing the memory into the GART
1127 
1128 	status_t status = aperture->BindMemory(memory, base, size);
1129 	if (status < B_OK) {
1130 		if (reservedBase < 0)
1131 			aperture->DeleteMemory(memory);
1132 
1133 		return status;
1134 	}
1135 
1136 	if (_apertureBase != NULL)
1137 		*_apertureBase = memory->base;
1138 
1139 	return B_OK;
1140 }
1141 
1142 
1143 static status_t
1144 unbind_aperture(aperture_id id, addr_t base)
1145 {
1146 	Aperture *aperture = get_aperture(id);
1147 	if (aperture == NULL)
1148 		return B_ENTRY_NOT_FOUND;
1149 
1150 	Autolock _(aperture->Lock());
1151 	aperture_memory *memory = aperture->GetMemory(base);
1152 	if (memory == NULL || (memory->flags & BIND_APERTURE) == 0)
1153 		return B_BAD_VALUE;
1154 
1155 	if ((memory->flags & ALLOCATED_APERTURE) != 0)
1156 		panic("unbind memory %lx (%p) allocated by agp_gart.", base, memory);
1157 
1158 	status_t status = aperture->UnbindMemory(memory);
1159 	if (status < B_OK)
1160 		return status;
1161 
1162 	if ((memory->flags & RESERVED_APERTURE) == 0)
1163 		aperture->DeleteMemory(memory);
1164 
1165 	return B_OK;
1166 }
1167 
1168 
1169 //	#pragma mark -
1170 
1171 
1172 static status_t
1173 agp_init(void)
1174 {
1175 	TRACE("bus manager init\n");
1176 
1177 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI) != B_OK)
1178 		return B_ERROR;
1179 
1180 	uint32 cookie = 0;
1181 	sDeviceCount = 0;
1182 	pci_info info;
1183 	while (get_next_agp_device(&cookie, info, sDeviceInfos[sDeviceCount])
1184 			== B_OK) {
1185 		sDeviceCount++;
1186 	}
1187 
1188 	TRACE("found %ld AGP devices\n", sDeviceCount);
1189 
1190 	// Since there can be custom aperture modules (for memory management only),
1191 	// we always succeed if we could get the resources we need.
1192 
1193 	new(&sApertureHashTable) ApertureHashTable();
1194 	return init_lock(&sLock, "agp_gart");
1195 }
1196 
1197 
1198 void
1199 agp_uninit(void)
1200 {
1201 	TRACE("bus manager uninit\n");
1202 
1203 	ApertureHashTable::Iterator iterator = sApertureHashTable.GetIterator();
1204 	while (iterator.HasNext()) {
1205 		Aperture *aperture = iterator.Next();
1206 		sApertureHashTable.Remove(aperture);
1207 		delete aperture;
1208 	}
1209 
1210 	put_module(B_PCI_MODULE_NAME);
1211 }
1212 
1213 
1214 static int32
1215 agp_std_ops(int32 op, ...)
1216 {
1217 	switch (op) {
1218 		case B_MODULE_INIT:
1219 			return agp_init();
1220 		case B_MODULE_UNINIT:
1221 			agp_uninit();
1222 			return B_OK;
1223 	}
1224 
1225 	return B_BAD_VALUE;
1226 }
1227 
1228 
1229 static struct agp_gart_module_info sAGPModuleInfo = {
1230 	{
1231 		{
1232 			B_AGP_GART_MODULE_NAME,
1233 			B_KEEP_LOADED,		// Keep loaded, even if no driver requires it
1234 			agp_std_ops
1235 		},
1236 		NULL 					// the rescan function
1237 	},
1238 	get_nth_agp_info,
1239 	acquire_agp,
1240 	release_agp,
1241 	set_agp_mode,
1242 
1243 	map_aperture,
1244 	map_custom_aperture,
1245 	unmap_aperture,
1246 	get_aperture_info,
1247 	allocate_memory,
1248 	free_memory,
1249 	reserve_aperture,
1250 	unreserve_aperture,
1251 	bind_aperture,
1252 	unbind_aperture,
1253 };
1254 
1255 module_info *modules[] = {
1256 	(module_info *)&sAGPModuleInfo,
1257 	NULL
1258 };
1259