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