xref: /haiku/src/add-ons/kernel/bus_managers/agp_gart/agp_gart.cpp (revision 555b9ff733f870194a24fb9c7a346c3697d5fe45)
1481c8841SAxel Dörfler /*
29a063f05SAxel Dörfler  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
3481c8841SAxel Dörfler  * Copyright 2004-2006, Rudolf Cornelissen. All rights reserved.
4481c8841SAxel Dörfler  *
5481c8841SAxel Dörfler  * Distributed under the terms of the MIT License.
6481c8841SAxel Dörfler  */
7481c8841SAxel Dörfler 
8481c8841SAxel Dörfler // TODO: rethink the AGP interface for more than one bridge/device!
9481c8841SAxel Dörfler //	(should be done with the new driver API then)
10481c8841SAxel Dörfler 
11481c8841SAxel Dörfler /*
12481c8841SAxel Dörfler 	Notes:
13481c8841SAxel Dörfler 	- currently we just setup all found devices with AGP interface to the same
14481c8841SAxel Dörfler 	highest common mode, we don't distinquish different AGP busses.
15481c8841SAxel Dörfler 	TODO: it might be a better idea to just setup one instead.
16481c8841SAxel Dörfler 
17481c8841SAxel Dörfler 	- AGP3 defines 'asynchronous request size' and 'calibration cycle' fields
18481c8841SAxel Dörfler 	in the status and command registers. Currently programming zero's which will
19481c8841SAxel Dörfler 	make it work, although further optimisation is possible.
20481c8841SAxel Dörfler 
21481c8841SAxel Dörfler 	- AGP3.5 also defines isochronous transfers which are not implemented here:
22481c8841SAxel Dörfler 	the hardware keeps them disabled by default.
23481c8841SAxel Dörfler */
24481c8841SAxel Dörfler 
25481c8841SAxel Dörfler 
26481c8841SAxel Dörfler #include <AGP.h>
27481c8841SAxel Dörfler 
28481c8841SAxel Dörfler #include <stdlib.h>
29481c8841SAxel Dörfler 
30481c8841SAxel Dörfler #include <KernelExport.h>
31481c8841SAxel Dörfler #include <PCI.h>
32481c8841SAxel Dörfler 
33481c8841SAxel Dörfler #include <util/OpenHashTable.h>
34481c8841SAxel Dörfler #include <kernel/lock.h>
35e50cf876SIngo Weinhold #include <vm/vm_page.h>
36e50cf876SIngo Weinhold #include <vm/vm_types.h>
37481c8841SAxel Dörfler 
38481c8841SAxel Dörfler #include <lock.h>
39481c8841SAxel Dörfler 
40481c8841SAxel Dörfler 
41481c8841SAxel Dörfler #define TRACE_AGP
42481c8841SAxel Dörfler #ifdef TRACE_AGP
43481c8841SAxel Dörfler #	define TRACE(x...) dprintf("\33[36mAGP:\33[0m " x)
44481c8841SAxel Dörfler #else
45481c8841SAxel Dörfler #	define TRACE(x...) ;
46481c8841SAxel Dörfler #endif
477d5632a0SJérôme Duval #define ERROR(x...) dprintf("\33[36mAGP:\33[0m " x)
48481c8841SAxel Dörfler 
49481c8841SAxel Dörfler 
50481c8841SAxel Dörfler #define MAX_DEVICES	  8
51481c8841SAxel Dörfler 
52481c8841SAxel Dörfler #define AGP_ID(address) (address)
53481c8841SAxel Dörfler #define AGP_STATUS(address) (address + 4)
54481c8841SAxel Dörfler #define AGP_COMMAND(address) (address + 8)
55481c8841SAxel Dörfler 
56481c8841SAxel Dörfler /* read and write to PCI config space */
57481c8841SAxel Dörfler #define get_pci_config(info, offset, size) \
58481c8841SAxel Dörfler 	(sPCI->read_pci_config((info).bus, (info).device, (info).function, \
59481c8841SAxel Dörfler 		(offset), (size)))
60481c8841SAxel Dörfler #define set_pci_config(info, offset, size, value) \
61481c8841SAxel Dörfler 	(sPCI->write_pci_config((info).bus, (info).device, (info).function, \
62481c8841SAxel Dörfler 		(offset), (size), (value)))
63481c8841SAxel Dörfler 
64481c8841SAxel Dörfler #define RESERVED_APERTURE			0x80000000
65481c8841SAxel Dörfler #define ALLOCATED_APERTURE			0x40000000
66481c8841SAxel Dörfler #define BIND_APERTURE				0x20000000
67481c8841SAxel Dörfler #define APERTURE_PUBLIC_FLAGS_MASK	0x0000ffff
68481c8841SAxel Dörfler 
695147963dSStephan Aßmus struct aperture_memory {
70481c8841SAxel Dörfler 	aperture_memory *next;
715147963dSStephan Aßmus 	aperture_memory *hash_link;
72481c8841SAxel Dörfler 	addr_t		base;
73481c8841SAxel Dörfler 	size_t		size;
74481c8841SAxel Dörfler 	uint32		flags;
7521c87a5dSJérôme Duval #if !defined(GART_TEST)
76481c8841SAxel Dörfler 	union {
77481c8841SAxel Dörfler 		vm_page	**pages;
78481c8841SAxel Dörfler 		vm_page *page;
79481c8841SAxel Dörfler 	};
803cd20943SIngo Weinhold #ifdef DEBUG_PAGE_ACCESS
813cd20943SIngo Weinhold 	thread_id	allocating_thread;
823cd20943SIngo Weinhold #endif
83481c8841SAxel Dörfler #else
84481c8841SAxel Dörfler 	area_id		area;
85481c8841SAxel Dörfler #endif
86481c8841SAxel Dörfler };
87481c8841SAxel Dörfler 
88481c8841SAxel Dörfler class Aperture;
89481c8841SAxel Dörfler 
90481c8841SAxel Dörfler class MemoryHashDefinition {
91481c8841SAxel Dörfler public:
92481c8841SAxel Dörfler 	typedef addr_t KeyType;
93481c8841SAxel Dörfler 	typedef aperture_memory ValueType;
94481c8841SAxel Dörfler 
MemoryHashDefinition(aperture_info & info)95481c8841SAxel Dörfler 	MemoryHashDefinition(aperture_info &info) : fInfo(info) {}
96481c8841SAxel Dörfler 
HashKey(const KeyType & base) const97481c8841SAxel Dörfler 	size_t HashKey(const KeyType &base) const
98481c8841SAxel Dörfler 		{ return (base - fInfo.base) / B_PAGE_SIZE; }
Hash(aperture_memory * memory) const99481c8841SAxel Dörfler 	size_t Hash(aperture_memory *memory) const
100481c8841SAxel Dörfler 		{ return (memory->base - fInfo.base) / B_PAGE_SIZE; }
Compare(const KeyType & base,aperture_memory * memory) const101481c8841SAxel Dörfler 	bool Compare(const KeyType &base, aperture_memory *memory) const
102481c8841SAxel Dörfler 		{ return base == memory->base; }
GetLink(aperture_memory * memory) const1035147963dSStephan Aßmus 	aperture_memory *&GetLink(aperture_memory *memory) const
1045147963dSStephan Aßmus 		{ return memory->hash_link; }
105481c8841SAxel Dörfler 
106481c8841SAxel Dörfler private:
107481c8841SAxel Dörfler 	aperture_info	&fInfo;
108481c8841SAxel Dörfler };
109481c8841SAxel Dörfler 
1105147963dSStephan Aßmus typedef BOpenHashTable<MemoryHashDefinition> MemoryHashTable;
111481c8841SAxel Dörfler 
112481c8841SAxel Dörfler struct agp_device_info {
113481c8841SAxel Dörfler 	uint8		address;	/* location of AGP interface in PCI capabilities */
114481c8841SAxel Dörfler 	agp_info	info;
115481c8841SAxel Dörfler };
116481c8841SAxel Dörfler 
1175147963dSStephan Aßmus class Aperture {
118481c8841SAxel Dörfler public:
119481c8841SAxel Dörfler 	Aperture(agp_gart_bus_module_info *module, void *aperture);
120481c8841SAxel Dörfler 	~Aperture();
121481c8841SAxel Dörfler 
InitCheck() const122481c8841SAxel Dörfler 	status_t InitCheck() const { return fLock.sem >= B_OK ? B_OK : fLock.sem; }
123481c8841SAxel Dörfler 
124481c8841SAxel Dörfler 	void DeleteMemory(aperture_memory *memory);
125481c8841SAxel Dörfler 	aperture_memory *CreateMemory(size_t size, size_t alignment, uint32 flags);
126481c8841SAxel Dörfler 
127481c8841SAxel Dörfler 	status_t AllocateMemory(aperture_memory *memory, uint32 flags);
128481c8841SAxel Dörfler 
129481c8841SAxel Dörfler 	status_t UnbindMemory(aperture_memory *memory);
130103d05f3SAxel Dörfler 	status_t BindMemory(aperture_memory *memory, addr_t base, size_t size);
131481c8841SAxel Dörfler 
132481c8841SAxel Dörfler 	status_t GetInfo(aperture_info *info);
133481c8841SAxel Dörfler 
GetMemory(addr_t base)134481c8841SAxel Dörfler 	aperture_memory *GetMemory(addr_t base) { return fHashTable.Lookup(base); }
135481c8841SAxel Dörfler 
Base() const136481c8841SAxel Dörfler 	addr_t Base() const { return fInfo.base; }
Size() const137481c8841SAxel Dörfler 	addr_t Size() const { return fInfo.size; }
ID() const138481c8841SAxel Dörfler 	int32 ID() const { return fID; }
Lock()139481c8841SAxel Dörfler 	struct lock &Lock() { return fLock; }
140481c8841SAxel Dörfler 
141481c8841SAxel Dörfler private:
1427e6d2343SAxel Dörfler 	bool _AdaptToReserved(addr_t &base, size_t &size, int32 *_offset = NULL);
143481c8841SAxel Dörfler 	void _Free(aperture_memory *memory);
144481c8841SAxel Dörfler 	void _Remove(aperture_memory *memory);
145481c8841SAxel Dörfler 	status_t _Insert(aperture_memory *memory, size_t size, size_t alignment,
146481c8841SAxel Dörfler 		uint32 flags);
147481c8841SAxel Dörfler 
148481c8841SAxel Dörfler 	struct lock					fLock;
149481c8841SAxel Dörfler 	agp_gart_bus_module_info	*fModule;
150481c8841SAxel Dörfler 	int32						fID;
151481c8841SAxel Dörfler 	aperture_info				fInfo;
152481c8841SAxel Dörfler 	MemoryHashTable				fHashTable;
153481c8841SAxel Dörfler 	aperture_memory				*fFirstMemory;
154481c8841SAxel Dörfler 	void						*fPrivateAperture;
1555147963dSStephan Aßmus 
1565147963dSStephan Aßmus public:
1575147963dSStephan Aßmus 	Aperture					*fNext;
158481c8841SAxel Dörfler };
159481c8841SAxel Dörfler 
160481c8841SAxel Dörfler class ApertureHashDefinition {
161481c8841SAxel Dörfler public:
162481c8841SAxel Dörfler 	typedef int32 KeyType;
163481c8841SAxel Dörfler 	typedef Aperture ValueType;
164481c8841SAxel Dörfler 
HashKey(const KeyType & id) const165481c8841SAxel Dörfler 	size_t HashKey(const KeyType &id) const
166481c8841SAxel Dörfler 		{ return id; }
Hash(Aperture * aperture) const167481c8841SAxel Dörfler 	size_t Hash(Aperture *aperture) const
168481c8841SAxel Dörfler 		{ return aperture->ID(); }
Compare(const KeyType & id,Aperture * aperture) const169481c8841SAxel Dörfler 	bool Compare(const KeyType &id, Aperture *aperture) const
170481c8841SAxel Dörfler 		{ return id == aperture->ID(); }
GetLink(Aperture * aperture) const1715147963dSStephan Aßmus 	Aperture *&GetLink(Aperture *aperture) const
1725147963dSStephan Aßmus 		{ return aperture->fNext; }
173481c8841SAxel Dörfler };
174481c8841SAxel Dörfler 
1755147963dSStephan Aßmus typedef BOpenHashTable<ApertureHashDefinition> ApertureHashTable;
176481c8841SAxel Dörfler 
177481c8841SAxel Dörfler 
178481c8841SAxel Dörfler static agp_device_info sDeviceInfos[MAX_DEVICES];
179481c8841SAxel Dörfler static uint32 sDeviceCount;
180481c8841SAxel Dörfler static pci_module_info *sPCI;
181481c8841SAxel Dörfler static int32 sAcquired;
182481c8841SAxel Dörfler static ApertureHashTable sApertureHashTable;
183481c8841SAxel Dörfler static int32 sNextApertureID;
184481c8841SAxel Dörfler static struct lock sLock;
185481c8841SAxel Dörfler 
186481c8841SAxel Dörfler 
187481c8841SAxel Dörfler //	#pragma mark - private support functions
188481c8841SAxel Dörfler 
189481c8841SAxel Dörfler 
190481c8841SAxel Dörfler /*!	Makes sure that all bits lower than the maximum supported rate is set. */
191481c8841SAxel Dörfler static uint32
fix_rate_support(uint32 command)192481c8841SAxel Dörfler fix_rate_support(uint32 command)
193481c8841SAxel Dörfler {
194481c8841SAxel Dörfler 	if ((command & AGP_3_MODE) != 0) {
195481c8841SAxel Dörfler 		if ((command & AGP_3_8x) != 0)
196481c8841SAxel Dörfler 			command |= AGP_3_4x;
197481c8841SAxel Dörfler 
198481c8841SAxel Dörfler 		command &= ~AGP_RATE_MASK | AGP_3_8x | AGP_3_4x;
199481c8841SAxel Dörfler 		command |= AGP_SBA;
200481c8841SAxel Dörfler 			// SBA is required for AGP3
201481c8841SAxel Dörfler 	} else {
202481c8841SAxel Dörfler 		/* AGP 2.0 scheme applies */
203481c8841SAxel Dörfler 		if ((command & AGP_2_4x) != 0)
204481c8841SAxel Dörfler 			command |= AGP_2_2x;
205481c8841SAxel Dörfler 		if ((command & AGP_2_2x) != 0)
206481c8841SAxel Dörfler 			command |= AGP_2_1x;
207481c8841SAxel Dörfler 	}
208481c8841SAxel Dörfler 
209481c8841SAxel Dörfler 	return command;
210481c8841SAxel Dörfler }
211481c8841SAxel Dörfler 
212481c8841SAxel Dörfler 
213481c8841SAxel Dörfler /*!	Makes sure that only the highest rate bit is set. */
214481c8841SAxel Dörfler static uint32
fix_rate_command(uint32 command)215481c8841SAxel Dörfler fix_rate_command(uint32 command)
216481c8841SAxel Dörfler {
217481c8841SAxel Dörfler 	if ((command & AGP_3_MODE) != 0) {
218481c8841SAxel Dörfler 		if ((command & AGP_3_8x) != 0)
219481c8841SAxel Dörfler 			command &= ~AGP_3_4x;
220481c8841SAxel Dörfler 	} else {
221481c8841SAxel Dörfler 		/* AGP 2.0 scheme applies */
222481c8841SAxel Dörfler 		if ((command & AGP_2_4x) != 0)
223481c8841SAxel Dörfler 			command &= ~(AGP_2_2x | AGP_2_1x);
224481c8841SAxel Dörfler 		if ((command & AGP_2_2x) != 0)
225481c8841SAxel Dörfler 			command &= ~AGP_2_1x;
226481c8841SAxel Dörfler 	}
227481c8841SAxel Dörfler 
228481c8841SAxel Dörfler 	return command;
229481c8841SAxel Dörfler }
230481c8841SAxel Dörfler 
231481c8841SAxel Dörfler 
232481c8841SAxel Dörfler /*!	Checks the capabilities of the device, and removes everything from
233481c8841SAxel Dörfler 	\a command that the device does not support.
234481c8841SAxel Dörfler */
235481c8841SAxel Dörfler static void
check_capabilities(agp_device_info & deviceInfo,uint32 & command)236481c8841SAxel Dörfler check_capabilities(agp_device_info &deviceInfo, uint32 &command)
237481c8841SAxel Dörfler {
238481c8841SAxel Dörfler 	uint32 agpStatus = deviceInfo.info.interface.status;
239481c8841SAxel Dörfler 	if (deviceInfo.info.class_base == PCI_bridge) {
240481c8841SAxel Dörfler 		// make sure the AGP rate support mask is correct
241481c8841SAxel Dörfler 		// (ie. has the lower bits set)
242481c8841SAxel Dörfler 		agpStatus = fix_rate_support(agpStatus);
243481c8841SAxel Dörfler 	}
244481c8841SAxel Dörfler 
24582c2deb5SJérôme Duval 	TRACE("device %u.%u.%u has AGP capabilities %" B_PRIx32 "\n", deviceInfo.info.bus,
246ed7d0f52SAxel Dörfler 		deviceInfo.info.device, deviceInfo.info.function, agpStatus);
247ed7d0f52SAxel Dörfler 
248481c8841SAxel Dörfler 	// block non-supported AGP modes
249481c8841SAxel Dörfler 	command &= (agpStatus & (AGP_3_MODE | AGP_RATE_MASK))
250481c8841SAxel Dörfler 		| ~(AGP_3_MODE | AGP_RATE_MASK);
251481c8841SAxel Dörfler 
252481c8841SAxel Dörfler 	// If no AGP mode is supported at all, nothing remains:
253481c8841SAxel Dörfler 	// devices exist that have the AGP style connector with AGP style registers,
254481c8841SAxel Dörfler 	// but not the features!
255481c8841SAxel Dörfler 	// (confirmed Matrox Millenium II AGP for instance)
256481c8841SAxel Dörfler 	if ((agpStatus & AGP_RATE_MASK) == 0)
257481c8841SAxel Dörfler 		command = 0;
258481c8841SAxel Dörfler 
259481c8841SAxel Dörfler 	// block side band adressing if not supported
260481c8841SAxel Dörfler 	if ((agpStatus & AGP_SBA) == 0)
261481c8841SAxel Dörfler 		command &= ~AGP_SBA;
262481c8841SAxel Dörfler 
263481c8841SAxel Dörfler 	// block fast writes if not supported
264481c8841SAxel Dörfler 	if ((agpStatus & AGP_FAST_WRITE) == 0)
265481c8841SAxel Dörfler 		command &= ~AGP_FAST_WRITE;
266481c8841SAxel Dörfler 
267481c8841SAxel Dörfler 	// adjust maximum request depth to least depth supported
268481c8841SAxel Dörfler 	// note: this is writable only in the graphics card
269481c8841SAxel Dörfler 	uint8 requestDepth = ((agpStatus & AGP_REQUEST) >> AGP_REQUEST_SHIFT);
270481c8841SAxel Dörfler 	if (requestDepth < ((command & AGP_REQUEST) >> AGP_REQUEST_SHIFT)) {
271481c8841SAxel Dörfler 		command &= ~AGP_REQUEST;
272481c8841SAxel Dörfler 		command |= (requestDepth << AGP_REQUEST_SHIFT);
273481c8841SAxel Dörfler 	}
274481c8841SAxel Dörfler }
275481c8841SAxel Dörfler 
276481c8841SAxel Dörfler 
277481c8841SAxel Dörfler /*!	Checks the PCI capabilities if the device is an AGP device
278481c8841SAxel Dörfler */
279481c8841SAxel Dörfler static bool
is_agp_device(pci_info & info,uint8 * _address)280481c8841SAxel Dörfler is_agp_device(pci_info &info, uint8 *_address)
281481c8841SAxel Dörfler {
282481c8841SAxel Dörfler 	// Check if device implements a list of capabilities
283481c8841SAxel Dörfler 	if ((get_pci_config(info, PCI_status, 2) & PCI_status_capabilities) == 0)
284481c8841SAxel Dörfler 		return false;
285481c8841SAxel Dörfler 
286481c8841SAxel Dörfler 	// Get pointer to PCI capabilities list
287481c8841SAxel Dörfler 	// (AGP devices only, no need to take cardbus into account)
288481c8841SAxel Dörfler 	uint8 address = get_pci_config(info, PCI_capabilities_ptr, 1);
289481c8841SAxel Dörfler 
290481c8841SAxel Dörfler 	while (true) {
291481c8841SAxel Dörfler 		uint8 id = get_pci_config(info, address, 1);
292481c8841SAxel Dörfler 		uint8 next = get_pci_config(info, address + 1, 1) & ~0x3;
293481c8841SAxel Dörfler 
294481c8841SAxel Dörfler 		if (id == PCI_cap_id_agp) {
295481c8841SAxel Dörfler 			// is an AGP device
296481c8841SAxel Dörfler 			if (_address != NULL)
297481c8841SAxel Dörfler 				*_address = address;
298481c8841SAxel Dörfler 			return true;
299481c8841SAxel Dörfler 		}
300481c8841SAxel Dörfler 		if (next == 0) {
301481c8841SAxel Dörfler 			// end of list
302481c8841SAxel Dörfler 			break;
303481c8841SAxel Dörfler 		}
304481c8841SAxel Dörfler 
305481c8841SAxel Dörfler 		address = next;
306481c8841SAxel Dörfler 	}
307481c8841SAxel Dörfler 
308481c8841SAxel Dörfler 	return false;
309481c8841SAxel Dörfler }
310481c8841SAxel Dörfler 
311481c8841SAxel Dörfler 
312481c8841SAxel Dörfler static status_t
get_next_agp_device(uint32 * _cookie,pci_info & info,agp_device_info & device)313481c8841SAxel Dörfler get_next_agp_device(uint32 *_cookie, pci_info &info, agp_device_info &device)
314481c8841SAxel Dörfler {
315481c8841SAxel Dörfler 	uint32 index = *_cookie;
316481c8841SAxel Dörfler 
317481c8841SAxel Dörfler 	// find devices
318481c8841SAxel Dörfler 
319481c8841SAxel Dörfler 	for (; sPCI->get_nth_pci_info(index, &info) == B_OK; index++) {
320481c8841SAxel Dörfler 		// is it a bridge or a graphics card?
321481c8841SAxel Dörfler 		if ((info.class_base != PCI_bridge || info.class_sub != PCI_host)
322481c8841SAxel Dörfler 			&& info.class_base != PCI_display)
323481c8841SAxel Dörfler 			continue;
324481c8841SAxel Dörfler 
325481c8841SAxel Dörfler 		if (is_agp_device(info, &device.address)) {
326481c8841SAxel Dörfler 			device.info.vendor_id = info.vendor_id;
327481c8841SAxel Dörfler 			device.info.device_id = info.device_id;
328481c8841SAxel Dörfler 			device.info.bus = info.bus;
329481c8841SAxel Dörfler 			device.info.device = info.device;
330481c8841SAxel Dörfler 			device.info.function = info.function;
331481c8841SAxel Dörfler 			device.info.class_sub = info.class_sub;
332481c8841SAxel Dörfler 			device.info.class_base = info.class_base;
333481c8841SAxel Dörfler 
334481c8841SAxel Dörfler 			/* get the contents of the AGP registers from this device */
335481c8841SAxel Dörfler 			device.info.interface.capability_id = get_pci_config(info,
336481c8841SAxel Dörfler 				AGP_ID(device.address), 4);
337481c8841SAxel Dörfler 			device.info.interface.status = get_pci_config(info,
338481c8841SAxel Dörfler 				AGP_STATUS(device.address), 4);
339481c8841SAxel Dörfler 			device.info.interface.command = get_pci_config(info,
340481c8841SAxel Dörfler 				AGP_COMMAND(device.address), 4);
341481c8841SAxel Dörfler 
342481c8841SAxel Dörfler 			*_cookie = index + 1;
343481c8841SAxel Dörfler 			return B_OK;
344481c8841SAxel Dörfler 		}
345481c8841SAxel Dörfler 	}
346481c8841SAxel Dörfler 
347481c8841SAxel Dörfler 	return B_ENTRY_NOT_FOUND;
348481c8841SAxel Dörfler }
349481c8841SAxel Dörfler 
350481c8841SAxel Dörfler 
351481c8841SAxel Dörfler static void
set_agp_command(agp_device_info & deviceInfo,uint32 command)352481c8841SAxel Dörfler set_agp_command(agp_device_info &deviceInfo, uint32 command)
353481c8841SAxel Dörfler {
354481c8841SAxel Dörfler 	set_pci_config(deviceInfo.info, AGP_COMMAND(deviceInfo.address), 4, command);
355481c8841SAxel Dörfler 	deviceInfo.info.interface.command = get_pci_config(deviceInfo.info,
356481c8841SAxel Dörfler 		AGP_COMMAND(deviceInfo.address), 4);
357481c8841SAxel Dörfler }
358481c8841SAxel Dörfler 
359481c8841SAxel Dörfler 
360481c8841SAxel Dörfler static void
set_pci_mode()361481c8841SAxel Dörfler set_pci_mode()
362481c8841SAxel Dörfler {
363ed7d0f52SAxel Dörfler 	TRACE("set PCI mode on all AGP capable devices.\n");
364ed7d0f52SAxel Dörfler 
365481c8841SAxel Dörfler 	// First program all graphics cards
366481c8841SAxel Dörfler 
367481c8841SAxel Dörfler 	for (uint32 index = 0; index < sDeviceCount; index++) {
368481c8841SAxel Dörfler 		agp_device_info &deviceInfo = sDeviceInfos[index];
369481c8841SAxel Dörfler 		if (deviceInfo.info.class_base != PCI_display)
370481c8841SAxel Dörfler 			continue;
371481c8841SAxel Dörfler 
372481c8841SAxel Dörfler 		set_agp_command(deviceInfo, 0);
373481c8841SAxel Dörfler 	}
374481c8841SAxel Dörfler 
375481c8841SAxel Dörfler 	// Then program all bridges - it's the other around for AGP mode
376481c8841SAxel Dörfler 
377481c8841SAxel Dörfler 	for (uint32 index = 0; index < sDeviceCount; index++) {
378481c8841SAxel Dörfler 		agp_device_info &deviceInfo = sDeviceInfos[index];
379481c8841SAxel Dörfler 		if (deviceInfo.info.class_base != PCI_bridge)
380481c8841SAxel Dörfler 			continue;
381481c8841SAxel Dörfler 
382481c8841SAxel Dörfler 		set_agp_command(deviceInfo, 0);
383481c8841SAxel Dörfler 	}
384481c8841SAxel Dörfler 
385481c8841SAxel Dörfler 	// Wait 10mS for the bridges to recover (failsafe!)
386481c8841SAxel Dörfler 	// Note: some SiS bridge chipsets apparantly require 5mS to recover
387481c8841SAxel Dörfler 	// or the master (graphics card) cannot be initialized correctly!
388481c8841SAxel Dörfler 	snooze(10000);
389481c8841SAxel Dörfler }
390481c8841SAxel Dörfler 
391481c8841SAxel Dörfler 
392103d05f3SAxel Dörfler status_t
get_area_base_and_size(area_id area,addr_t & base,size_t & size)3930148fb2dSAxel Dörfler get_area_base_and_size(area_id area, addr_t &base, size_t &size)
394103d05f3SAxel Dörfler {
395103d05f3SAxel Dörfler 	area_info info;
396103d05f3SAxel Dörfler 	status_t status = get_area_info(area, &info);
397103d05f3SAxel Dörfler 	if (status < B_OK)
398103d05f3SAxel Dörfler 		return status;
399103d05f3SAxel Dörfler 
400103d05f3SAxel Dörfler 	base = (addr_t)info.address;
401103d05f3SAxel Dörfler 	size = info.size;
402103d05f3SAxel Dörfler 	return B_OK;
403103d05f3SAxel Dörfler }
404103d05f3SAxel Dörfler 
405103d05f3SAxel Dörfler 
406481c8841SAxel Dörfler Aperture *
get_aperture(aperture_id id)407481c8841SAxel Dörfler get_aperture(aperture_id id)
408481c8841SAxel Dörfler {
409481c8841SAxel Dörfler 	Autolock _(sLock);
410481c8841SAxel Dörfler 	return sApertureHashTable.Lookup(id);
411481c8841SAxel Dörfler }
412481c8841SAxel Dörfler 
413481c8841SAxel Dörfler 
414481c8841SAxel Dörfler //	#pragma mark - Aperture
415481c8841SAxel Dörfler 
416481c8841SAxel Dörfler 
Aperture(agp_gart_bus_module_info * module,void * aperture)417481c8841SAxel Dörfler Aperture::Aperture(agp_gart_bus_module_info *module, void *aperture)
418481c8841SAxel Dörfler 	:
419481c8841SAxel Dörfler 	fModule(module),
420*555b9ff7SNiels Sascha Reedijk 	fInfo(),
421481c8841SAxel Dörfler 	fHashTable(fInfo),
4227e6d2343SAxel Dörfler 	fFirstMemory(NULL),
423481c8841SAxel Dörfler 	fPrivateAperture(aperture)
424481c8841SAxel Dörfler {
425481c8841SAxel Dörfler 	fModule->get_aperture_info(fPrivateAperture, &fInfo);
426481c8841SAxel Dörfler 	fID = atomic_add(&sNextApertureID, 1);
427481c8841SAxel Dörfler 	init_lock(&fLock, "aperture");
428481c8841SAxel Dörfler }
429481c8841SAxel Dörfler 
430481c8841SAxel Dörfler 
~Aperture()431481c8841SAxel Dörfler Aperture::~Aperture()
432481c8841SAxel Dörfler {
4337e6d2343SAxel Dörfler 	while (fFirstMemory != NULL) {
4347e6d2343SAxel Dörfler 		DeleteMemory(fFirstMemory);
4357e6d2343SAxel Dörfler 	}
4367e6d2343SAxel Dörfler 
437481c8841SAxel Dörfler 	fModule->delete_aperture(fPrivateAperture);
438481c8841SAxel Dörfler 	put_module(fModule->info.name);
439481c8841SAxel Dörfler }
440481c8841SAxel Dörfler 
441481c8841SAxel Dörfler 
442481c8841SAxel Dörfler status_t
GetInfo(aperture_info * info)443481c8841SAxel Dörfler Aperture::GetInfo(aperture_info *info)
444481c8841SAxel Dörfler {
445481c8841SAxel Dörfler 	if (info == NULL)
446481c8841SAxel Dörfler 		return B_BAD_VALUE;
447481c8841SAxel Dörfler 
448481c8841SAxel Dörfler 	*info = fInfo;
449481c8841SAxel Dörfler 	return B_OK;
450481c8841SAxel Dörfler }
451481c8841SAxel Dörfler 
452481c8841SAxel Dörfler 
453481c8841SAxel Dörfler void
DeleteMemory(aperture_memory * memory)454481c8841SAxel Dörfler Aperture::DeleteMemory(aperture_memory *memory)
455481c8841SAxel Dörfler {
4567e6d2343SAxel Dörfler 	TRACE("delete memory %p\n", memory);
4577e6d2343SAxel Dörfler 
458481c8841SAxel Dörfler 	UnbindMemory(memory);
459481c8841SAxel Dörfler 	_Free(memory);
460481c8841SAxel Dörfler 	_Remove(memory);
461481c8841SAxel Dörfler 	fHashTable.Remove(memory);
462481c8841SAxel Dörfler 	delete memory;
463481c8841SAxel Dörfler }
464481c8841SAxel Dörfler 
465481c8841SAxel Dörfler 
466481c8841SAxel Dörfler aperture_memory *
CreateMemory(size_t size,size_t alignment,uint32 flags)467481c8841SAxel Dörfler Aperture::CreateMemory(size_t size, size_t alignment, uint32 flags)
468481c8841SAxel Dörfler {
469481c8841SAxel Dörfler 	aperture_memory *memory = new(std::nothrow) aperture_memory;
470481c8841SAxel Dörfler 	if (memory == NULL)
471481c8841SAxel Dörfler 		return NULL;
472481c8841SAxel Dörfler 
473481c8841SAxel Dörfler 	status_t status = _Insert(memory, size, alignment, flags);
474481c8841SAxel Dörfler 	if (status < B_OK) {
4757d5632a0SJérôme Duval 		ERROR("Aperture::CreateMemory(): did not find a free space large for "
4767d5632a0SJérôme Duval 			"this memory object\n");
477481c8841SAxel Dörfler 		delete memory;
478481c8841SAxel Dörfler 		return NULL;
479481c8841SAxel Dörfler 	}
480481c8841SAxel Dörfler 
48182c2deb5SJérôme Duval 	TRACE("create memory %p, base %" B_PRIxADDR ", size %" B_PRIxSIZE
48282c2deb5SJérôme Duval 		", flags %" B_PRIx32 "\n", memory, memory->base, memory->size, flags);
4837e6d2343SAxel Dörfler 
484481c8841SAxel Dörfler 	memory->flags = flags;
48521c87a5dSJérôme Duval #if !defined(GART_TEST)
486481c8841SAxel Dörfler 	memory->pages = NULL;
487481c8841SAxel Dörfler #else
488481c8841SAxel Dörfler 	memory->area = -1;
489481c8841SAxel Dörfler #endif
490481c8841SAxel Dörfler 
491481c8841SAxel Dörfler 	fHashTable.Insert(memory);
492481c8841SAxel Dörfler 	return memory;
493481c8841SAxel Dörfler }
494481c8841SAxel Dörfler 
495481c8841SAxel Dörfler 
4967e6d2343SAxel Dörfler bool
_AdaptToReserved(addr_t & base,size_t & size,int32 * _offset)4977e6d2343SAxel Dörfler Aperture::_AdaptToReserved(addr_t &base, size_t &size, int32 *_offset)
4987e6d2343SAxel Dörfler {
4997e6d2343SAxel Dörfler 	addr_t reservedEnd = fInfo.base + fInfo.reserved_size;
5007e6d2343SAxel Dörfler 	if (reservedEnd <= base)
5017e6d2343SAxel Dörfler 		return false;
5027e6d2343SAxel Dörfler 
5037e6d2343SAxel Dörfler 	if (reservedEnd >= base + size) {
5047e6d2343SAxel Dörfler 		size = 0;
5057e6d2343SAxel Dörfler 		return true;
5067e6d2343SAxel Dörfler 	}
5077e6d2343SAxel Dörfler 
5087e6d2343SAxel Dörfler 	if (_offset != NULL)
5097e6d2343SAxel Dörfler 		*_offset = reservedEnd - base;
5107e6d2343SAxel Dörfler 
5117e6d2343SAxel Dörfler 	size -= reservedEnd - base;
5127e6d2343SAxel Dörfler 	base = reservedEnd;
5137e6d2343SAxel Dörfler 	return true;
5147e6d2343SAxel Dörfler }
5157e6d2343SAxel Dörfler 
5167e6d2343SAxel Dörfler 
517481c8841SAxel Dörfler status_t
AllocateMemory(aperture_memory * memory,uint32 flags)518481c8841SAxel Dörfler Aperture::AllocateMemory(aperture_memory *memory, uint32 flags)
519481c8841SAxel Dörfler {
5207e6d2343SAxel Dörfler 	// We don't need to allocate reserved memory - it's
521481c8841SAxel Dörfler 	// already there for us to use
5227e6d2343SAxel Dörfler 	addr_t base = memory->base;
523481c8841SAxel Dörfler 	size_t size = memory->size;
5247e6d2343SAxel Dörfler 	if (_AdaptToReserved(base, size)) {
5257e6d2343SAxel Dörfler 		if (size == 0) {
5267e6d2343SAxel Dörfler 			TRACE("allocation is made of reserved memory\n");
527481c8841SAxel Dörfler 			return B_OK;
528481c8841SAxel Dörfler 		}
529481c8841SAxel Dörfler 
5307e6d2343SAxel Dörfler 		memset((void *)memory->base, 0, memory->size - size);
5317e6d2343SAxel Dörfler 	}
5327e6d2343SAxel Dörfler 	TRACE("allocate %ld bytes out of %ld\n", size, memory->size);
5337e6d2343SAxel Dörfler 
53421c87a5dSJérôme Duval #if !defined(GART_TEST)
535481c8841SAxel Dörfler 	uint32 count = size / B_PAGE_SIZE;
536481c8841SAxel Dörfler 
537481c8841SAxel Dörfler 	if ((flags & B_APERTURE_NEED_PHYSICAL) != 0) {
538a8ad734fSIngo Weinhold 		physical_address_restrictions restrictions = {};
539c53724f7SIngo Weinhold #if B_HAIKU_PHYSICAL_BITS > 32
540c53724f7SIngo Weinhold 		restrictions.high_address = (phys_addr_t)1 << 32;
541c53724f7SIngo Weinhold 			// TODO: Work-around until intel_gart can deal with physical
542c53724f7SIngo Weinhold 			// addresses > 4 GB.
543c53724f7SIngo Weinhold #endif
544e65c4002SIngo Weinhold 		memory->page = vm_page_allocate_page_run(
545a8ad734fSIngo Weinhold 			PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR, count, &restrictions,
546cff6e9e4SIngo Weinhold 			VM_PRIORITY_SYSTEM);
5477d5632a0SJérôme Duval 		if (memory->page == NULL) {
5487d5632a0SJérôme Duval 			ERROR("Aperture::AllocateMemory(): vm_page_allocate_page_run() "
5497d5632a0SJérôme Duval 				"failed (with B_APERTURE_NEED_PHYSICAL)\n");
550481c8841SAxel Dörfler 			return B_NO_MEMORY;
5517d5632a0SJérôme Duval 		}
552481c8841SAxel Dörfler 	} else {
553481c8841SAxel Dörfler 		// Allocate table to hold the pages
554481c8841SAxel Dörfler 		memory->pages = (vm_page **)malloc(count * sizeof(vm_page *));
555481c8841SAxel Dörfler 		if (memory->pages == NULL)
556481c8841SAxel Dörfler 			return B_NO_MEMORY;
557481c8841SAxel Dörfler 
558c53724f7SIngo Weinhold #if B_HAIKU_PHYSICAL_BITS > 32
559c53724f7SIngo Weinhold 		// TODO: Work-around until intel_gart can deal with physical
560c53724f7SIngo Weinhold 		// addresses > 4 GB.
561c53724f7SIngo Weinhold 		physical_address_restrictions restrictions = {};
562c53724f7SIngo Weinhold 		restrictions.high_address = (phys_addr_t)1 << 32;
563c53724f7SIngo Weinhold 		vm_page* page = vm_page_allocate_page_run(
564c53724f7SIngo Weinhold 			PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR, count, &restrictions,
565c53724f7SIngo Weinhold 			VM_PRIORITY_SYSTEM);
5667d5632a0SJérôme Duval 		if (page == NULL) {
5677d5632a0SJérôme Duval 			ERROR("Aperture::AllocateMemory(): vm_page_allocate_page_run() "
5687d5632a0SJérôme Duval 				"failed (without B_APERTURE_NEED_PHYSICAL)\n");
569c53724f7SIngo Weinhold 			return B_NO_MEMORY;
5707d5632a0SJérôme Duval 		}
571c53724f7SIngo Weinhold 
572c53724f7SIngo Weinhold 		for (uint32 i = 0; i < count; i++)
573c53724f7SIngo Weinhold 			memory->pages[i] = page + i;
574c53724f7SIngo Weinhold #else
57540bb9481SIngo Weinhold 		vm_page_reservation reservation;
57640bb9481SIngo Weinhold 		vm_page_reserve_pages(&reservation, count, VM_PRIORITY_SYSTEM);
57772382fa6SIngo Weinhold 		for (uint32 i = 0; i < count; i++) {
57840bb9481SIngo Weinhold 			memory->pages[i] = vm_page_allocate_page(&reservation,
579e65c4002SIngo Weinhold 				PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
58072382fa6SIngo Weinhold 		}
58140bb9481SIngo Weinhold 		vm_page_unreserve_pages(&reservation);
582c53724f7SIngo Weinhold #endif
583481c8841SAxel Dörfler 	}
5843cd20943SIngo Weinhold 
5853cd20943SIngo Weinhold #ifdef DEBUG_PAGE_ACCESS
5863cd20943SIngo Weinhold 	memory->allocating_thread = find_thread(NULL);
5873cd20943SIngo Weinhold #endif
5883cd20943SIngo Weinhold 
58921c87a5dSJérôme Duval #else	// GART_TEST
590481c8841SAxel Dörfler 	void *address;
591481c8841SAxel Dörfler 	memory->area = create_area("GART memory", &address, B_ANY_KERNEL_ADDRESS,
592481c8841SAxel Dörfler 		size, B_FULL_LOCK | ((flags & B_APERTURE_NEED_PHYSICAL) != 0
593956f4507STrung Nguyen 			? B_CONTIGUOUS : 0), B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
5947d5632a0SJérôme Duval 	if (memory->area < B_OK) {
5957d5632a0SJérôme Duval 		ERROR("Aperture::AllocateMemory(): create_area() failed\n");
596481c8841SAxel Dörfler 		return B_NO_MEMORY;
5977d5632a0SJérôme Duval 	}
598481c8841SAxel Dörfler #endif
599481c8841SAxel Dörfler 
600481c8841SAxel Dörfler 	memory->flags |= ALLOCATED_APERTURE;
601481c8841SAxel Dörfler 	return B_OK;
602481c8841SAxel Dörfler }
603481c8841SAxel Dörfler 
604481c8841SAxel Dörfler 
605481c8841SAxel Dörfler status_t
UnbindMemory(aperture_memory * memory)606481c8841SAxel Dörfler Aperture::UnbindMemory(aperture_memory *memory)
607481c8841SAxel Dörfler {
608481c8841SAxel Dörfler 	if ((memory->flags & BIND_APERTURE) == 0)
609481c8841SAxel Dörfler 		return B_BAD_VALUE;
610481c8841SAxel Dörfler 
6117e6d2343SAxel Dörfler 	// We must not unbind reserved memory
6127e6d2343SAxel Dörfler 	addr_t base = memory->base;
6137e6d2343SAxel Dörfler 	size_t size = memory->size;
6147e6d2343SAxel Dörfler 	if (_AdaptToReserved(base, size) && size == 0) {
6157e6d2343SAxel Dörfler 		memory->flags &= ~BIND_APERTURE;
6167e6d2343SAxel Dörfler 		return B_OK;
6177e6d2343SAxel Dörfler 	}
6187e6d2343SAxel Dörfler 
6197e6d2343SAxel Dörfler 	addr_t start = base - Base();
620103d05f3SAxel Dörfler 	TRACE("unbind %ld bytes at %lx\n", size, start);
621481c8841SAxel Dörfler 
622481c8841SAxel Dörfler 	for (addr_t offset = 0; offset < memory->size; offset += B_PAGE_SIZE) {
623481c8841SAxel Dörfler 		status_t status = fModule->unbind_page(fPrivateAperture, start + offset);
624481c8841SAxel Dörfler 		if (status < B_OK)
625481c8841SAxel Dörfler 			return status;
626481c8841SAxel Dörfler 	}
627481c8841SAxel Dörfler 
628481c8841SAxel Dörfler 	memory->flags &= ~BIND_APERTURE;
6297e6d2343SAxel Dörfler 	fModule->flush_tlbs(fPrivateAperture);
630481c8841SAxel Dörfler 	return B_OK;
631481c8841SAxel Dörfler }
632481c8841SAxel Dörfler 
633481c8841SAxel Dörfler 
634481c8841SAxel Dörfler status_t
BindMemory(aperture_memory * memory,addr_t address,size_t size)635103d05f3SAxel Dörfler Aperture::BindMemory(aperture_memory *memory, addr_t address, size_t size)
636481c8841SAxel Dörfler {
637103d05f3SAxel Dörfler 	bool physical = false;
638103d05f3SAxel Dörfler 
639103d05f3SAxel Dörfler 	if ((memory->flags & ALLOCATED_APERTURE) != 0) {
640103d05f3SAxel Dörfler 		// We allocated this memory, get the base and size from there
641d23e60e7SAxel Dörfler 		size = memory->size;
642103d05f3SAxel Dörfler 		physical = true;
643103d05f3SAxel Dörfler 	}
644103d05f3SAxel Dörfler 
6457e6d2343SAxel Dörfler 	// We don't need to bind reserved memory
6467e6d2343SAxel Dörfler 	addr_t base = memory->base;
6477e6d2343SAxel Dörfler 	int32 offset;
6487e6d2343SAxel Dörfler 	if (_AdaptToReserved(base, size, &offset)) {
6497e6d2343SAxel Dörfler 		if (size == 0) {
6507e6d2343SAxel Dörfler 			TRACE("reserved memory already bound\n");
6517e6d2343SAxel Dörfler 			memory->flags |= BIND_APERTURE;
6527e6d2343SAxel Dörfler 			return B_OK;
6537e6d2343SAxel Dörfler 		}
6547e6d2343SAxel Dörfler 
6557e6d2343SAxel Dörfler 		address += offset;
6567e6d2343SAxel Dörfler 	}
6577e6d2343SAxel Dörfler 
6587e6d2343SAxel Dörfler 	addr_t start = base - Base();
6597e6d2343SAxel Dörfler 	TRACE("bind %ld bytes at %lx\n", size, base);
660481c8841SAxel Dörfler 
661481c8841SAxel Dörfler 	for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) {
66264d79effSIngo Weinhold 		phys_addr_t physicalAddress = 0;
663481c8841SAxel Dörfler 		status_t status;
664481c8841SAxel Dörfler 
665481c8841SAxel Dörfler 		if (!physical) {
666481c8841SAxel Dörfler 			physical_entry entry;
6677e6d2343SAxel Dörfler 			status = get_memory_map((void *)(address + offset), B_PAGE_SIZE,
668481c8841SAxel Dörfler 				&entry, 1);
6697d5632a0SJérôme Duval 			if (status < B_OK) {
6707d5632a0SJérôme Duval 				ERROR("Aperture::BindMemory(): get_memory_map() failed\n");
671481c8841SAxel Dörfler 				return status;
6727d5632a0SJérôme Duval 			}
673481c8841SAxel Dörfler 
67464d79effSIngo Weinhold 			physicalAddress = entry.address;
675103d05f3SAxel Dörfler 		} else {
676103d05f3SAxel Dörfler 			uint32 index = offset >> PAGE_SHIFT;
677103d05f3SAxel Dörfler 			vm_page *page;
678103d05f3SAxel Dörfler 			if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0)
679103d05f3SAxel Dörfler 				page = memory->page + index;
680103d05f3SAxel Dörfler 			else
681103d05f3SAxel Dörfler 				page = memory->pages[index];
682103d05f3SAxel Dörfler 
6839a063f05SAxel Dörfler 			physicalAddress
6849a063f05SAxel Dörfler 				= (phys_addr_t)page->physical_page_number << PAGE_SHIFT;
685103d05f3SAxel Dörfler 		}
6867e6d2343SAxel Dörfler 
6877e6d2343SAxel Dörfler 		status = fModule->bind_page(fPrivateAperture, start + offset,
6887e6d2343SAxel Dörfler 			physicalAddress);
6897d5632a0SJérôme Duval 		if (status < B_OK) {
6907d5632a0SJérôme Duval 			ERROR("Aperture::BindMemory(): bind_page() failed\n");
691481c8841SAxel Dörfler 			return status;
692481c8841SAxel Dörfler 		}
6937d5632a0SJérôme Duval 	}
694481c8841SAxel Dörfler 
695481c8841SAxel Dörfler 	memory->flags |= BIND_APERTURE;
6967e6d2343SAxel Dörfler 	fModule->flush_tlbs(fPrivateAperture);
697481c8841SAxel Dörfler 	return B_OK;
698481c8841SAxel Dörfler }
699481c8841SAxel Dörfler 
700481c8841SAxel Dörfler 
701481c8841SAxel Dörfler void
_Free(aperture_memory * memory)702481c8841SAxel Dörfler Aperture::_Free(aperture_memory *memory)
703481c8841SAxel Dörfler {
704481c8841SAxel Dörfler 	if ((memory->flags & ALLOCATED_APERTURE) == 0)
705481c8841SAxel Dörfler 		return;
706481c8841SAxel Dörfler 
70721c87a5dSJérôme Duval #if !defined(GART_TEST)
708481c8841SAxel Dörfler 	// Remove the stolen area from the allocation
709481c8841SAxel Dörfler 	size_t size = memory->size;
710481c8841SAxel Dörfler 	addr_t reservedEnd = fInfo.base + fInfo.reserved_size;
711481c8841SAxel Dörfler 	if (memory->base < reservedEnd)
712481c8841SAxel Dörfler 		size -= reservedEnd - memory->base;
713481c8841SAxel Dörfler 
714481c8841SAxel Dörfler 	// Free previously allocated pages and page table
715481c8841SAxel Dörfler 	uint32 count = size / B_PAGE_SIZE;
716481c8841SAxel Dörfler 
717481c8841SAxel Dörfler 	if ((memory->flags & B_APERTURE_NEED_PHYSICAL) != 0) {
718481c8841SAxel Dörfler 		vm_page *page = memory->page;
719481c8841SAxel Dörfler 		for (uint32 i = 0; i < count; i++, page++) {
7203cd20943SIngo Weinhold 			DEBUG_PAGE_ACCESS_TRANSFER(page, memory->allocating_thread);
721481c8841SAxel Dörfler 			vm_page_set_state(page, PAGE_STATE_FREE);
722481c8841SAxel Dörfler 		}
7237f5c5dc8SAxel Dörfler 
7247f5c5dc8SAxel Dörfler 		memory->page = NULL;
725481c8841SAxel Dörfler 	} else {
726481c8841SAxel Dörfler 		for (uint32 i = 0; i < count; i++) {
7273cd20943SIngo Weinhold 			DEBUG_PAGE_ACCESS_TRANSFER(memory->pages[i],
7283cd20943SIngo Weinhold 				memory->allocating_thread);
729481c8841SAxel Dörfler 			vm_page_set_state(memory->pages[i], PAGE_STATE_FREE);
730481c8841SAxel Dörfler 		}
731481c8841SAxel Dörfler 
732481c8841SAxel Dörfler 		free(memory->pages);
733481c8841SAxel Dörfler 		memory->pages = NULL;
7347f5c5dc8SAxel Dörfler 	}
735481c8841SAxel Dörfler #else
736481c8841SAxel Dörfler 	delete_area(memory->area);
737481c8841SAxel Dörfler 	memory->area = -1;
738481c8841SAxel Dörfler #endif
739481c8841SAxel Dörfler 
740481c8841SAxel Dörfler 	memory->flags &= ~ALLOCATED_APERTURE;
741481c8841SAxel Dörfler }
742481c8841SAxel Dörfler 
743481c8841SAxel Dörfler 
744481c8841SAxel Dörfler void
_Remove(aperture_memory * memory)745481c8841SAxel Dörfler Aperture::_Remove(aperture_memory *memory)
746481c8841SAxel Dörfler {
747481c8841SAxel Dörfler 	aperture_memory *current = fFirstMemory, *last = NULL;
748481c8841SAxel Dörfler 
749481c8841SAxel Dörfler 	while (current != NULL) {
750481c8841SAxel Dörfler 		if (memory == current) {
751481c8841SAxel Dörfler 			if (last != NULL) {
752481c8841SAxel Dörfler 				last->next = current->next;
753481c8841SAxel Dörfler 			} else {
754481c8841SAxel Dörfler 				fFirstMemory = current->next;
755481c8841SAxel Dörfler 			}
756481c8841SAxel Dörfler 			break;
757481c8841SAxel Dörfler 		}
758481c8841SAxel Dörfler 
759481c8841SAxel Dörfler 		last = current;
760481c8841SAxel Dörfler 		current = current->next;
761481c8841SAxel Dörfler 	}
762481c8841SAxel Dörfler }
763481c8841SAxel Dörfler 
764481c8841SAxel Dörfler 
765481c8841SAxel Dörfler status_t
_Insert(aperture_memory * memory,size_t size,size_t alignment,uint32 flags)766481c8841SAxel Dörfler Aperture::_Insert(aperture_memory *memory, size_t size, size_t alignment,
767481c8841SAxel Dörfler 	uint32 flags)
768481c8841SAxel Dörfler {
769481c8841SAxel Dörfler 	aperture_memory *last = NULL;
770481c8841SAxel Dörfler 	aperture_memory *next;
771481c8841SAxel Dörfler 	bool foundSpot = false;
772481c8841SAxel Dörfler 
773481c8841SAxel Dörfler 	// do some sanity checking
774481c8841SAxel Dörfler 	if (size == 0 || size > fInfo.size)
775481c8841SAxel Dörfler 		return B_BAD_VALUE;
776481c8841SAxel Dörfler 
7777e6d2343SAxel Dörfler 	if (alignment < B_PAGE_SIZE)
7787e6d2343SAxel Dörfler 		alignment = B_PAGE_SIZE;
7797e6d2343SAxel Dörfler 
780481c8841SAxel Dörfler 	addr_t start = fInfo.base;
781481c8841SAxel Dörfler 	if ((flags & (B_APERTURE_NON_RESERVED | B_APERTURE_NEED_PHYSICAL)) != 0)
782481c8841SAxel Dörfler 		start += fInfo.reserved_size;
783481c8841SAxel Dörfler 
784481c8841SAxel Dörfler 	start = ROUNDUP(start, alignment);
785481c8841SAxel Dörfler 	if (start > fInfo.base - 1 + fInfo.size || start < fInfo.base)
786481c8841SAxel Dörfler 		return B_NO_MEMORY;
787481c8841SAxel Dörfler 
788481c8841SAxel Dörfler 	// walk up to the spot where we should start searching
789481c8841SAxel Dörfler 
790481c8841SAxel Dörfler 	next = fFirstMemory;
791481c8841SAxel Dörfler 	while (next) {
792481c8841SAxel Dörfler 		if (next->base >= start + size) {
793481c8841SAxel Dörfler 			// we have a winner
794481c8841SAxel Dörfler 			break;
795481c8841SAxel Dörfler 		}
796481c8841SAxel Dörfler 		last = next;
797481c8841SAxel Dörfler 		next = next->next;
798481c8841SAxel Dörfler 	}
799481c8841SAxel Dörfler 
800481c8841SAxel Dörfler 	// find a big enough hole
801481c8841SAxel Dörfler 	if (last == NULL) {
802481c8841SAxel Dörfler 		// see if we can build it at the beginning of the virtual map
803481c8841SAxel Dörfler 		if (next == NULL || (next->base >= ROUNDUP(start, alignment) + size)) {
804481c8841SAxel Dörfler 			memory->base = ROUNDUP(start, alignment);
805481c8841SAxel Dörfler 			foundSpot = true;
806481c8841SAxel Dörfler 		} else {
807481c8841SAxel Dörfler 			last = next;
808481c8841SAxel Dörfler 			next = next->next;
809481c8841SAxel Dörfler 		}
810481c8841SAxel Dörfler 	}
811481c8841SAxel Dörfler 
812481c8841SAxel Dörfler 	if (!foundSpot) {
813481c8841SAxel Dörfler 		// keep walking
814481c8841SAxel Dörfler 		while (next != NULL) {
815481c8841SAxel Dörfler 			if (next->base >= ROUNDUP(last->base + last->size, alignment) + size) {
816481c8841SAxel Dörfler 				// we found a spot (it'll be filled up below)
817481c8841SAxel Dörfler 				break;
818481c8841SAxel Dörfler 			}
819481c8841SAxel Dörfler 			last = next;
820481c8841SAxel Dörfler 			next = next->next;
821481c8841SAxel Dörfler 		}
822481c8841SAxel Dörfler 
823481c8841SAxel Dörfler 		if ((fInfo.base + (fInfo.size - 1)) >= (ROUNDUP(last->base + last->size,
824481c8841SAxel Dörfler 				alignment) + (size - 1))) {
825481c8841SAxel Dörfler 			// got a spot
826481c8841SAxel Dörfler 			foundSpot = true;
827481c8841SAxel Dörfler 			memory->base = ROUNDUP(last->base + last->size, alignment);
8287e6d2343SAxel Dörfler 			if (memory->base < start)
8297e6d2343SAxel Dörfler 				memory->base = start;
830481c8841SAxel Dörfler 		}
831481c8841SAxel Dörfler 
832481c8841SAxel Dörfler 		if (!foundSpot)
833481c8841SAxel Dörfler 			return B_NO_MEMORY;
834481c8841SAxel Dörfler 	}
835481c8841SAxel Dörfler 
836481c8841SAxel Dörfler 	memory->size = size;
837481c8841SAxel Dörfler 	if (last) {
838481c8841SAxel Dörfler 		memory->next = last->next;
839481c8841SAxel Dörfler 		last->next = memory;
840481c8841SAxel Dörfler 	} else {
841481c8841SAxel Dörfler 		memory->next = fFirstMemory;
842481c8841SAxel Dörfler 		fFirstMemory = memory;
843481c8841SAxel Dörfler 	}
844481c8841SAxel Dörfler 
845481c8841SAxel Dörfler 	return B_OK;
846481c8841SAxel Dörfler }
847481c8841SAxel Dörfler 
848481c8841SAxel Dörfler 
849481c8841SAxel Dörfler //	#pragma mark - AGP module interface
850481c8841SAxel Dörfler 
851481c8841SAxel Dörfler 
852481c8841SAxel Dörfler status_t
get_nth_agp_info(uint32 index,agp_info * info)853481c8841SAxel Dörfler get_nth_agp_info(uint32 index, agp_info *info)
854481c8841SAxel Dörfler {
85582c2deb5SJérôme Duval 	TRACE("get_nth_agp_info(index %" B_PRIu32 ")\n", index);
856481c8841SAxel Dörfler 
857481c8841SAxel Dörfler 	if (index >= sDeviceCount)
858481c8841SAxel Dörfler 		return B_BAD_VALUE;
859481c8841SAxel Dörfler 
860481c8841SAxel Dörfler 	// refresh from the contents of the AGP registers from this device
861481c8841SAxel Dörfler 	sDeviceInfos[index].info.interface.status = get_pci_config(
862481c8841SAxel Dörfler 		sDeviceInfos[index].info, AGP_STATUS(sDeviceInfos[index].address), 4);
863481c8841SAxel Dörfler 	sDeviceInfos[index].info.interface.command = get_pci_config(
864481c8841SAxel Dörfler 		sDeviceInfos[index].info, AGP_COMMAND(sDeviceInfos[index].address), 4);
865481c8841SAxel Dörfler 
866481c8841SAxel Dörfler 	*info = sDeviceInfos[index].info;
867481c8841SAxel Dörfler 	return B_OK;
868481c8841SAxel Dörfler }
869481c8841SAxel Dörfler 
870481c8841SAxel Dörfler 
871481c8841SAxel Dörfler status_t
acquire_agp(void)872481c8841SAxel Dörfler acquire_agp(void)
873481c8841SAxel Dörfler {
874481c8841SAxel Dörfler 	if (atomic_or(&sAcquired, 1) == 1)
875481c8841SAxel Dörfler 		return B_BUSY;
876481c8841SAxel Dörfler 
877481c8841SAxel Dörfler 	return B_OK;
878481c8841SAxel Dörfler }
879481c8841SAxel Dörfler 
880481c8841SAxel Dörfler 
881481c8841SAxel Dörfler void
release_agp(void)882481c8841SAxel Dörfler release_agp(void)
883481c8841SAxel Dörfler {
884481c8841SAxel Dörfler 	atomic_and(&sAcquired, 0);
885481c8841SAxel Dörfler }
886481c8841SAxel Dörfler 
887481c8841SAxel Dörfler 
888481c8841SAxel Dörfler uint32
set_agp_mode(uint32 command)889481c8841SAxel Dörfler set_agp_mode(uint32 command)
890481c8841SAxel Dörfler {
89182c2deb5SJérôme Duval 	TRACE("set_agp_mode(command %" B_PRIx32 ")\n", command);
892481c8841SAxel Dörfler 
893481c8841SAxel Dörfler 	if ((command & AGP_ENABLE) == 0) {
894481c8841SAxel Dörfler 		set_pci_mode();
895481c8841SAxel Dörfler 		return 0;
896481c8841SAxel Dörfler 	}
897481c8841SAxel Dörfler 
898481c8841SAxel Dörfler 	// Make sure we accept all modes lower than requested one and we
899481c8841SAxel Dörfler 	// reset reserved bits
900481c8841SAxel Dörfler 	command = fix_rate_support(command);
901481c8841SAxel Dörfler 
902481c8841SAxel Dörfler 	// iterate through our device list to find the common capabilities supported
903481c8841SAxel Dörfler 	for (uint32 index = 0; index < sDeviceCount; index++) {
904481c8841SAxel Dörfler 		agp_device_info &deviceInfo = sDeviceInfos[index];
905481c8841SAxel Dörfler 
906481c8841SAxel Dörfler 		// Refresh from the contents of the AGP capability registers
907481c8841SAxel Dörfler 		// (note: some graphics driver may have been tweaking, like nvidia)
908481c8841SAxel Dörfler 		deviceInfo.info.interface.status = get_pci_config(deviceInfo.info,
909481c8841SAxel Dörfler 			AGP_STATUS(deviceInfo.address), 4);
910481c8841SAxel Dörfler 
911481c8841SAxel Dörfler 		check_capabilities(deviceInfo, command);
912481c8841SAxel Dörfler 	}
913481c8841SAxel Dörfler 
914481c8841SAxel Dörfler 	command = fix_rate_command(command);
91582c2deb5SJérôme Duval 	TRACE("set AGP command %" B_PRIx32 " on all capable devices.\n", command);
916481c8841SAxel Dörfler 
917481c8841SAxel Dörfler 	// The order of programming differs for enabling/disabling AGP mode
918481c8841SAxel Dörfler 	// (see AGP specification)
919481c8841SAxel Dörfler 
920481c8841SAxel Dörfler 	// First program all bridges (master)
921481c8841SAxel Dörfler 
922481c8841SAxel Dörfler 	for (uint32 index = 0; index < sDeviceCount; index++) {
923481c8841SAxel Dörfler 		agp_device_info &deviceInfo = sDeviceInfos[index];
924481c8841SAxel Dörfler 		if (deviceInfo.info.class_base != PCI_bridge)
925481c8841SAxel Dörfler 			continue;
926481c8841SAxel Dörfler 
927481c8841SAxel Dörfler 		set_agp_command(deviceInfo, command);
928481c8841SAxel Dörfler 	}
929481c8841SAxel Dörfler 
930481c8841SAxel Dörfler 	// Wait 10mS for the bridges to recover (failsafe, see set_pci_mode()!)
931481c8841SAxel Dörfler 	snooze(10000);
932481c8841SAxel Dörfler 
933481c8841SAxel Dörfler 	// Then all graphics cards (target)
934481c8841SAxel Dörfler 
935481c8841SAxel Dörfler 	for (uint32 index = 0; index < sDeviceCount; index++) {
936481c8841SAxel Dörfler 		agp_device_info &deviceInfo = sDeviceInfos[index];
937481c8841SAxel Dörfler 		if (deviceInfo.info.class_base != PCI_display)
938481c8841SAxel Dörfler 			continue;
939481c8841SAxel Dörfler 
940481c8841SAxel Dörfler 		set_agp_command(deviceInfo, command);
941481c8841SAxel Dörfler 	}
942481c8841SAxel Dörfler 
943481c8841SAxel Dörfler 	return command;
944481c8841SAxel Dörfler }
945481c8841SAxel Dörfler 
946481c8841SAxel Dörfler 
947481c8841SAxel Dörfler //	#pragma mark - GART module interface
948481c8841SAxel Dörfler 
949481c8841SAxel Dörfler 
950481c8841SAxel Dörfler static aperture_id
map_aperture(uint8 bus,uint8 device,uint8 function,size_t size,addr_t * _apertureBase)951481c8841SAxel Dörfler map_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
952481c8841SAxel Dörfler 	addr_t *_apertureBase)
953481c8841SAxel Dörfler {
954481c8841SAxel Dörfler 	void *iterator = open_module_list("busses/agp_gart");
955481c8841SAxel Dörfler 	status_t status = B_ENTRY_NOT_FOUND;
956481c8841SAxel Dörfler 	Aperture *aperture = NULL;
957481c8841SAxel Dörfler 
958481c8841SAxel Dörfler 	Autolock _(sLock);
959481c8841SAxel Dörfler 
960481c8841SAxel Dörfler 	while (true) {
961481c8841SAxel Dörfler 		char name[256];
962481c8841SAxel Dörfler 		size_t nameLength = sizeof(name);
963481c8841SAxel Dörfler 		if (read_next_module_name(iterator, name, &nameLength) != B_OK)
964481c8841SAxel Dörfler 			break;
965481c8841SAxel Dörfler 
966481c8841SAxel Dörfler 		agp_gart_bus_module_info *module;
967481c8841SAxel Dörfler 		if (get_module(name, (module_info **)&module) == B_OK) {
968481c8841SAxel Dörfler 			void *privateAperture;
969481c8841SAxel Dörfler 			status = module->create_aperture(bus, device, function, size,
970481c8841SAxel Dörfler 				&privateAperture);
971481c8841SAxel Dörfler 			if (status < B_OK) {
972481c8841SAxel Dörfler 				put_module(name);
973481c8841SAxel Dörfler 				continue;
974481c8841SAxel Dörfler 			}
975481c8841SAxel Dörfler 
976481c8841SAxel Dörfler 			aperture = new(std::nothrow) Aperture(module, privateAperture);
977481c8841SAxel Dörfler 			status = aperture->InitCheck();
978481c8841SAxel Dörfler 			if (status == B_OK) {
979481c8841SAxel Dörfler 				if (_apertureBase != NULL)
980481c8841SAxel Dörfler 					*_apertureBase = aperture->Base();
981481c8841SAxel Dörfler 
982481c8841SAxel Dörfler 				sApertureHashTable.Insert(aperture);
983481c8841SAxel Dörfler 			} else {
984481c8841SAxel Dörfler 				delete aperture;
985481c8841SAxel Dörfler 				aperture = NULL;
986481c8841SAxel Dörfler 			}
987481c8841SAxel Dörfler 			break;
988481c8841SAxel Dörfler 		}
989481c8841SAxel Dörfler 	}
990481c8841SAxel Dörfler 
991481c8841SAxel Dörfler 	close_module_list(iterator);
992481c8841SAxel Dörfler 	return aperture != NULL ? aperture->ID() : status;
993481c8841SAxel Dörfler }
994481c8841SAxel Dörfler 
995481c8841SAxel Dörfler 
996481c8841SAxel Dörfler static aperture_id
map_custom_aperture(gart_bus_module_info * module,addr_t * _apertureBase)997481c8841SAxel Dörfler map_custom_aperture(gart_bus_module_info *module, addr_t *_apertureBase)
998481c8841SAxel Dörfler {
999481c8841SAxel Dörfler 	return B_ERROR;
1000481c8841SAxel Dörfler }
1001481c8841SAxel Dörfler 
1002481c8841SAxel Dörfler 
1003481c8841SAxel Dörfler static status_t
unmap_aperture(aperture_id id)1004481c8841SAxel Dörfler unmap_aperture(aperture_id id)
1005481c8841SAxel Dörfler {
1006481c8841SAxel Dörfler 	Autolock _(sLock);
1007481c8841SAxel Dörfler 	Aperture *aperture = sApertureHashTable.Lookup(id);
1008481c8841SAxel Dörfler 	if (aperture == NULL)
1009481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1010481c8841SAxel Dörfler 
1011481c8841SAxel Dörfler 	sApertureHashTable.Remove(aperture);
1012481c8841SAxel Dörfler 	delete aperture;
1013481c8841SAxel Dörfler 	return B_OK;
1014481c8841SAxel Dörfler }
1015481c8841SAxel Dörfler 
1016481c8841SAxel Dörfler 
1017481c8841SAxel Dörfler static status_t
get_aperture_info(aperture_id id,aperture_info * info)1018481c8841SAxel Dörfler get_aperture_info(aperture_id id, aperture_info *info)
1019481c8841SAxel Dörfler {
1020481c8841SAxel Dörfler 	Aperture *aperture = get_aperture(id);
1021481c8841SAxel Dörfler 	if (aperture == NULL)
1022481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1023481c8841SAxel Dörfler 
1024481c8841SAxel Dörfler 	Autolock _(aperture->Lock());
1025481c8841SAxel Dörfler 	return aperture->GetInfo(info);
1026481c8841SAxel Dörfler }
1027481c8841SAxel Dörfler 
1028481c8841SAxel Dörfler 
1029481c8841SAxel Dörfler static status_t
allocate_memory(aperture_id id,size_t size,size_t alignment,uint32 flags,addr_t * _apertureBase,phys_addr_t * _physicalBase)1030481c8841SAxel Dörfler allocate_memory(aperture_id id, size_t size, size_t alignment, uint32 flags,
10319a063f05SAxel Dörfler 	addr_t *_apertureBase, phys_addr_t *_physicalBase)
1032481c8841SAxel Dörfler {
1033481c8841SAxel Dörfler 	if ((flags & ~APERTURE_PUBLIC_FLAGS_MASK) != 0 || _apertureBase == NULL)
1034481c8841SAxel Dörfler 		return B_BAD_VALUE;
1035481c8841SAxel Dörfler 
1036481c8841SAxel Dörfler 	Aperture *aperture = get_aperture(id);
1037481c8841SAxel Dörfler 	if (aperture == NULL)
1038481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1039481c8841SAxel Dörfler 
1040481c8841SAxel Dörfler 	size = ROUNDUP(size, B_PAGE_SIZE);
1041481c8841SAxel Dörfler 
10427e6d2343SAxel Dörfler 	Autolock _(aperture->Lock());
10437e6d2343SAxel Dörfler 
1044481c8841SAxel Dörfler 	aperture_memory *memory = aperture->CreateMemory(size, alignment, flags);
1045481c8841SAxel Dörfler 	if (memory == NULL)
1046481c8841SAxel Dörfler 		return B_NO_MEMORY;
1047481c8841SAxel Dörfler 
1048481c8841SAxel Dörfler 	status_t status = aperture->AllocateMemory(memory, flags);
1049481c8841SAxel Dörfler 	if (status == B_OK)
1050103d05f3SAxel Dörfler 		status = aperture->BindMemory(memory, 0, 0);
1051481c8841SAxel Dörfler 	if (status < B_OK) {
1052481c8841SAxel Dörfler 		aperture->DeleteMemory(memory);
1053481c8841SAxel Dörfler 		return status;
1054481c8841SAxel Dörfler 	}
1055481c8841SAxel Dörfler 
1056481c8841SAxel Dörfler 	if (_physicalBase != NULL && (flags & B_APERTURE_NEED_PHYSICAL) != 0) {
105721c87a5dSJérôme Duval #if !defined(GART_TEST)
10589a063f05SAxel Dörfler 		*_physicalBase
10599a063f05SAxel Dörfler 			= (phys_addr_t)memory->page->physical_page_number * B_PAGE_SIZE;
1060481c8841SAxel Dörfler #else
1061481c8841SAxel Dörfler 		physical_entry entry;
1062481c8841SAxel Dörfler 		status = get_memory_map((void *)memory->base, B_PAGE_SIZE, &entry, 1);
1063481c8841SAxel Dörfler 		if (status < B_OK) {
1064481c8841SAxel Dörfler 			aperture->DeleteMemory(memory);
1065481c8841SAxel Dörfler 			return status;
1066481c8841SAxel Dörfler 		}
1067481c8841SAxel Dörfler 
106864d79effSIngo Weinhold 		*_physicalBase = entry.address;
1069481c8841SAxel Dörfler #endif
1070481c8841SAxel Dörfler 	}
1071481c8841SAxel Dörfler 
1072481c8841SAxel Dörfler 	*_apertureBase = memory->base;
1073481c8841SAxel Dörfler 	return B_OK;
1074481c8841SAxel Dörfler }
1075481c8841SAxel Dörfler 
1076481c8841SAxel Dörfler 
1077481c8841SAxel Dörfler static status_t
free_memory(aperture_id id,addr_t base)1078103d05f3SAxel Dörfler free_memory(aperture_id id, addr_t base)
1079481c8841SAxel Dörfler {
1080481c8841SAxel Dörfler 	Aperture *aperture = get_aperture(id);
1081481c8841SAxel Dörfler 	if (aperture == NULL)
1082481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1083481c8841SAxel Dörfler 
1084481c8841SAxel Dörfler 	Autolock _(aperture->Lock());
1085481c8841SAxel Dörfler 	aperture_memory *memory = aperture->GetMemory(base);
1086481c8841SAxel Dörfler 	if (memory == NULL)
1087481c8841SAxel Dörfler 		return B_BAD_VALUE;
1088481c8841SAxel Dörfler 
1089481c8841SAxel Dörfler 	aperture->DeleteMemory(memory);
1090481c8841SAxel Dörfler 	return B_OK;
1091481c8841SAxel Dörfler }
1092481c8841SAxel Dörfler 
1093481c8841SAxel Dörfler 
1094481c8841SAxel Dörfler static status_t
reserve_aperture(aperture_id id,size_t size,addr_t * _apertureBase)1095481c8841SAxel Dörfler reserve_aperture(aperture_id id, size_t size, addr_t *_apertureBase)
1096481c8841SAxel Dörfler {
1097481c8841SAxel Dörfler 	Aperture *aperture = get_aperture(id);
1098481c8841SAxel Dörfler 	if (aperture == NULL)
1099481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1100481c8841SAxel Dörfler 
1101481c8841SAxel Dörfler 	return B_ERROR;
1102481c8841SAxel Dörfler }
1103481c8841SAxel Dörfler 
1104481c8841SAxel Dörfler 
1105481c8841SAxel Dörfler static status_t
unreserve_aperture(aperture_id id,addr_t apertureBase)1106481c8841SAxel Dörfler unreserve_aperture(aperture_id id, addr_t apertureBase)
1107481c8841SAxel Dörfler {
1108481c8841SAxel Dörfler 	Aperture *aperture = get_aperture(id);
1109481c8841SAxel Dörfler 	if (aperture == NULL)
1110481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1111481c8841SAxel Dörfler 
1112481c8841SAxel Dörfler 	return B_ERROR;
1113481c8841SAxel Dörfler }
1114481c8841SAxel Dörfler 
1115481c8841SAxel Dörfler 
1116481c8841SAxel Dörfler static status_t
bind_aperture(aperture_id id,area_id area,addr_t base,size_t size,size_t alignment,addr_t reservedBase,addr_t * _apertureBase)1117481c8841SAxel Dörfler bind_aperture(aperture_id id, area_id area, addr_t base, size_t size,
1118103d05f3SAxel Dörfler 	size_t alignment, addr_t reservedBase, addr_t *_apertureBase)
1119481c8841SAxel Dörfler {
1120481c8841SAxel Dörfler 	Aperture *aperture = get_aperture(id);
1121481c8841SAxel Dörfler 	if (aperture == NULL)
1122481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1123481c8841SAxel Dörfler 
11247e6d2343SAxel Dörfler 	if (area < 0) {
1125481c8841SAxel Dörfler 		if (size == 0 || size > aperture->Size()
11267e6d2343SAxel Dörfler 			|| (base & (B_PAGE_SIZE - 1)) != 0
11277e6d2343SAxel Dörfler 			|| base == 0)
1128481c8841SAxel Dörfler 			return B_BAD_VALUE;
1129481c8841SAxel Dörfler 
1130481c8841SAxel Dörfler 		size = ROUNDUP(size, B_PAGE_SIZE);
11317e6d2343SAxel Dörfler 	}
1132481c8841SAxel Dörfler 
1133481c8841SAxel Dörfler 	if (area >= 0) {
1134103d05f3SAxel Dörfler 		status_t status = get_area_base_and_size(area, base, size);
1135481c8841SAxel Dörfler 		if (status < B_OK)
1136481c8841SAxel Dörfler 			return status;
1137481c8841SAxel Dörfler 	}
1138481c8841SAxel Dörfler 
1139481c8841SAxel Dörfler 	Autolock _(aperture->Lock());
1140481c8841SAxel Dörfler 	aperture_memory *memory = NULL;
1141481c8841SAxel Dörfler 	if (reservedBase != 0) {
1142481c8841SAxel Dörfler 		// use reserved aperture to bind the pages
1143481c8841SAxel Dörfler 		memory = aperture->GetMemory(reservedBase);
1144481c8841SAxel Dörfler 		if (memory == NULL)
1145481c8841SAxel Dörfler 			return B_BAD_VALUE;
1146481c8841SAxel Dörfler 	} else {
1147481c8841SAxel Dörfler 		// create new memory object
11487e6d2343SAxel Dörfler 		memory = aperture->CreateMemory(size, alignment,
11497e6d2343SAxel Dörfler 			B_APERTURE_NON_RESERVED);
1150481c8841SAxel Dörfler 		if (memory == NULL)
1151481c8841SAxel Dörfler 			return B_NO_MEMORY;
1152481c8841SAxel Dörfler 	}
1153481c8841SAxel Dörfler 
1154481c8841SAxel Dörfler 	// just bind the physical pages backing the memory into the GART
1155481c8841SAxel Dörfler 
1156103d05f3SAxel Dörfler 	status_t status = aperture->BindMemory(memory, base, size);
1157481c8841SAxel Dörfler 	if (status < B_OK) {
115812d046d0SAdrien Destugues 		if (reservedBase != 0)
1159481c8841SAxel Dörfler 			aperture->DeleteMemory(memory);
1160481c8841SAxel Dörfler 
1161481c8841SAxel Dörfler 		return status;
1162481c8841SAxel Dörfler 	}
1163481c8841SAxel Dörfler 
1164481c8841SAxel Dörfler 	if (_apertureBase != NULL)
1165481c8841SAxel Dörfler 		*_apertureBase = memory->base;
1166481c8841SAxel Dörfler 
1167481c8841SAxel Dörfler 	return B_OK;
1168481c8841SAxel Dörfler }
1169481c8841SAxel Dörfler 
1170481c8841SAxel Dörfler 
1171481c8841SAxel Dörfler static status_t
unbind_aperture(aperture_id id,addr_t base)1172481c8841SAxel Dörfler unbind_aperture(aperture_id id, addr_t base)
1173481c8841SAxel Dörfler {
1174481c8841SAxel Dörfler 	Aperture *aperture = get_aperture(id);
1175481c8841SAxel Dörfler 	if (aperture == NULL)
1176481c8841SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1177481c8841SAxel Dörfler 
1178481c8841SAxel Dörfler 	Autolock _(aperture->Lock());
1179481c8841SAxel Dörfler 	aperture_memory *memory = aperture->GetMemory(base);
1180481c8841SAxel Dörfler 	if (memory == NULL || (memory->flags & BIND_APERTURE) == 0)
1181481c8841SAxel Dörfler 		return B_BAD_VALUE;
1182481c8841SAxel Dörfler 
1183481c8841SAxel Dörfler 	if ((memory->flags & ALLOCATED_APERTURE) != 0)
1184481c8841SAxel Dörfler 		panic("unbind memory %lx (%p) allocated by agp_gart.", base, memory);
1185481c8841SAxel Dörfler 
1186481c8841SAxel Dörfler 	status_t status = aperture->UnbindMemory(memory);
1187481c8841SAxel Dörfler 	if (status < B_OK)
1188481c8841SAxel Dörfler 		return status;
1189481c8841SAxel Dörfler 
1190481c8841SAxel Dörfler 	if ((memory->flags & RESERVED_APERTURE) == 0)
1191481c8841SAxel Dörfler 		aperture->DeleteMemory(memory);
1192481c8841SAxel Dörfler 
1193481c8841SAxel Dörfler 	return B_OK;
1194481c8841SAxel Dörfler }
1195481c8841SAxel Dörfler 
1196481c8841SAxel Dörfler 
1197481c8841SAxel Dörfler //	#pragma mark -
1198481c8841SAxel Dörfler 
1199481c8841SAxel Dörfler 
1200481c8841SAxel Dörfler static status_t
agp_init(void)1201481c8841SAxel Dörfler agp_init(void)
1202481c8841SAxel Dörfler {
1203481c8841SAxel Dörfler 	TRACE("bus manager init\n");
1204481c8841SAxel Dörfler 
1205481c8841SAxel Dörfler 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI) != B_OK)
1206481c8841SAxel Dörfler 		return B_ERROR;
1207481c8841SAxel Dörfler 
1208481c8841SAxel Dörfler 	uint32 cookie = 0;
1209481c8841SAxel Dörfler 	sDeviceCount = 0;
1210481c8841SAxel Dörfler 	pci_info info;
1211481c8841SAxel Dörfler 	while (get_next_agp_device(&cookie, info, sDeviceInfos[sDeviceCount])
1212481c8841SAxel Dörfler 			== B_OK) {
1213481c8841SAxel Dörfler 		sDeviceCount++;
1214481c8841SAxel Dörfler 	}
1215481c8841SAxel Dörfler 
121682c2deb5SJérôme Duval 	TRACE("found %" B_PRId32 " AGP devices\n", sDeviceCount);
1217481c8841SAxel Dörfler 
1218481c8841SAxel Dörfler 	// Since there can be custom aperture modules (for memory management only),
1219481c8841SAxel Dörfler 	// we always succeed if we could get the resources we need.
1220481c8841SAxel Dörfler 
1221481c8841SAxel Dörfler 	new(&sApertureHashTable) ApertureHashTable();
1222481c8841SAxel Dörfler 	return init_lock(&sLock, "agp_gart");
1223481c8841SAxel Dörfler }
1224481c8841SAxel Dörfler 
1225481c8841SAxel Dörfler 
1226481c8841SAxel Dörfler void
agp_uninit(void)1227481c8841SAxel Dörfler agp_uninit(void)
1228481c8841SAxel Dörfler {
1229481c8841SAxel Dörfler 	TRACE("bus manager uninit\n");
1230481c8841SAxel Dörfler 
1231481c8841SAxel Dörfler 	ApertureHashTable::Iterator iterator = sApertureHashTable.GetIterator();
1232481c8841SAxel Dörfler 	while (iterator.HasNext()) {
1233481c8841SAxel Dörfler 		Aperture *aperture = iterator.Next();
1234481c8841SAxel Dörfler 		sApertureHashTable.Remove(aperture);
1235481c8841SAxel Dörfler 		delete aperture;
1236481c8841SAxel Dörfler 	}
1237481c8841SAxel Dörfler 
1238481c8841SAxel Dörfler 	put_module(B_PCI_MODULE_NAME);
1239481c8841SAxel Dörfler }
1240481c8841SAxel Dörfler 
1241481c8841SAxel Dörfler 
1242481c8841SAxel Dörfler static int32
agp_std_ops(int32 op,...)1243481c8841SAxel Dörfler agp_std_ops(int32 op, ...)
1244481c8841SAxel Dörfler {
1245481c8841SAxel Dörfler 	switch (op) {
1246481c8841SAxel Dörfler 		case B_MODULE_INIT:
1247481c8841SAxel Dörfler 			return agp_init();
1248481c8841SAxel Dörfler 		case B_MODULE_UNINIT:
1249481c8841SAxel Dörfler 			agp_uninit();
1250481c8841SAxel Dörfler 			return B_OK;
1251481c8841SAxel Dörfler 	}
1252481c8841SAxel Dörfler 
1253481c8841SAxel Dörfler 	return B_BAD_VALUE;
1254481c8841SAxel Dörfler }
1255481c8841SAxel Dörfler 
1256481c8841SAxel Dörfler 
1257481c8841SAxel Dörfler static struct agp_gart_module_info sAGPModuleInfo = {
1258481c8841SAxel Dörfler 	{
1259481c8841SAxel Dörfler 		{
1260481c8841SAxel Dörfler 			B_AGP_GART_MODULE_NAME,
1261481c8841SAxel Dörfler 			B_KEEP_LOADED,		// Keep loaded, even if no driver requires it
1262481c8841SAxel Dörfler 			agp_std_ops
1263481c8841SAxel Dörfler 		},
1264481c8841SAxel Dörfler 		NULL 					// the rescan function
1265481c8841SAxel Dörfler 	},
1266481c8841SAxel Dörfler 	get_nth_agp_info,
1267481c8841SAxel Dörfler 	acquire_agp,
1268481c8841SAxel Dörfler 	release_agp,
1269481c8841SAxel Dörfler 	set_agp_mode,
1270481c8841SAxel Dörfler 
1271481c8841SAxel Dörfler 	map_aperture,
1272481c8841SAxel Dörfler 	map_custom_aperture,
1273481c8841SAxel Dörfler 	unmap_aperture,
1274481c8841SAxel Dörfler 	get_aperture_info,
1275481c8841SAxel Dörfler 	allocate_memory,
1276103d05f3SAxel Dörfler 	free_memory,
1277481c8841SAxel Dörfler 	reserve_aperture,
1278481c8841SAxel Dörfler 	unreserve_aperture,
1279481c8841SAxel Dörfler 	bind_aperture,
1280481c8841SAxel Dörfler 	unbind_aperture,
1281481c8841SAxel Dörfler };
1282481c8841SAxel Dörfler 
1283481c8841SAxel Dörfler module_info *modules[] = {
1284481c8841SAxel Dörfler 	(module_info *)&sAGPModuleInfo,
1285481c8841SAxel Dörfler 	NULL
1286481c8841SAxel Dörfler };
1287