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