xref: /haiku/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp (revision efafab643ce980e3f3c916795ed302599f6b4f66)
1 /*
2  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2011-2016, Haiku, Inc. All Rights Reserved.
4  * Distributed under the terms of the MIT License.
5  *
6  * Authors:
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Jerome Duval, jerome.duval@gmail.com
9  *		Adrien Destugues, pulkomandy@gmail.com
10  *		Michael Lotz, mmlr@mlotz.ch
11  *		Alexander von Gluck IV, kallisti5@unixzen.com
12  */
13 
14 
15 #include <AreaKeeper.h>
16 #include <intel_extreme.h>
17 
18 #include <stdlib.h>
19 
20 #include <AGP.h>
21 #include <KernelExport.h>
22 #include <PCI.h>
23 
24 #include <new>
25 
26 
27 #define TRACE_INTEL
28 #ifdef TRACE_INTEL
29 #	define TRACE(x...) dprintf("intel_gart: " x)
30 #else
31 #	define TRACE(x...) ;
32 #endif
33 #define ERROR(x...) dprintf("intel_gart: " x)
34 
35 
36 /* read and write to PCI config space */
37 #define get_pci_config(info, offset, size) \
38 	(sPCI->read_pci_config((info).bus, (info).device, (info).function, \
39 		(offset), (size)))
40 #define set_pci_config(info, offset, size, value) \
41 	(sPCI->write_pci_config((info).bus, (info).device, (info).function, \
42 		(offset), (size), (value)))
43 #define write32(address, data) \
44 	(*((volatile uint32*)(address)) = (data))
45 #define read32(address) \
46 	(*((volatile uint32*)(address)))
47 
48 
49 // PCI "Host bridge" is most cases :-)
50 const struct supported_device {
51 	uint32		bridge_id;
52 	uint32		display_id;
53 	int32		type;
54 	const char	*name;
55 } kSupportedDevices[] = {
56 	{0x3575, 0x3577, INTEL_GROUP_83x, "i830GM"},
57 	{0x2560, 0x2562, INTEL_GROUP_83x, "i845G"},
58 	{0x3580, 0x3582, INTEL_GROUP_85x, "i855G"},
59 	{0x358c, 0x358e, INTEL_GROUP_85x, "i855G"},
60 	{0x2570, 0x2572, INTEL_GROUP_85x, "i865G"},
61 
62 //	{0x2792, INTEL_GROUP_91x, "i910"},
63 //	{0x258a, INTEL_GROUP_91x, "i915"},
64 	{0x2580, 0x2582, INTEL_MODEL_915, "i915G"},
65 	{0x2590, 0x2592, INTEL_MODEL_915M, "i915GM"},
66 	{0x2770, 0x2772, INTEL_MODEL_945, "i945G"},
67 	{0x27a0, 0x27a2, INTEL_MODEL_945M, "i945GM"},
68 	{0x27ac, 0x27ae, INTEL_MODEL_945M, "i945GME"},
69 
70 	{0x2970, 0x2972, INTEL_MODEL_965, "i946GZ"},
71 	{0x2980, 0x2982, INTEL_MODEL_965, "G35"},
72 	{0x2990, 0x2992, INTEL_MODEL_965, "i965Q"},
73 	{0x29a0, 0x29a2, INTEL_MODEL_965, "i965G"},
74 	{0x2a00, 0x2a02, INTEL_MODEL_965, "i965GM"},
75 	{0x2a10, 0x2a12, INTEL_MODEL_965, "i965GME"},
76 
77 	{0x29b0, 0x29b2, INTEL_MODEL_G33, "G33"},
78 	{0x29c0, 0x29c2, INTEL_MODEL_G33, "Q35"},
79 	{0x29d0, 0x29d2, INTEL_MODEL_G33, "Q33"},
80 
81 	{0x2a40, 0x2a42, INTEL_MODEL_GM45, "GM45"},
82 	{0x2e00, 0x2e02, INTEL_MODEL_G45, "IGD"},
83 	{0x2e10, 0x2e12, INTEL_MODEL_G45, "Q45"},
84 	{0x2e20, 0x2e22, INTEL_MODEL_G45, "G45"},
85 	{0x2e30, 0x2e32, INTEL_MODEL_G45, "G41"},
86 	{0x2e40, 0x2e42, INTEL_MODEL_G45, "B43"},
87 	{0x2e90, 0x2e92, INTEL_MODEL_G45, "B43"},
88 
89 	{0xa000, 0xa001, INTEL_MODEL_PINE, "Atom D4xx"},
90 	{0xa000, 0xa002, INTEL_MODEL_PINE, "Atom D5xx"},
91 	{0xa010, 0xa011, INTEL_MODEL_PINEM, "Atom N4xx"},
92 	{0xa010, 0xa012, INTEL_MODEL_PINEM, "Atom N5xx"},
93 
94 	{0x0040, 0x0042, INTEL_MODEL_ILKG, "IronLake Desktop"},
95 	{0x0044, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
96 	{0x0062, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
97 	{0x006a, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
98 
99 	{0x0100, 0x0102, INTEL_MODEL_SNBG, "SandyBridge Desktop GT1"},
100 	{0x0100, 0x0112, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2"},
101 	{0x0100, 0x0122, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2+"},
102 	{0x0104, 0x0106, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT1"},
103 	{0x0104, 0x0116, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2"},
104 	{0x0104, 0x0126, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2+"},
105 	{0x0108, 0x010a, INTEL_MODEL_SNBGS, "SandyBridge Server"},
106 
107 	{0x0150, 0x0152, INTEL_MODEL_IVBG, "IvyBridge Desktop GT1"},
108 	{0x0150, 0x0162, INTEL_MODEL_IVBG, "IvyBridge Desktop GT2"},
109 	{0x0154, 0x0156, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT1"},
110 	{0x0154, 0x0166, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT2"},
111 	{0x0158, 0x015a, INTEL_MODEL_IVBGS, "IvyBridge Server GT1"},
112 	{0x0158, 0x016a, INTEL_MODEL_IVBGS, "IvyBridge Server GT2"},
113 
114 	{0x0c00, 0x0412, INTEL_MODEL_HAS, "Haswell Desktop"},
115 	{0x0c04, 0x0416, INTEL_MODEL_HASM, "Haswell Mobile"},
116 	{0x0d04, 0x0d26, INTEL_MODEL_HASM, "Haswell Mobile"},
117 	{0x0a04, 0x0a16, INTEL_MODEL_HASM, "Haswell Mobile"},
118 
119 	// XXX: 0x0f00 only confirmed on 0x0f30, 0x0f31
120 	{0x0f00, 0x0155, INTEL_MODEL_VLV, "ValleyView Desktop"},
121 	{0x0f00, 0x0f30, INTEL_MODEL_VLVM, "ValleyView Mobile"},
122 	{0x0f00, 0x0f31, INTEL_MODEL_VLVM, "ValleyView Mobile"},
123 	{0x0f00, 0x0f32, INTEL_MODEL_VLVM, "ValleyView Mobile"},
124 	{0x0f00, 0x0f33, INTEL_MODEL_VLVM, "ValleyView Mobile"},
125 	{0x0f00, 0x0157, INTEL_MODEL_VLVM, "ValleyView Mobile"},
126 
127 	{0x1604, 0x1616, INTEL_MODEL_BDWM, "HD Graphics 5500 (Broadwell GT2)"},
128 
129 	// XXX: 0x1904 only confirmed on 0x1916
130 	{0x1904, 0x1902, INTEL_MODEL_SKY,  "Skylake GT1"},
131 	{0x1904, 0x1906, INTEL_MODEL_SKYM, "Skylake GT1"},
132 	{0x1904, 0x190a, INTEL_MODEL_SKYS, "Skylake GT1"},
133 	{0x1904, 0x190b, INTEL_MODEL_SKY,  "Skylake GT1"},
134 	{0x1904, 0x190e, INTEL_MODEL_SKYM, "Skylake GT1"},
135 	{0x1904, 0x1912, INTEL_MODEL_SKY,  "Skylake GT2"},
136 	{0x1904, 0x1916, INTEL_MODEL_SKYM, "Skylake GT2"},
137 	{0x1904, 0x191a, INTEL_MODEL_SKYS, "Skylake GT2"},
138 	{0x1904, 0x191b, INTEL_MODEL_SKY,  "Skylake GT2"},
139 	{0x1904, 0x191d, INTEL_MODEL_SKY,  "Skylake GT2"},
140 	{0x1904, 0x191e, INTEL_MODEL_SKYM, "Skylake GT2"},
141 	{0x1904, 0x1921, INTEL_MODEL_SKYM, "Skylake GT2F"},
142 	{0x1904, 0x1926, INTEL_MODEL_SKYM, "Skylake GT3"},
143 	{0x1904, 0x192a, INTEL_MODEL_SKYS, "Skylake GT3"},
144 	{0x1904, 0x192b, INTEL_MODEL_SKY,  "Skylake GT3"},
145 };
146 
147 struct intel_info {
148 	pci_info	bridge;
149 	pci_info	display;
150 	DeviceType*	type;
151 
152 	uint32*		gtt_base;
153 	phys_addr_t	gtt_physical_base;
154 	area_id		gtt_area;
155 	size_t		gtt_entries;
156 	size_t		gtt_stolen_entries;
157 
158 	vuint32*	registers;
159 	area_id		registers_area;
160 
161 	addr_t		aperture_base;
162 	phys_addr_t	aperture_physical_base;
163 	area_id		aperture_area;
164 	size_t		aperture_size;
165 	size_t		aperture_stolen_size;
166 
167 	phys_addr_t	scratch_page;
168 	area_id		scratch_area;
169 };
170 
171 static intel_info sInfo;
172 static pci_module_info* sPCI;
173 
174 
175 static bool
176 has_display_device(pci_info &info, uint32 deviceID)
177 {
178 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK;
179 			index++) {
180 		if (info.vendor_id != VENDOR_ID_INTEL
181 			|| info.device_id != deviceID
182 			|| info.class_base != PCI_display)
183 			continue;
184 
185 		return true;
186 	}
187 
188 	return false;
189 }
190 
191 
192 static uint16
193 gtt_memory_config(intel_info &info)
194 {
195 	uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL;
196 	if (info.type->InGroup(INTEL_GROUP_SNB))
197 		controlRegister = SNB_GRAPHICS_MEMORY_CONTROL;
198 
199 	return get_pci_config(info.bridge, controlRegister, 2);
200 }
201 
202 
203 static size_t
204 determine_gtt_stolen(intel_info &info)
205 {
206 	uint16 memoryConfig = gtt_memory_config(info);
207 	size_t memorySize = 1 << 20; // 1 MB
208 
209 	if (info.type->InGroup(INTEL_GROUP_83x)) {
210 		// Older chips
211 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
212 			case i830_LOCAL_MEMORY_ONLY:
213 				// TODO: determine its size!
214 				ERROR("getting local memory size not implemented.\n");
215 				break;
216 			case i830_STOLEN_512K:
217 				memorySize >>= 1;
218 				break;
219 			case i830_STOLEN_1M:
220 				// default case
221 				break;
222 			case i830_STOLEN_8M:
223 				memorySize *= 8;
224 				break;
225 		}
226 	} else if (info.type->InGroup(INTEL_GROUP_SNB)) {
227 		switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) {
228 			case SNB_STOLEN_MEMORY_32MB:
229 				memorySize *= 32;
230 				break;
231 			case SNB_STOLEN_MEMORY_64MB:
232 				memorySize *= 64;
233 				break;
234 			case SNB_STOLEN_MEMORY_96MB:
235 				memorySize *= 96;
236 				break;
237 			case SNB_STOLEN_MEMORY_128MB:
238 				memorySize *= 128;
239 				break;
240 			case SNB_STOLEN_MEMORY_160MB:
241 				memorySize *= 160;
242 				break;
243 			case SNB_STOLEN_MEMORY_192MB:
244 				memorySize *= 192;
245 				break;
246 			case SNB_STOLEN_MEMORY_224MB:
247 				memorySize *= 224;
248 				break;
249 			case SNB_STOLEN_MEMORY_256MB:
250 				memorySize *= 256;
251 				break;
252 			case SNB_STOLEN_MEMORY_288MB:
253 				memorySize *= 288;
254 				break;
255 			case SNB_STOLEN_MEMORY_320MB:
256 				memorySize *= 320;
257 				break;
258 			case SNB_STOLEN_MEMORY_352MB:
259 				memorySize *= 352;
260 				break;
261 			case SNB_STOLEN_MEMORY_384MB:
262 				memorySize *= 384;
263 				break;
264 			case SNB_STOLEN_MEMORY_416MB:
265 				memorySize *= 416;
266 				break;
267 			case SNB_STOLEN_MEMORY_448MB:
268 				memorySize *= 448;
269 				break;
270 			case SNB_STOLEN_MEMORY_480MB:
271 				memorySize *= 480;
272 				break;
273 			case SNB_STOLEN_MEMORY_512MB:
274 				memorySize *= 512;
275 				break;
276 		}
277 	} else if (info.type->InGroup(INTEL_GROUP_85x)
278 		|| info.type->InFamily(INTEL_FAMILY_9xx)
279         || info.type->InFamily(INTEL_FAMILY_SER5)
280         || info.type->InFamily(INTEL_FAMILY_SOC0)
281         || info.type->InFamily(INTEL_FAMILY_POVR)) {
282 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
283 			case i855_STOLEN_MEMORY_4M:
284 				memorySize *= 4;
285 				break;
286 			case i855_STOLEN_MEMORY_8M:
287 				memorySize *= 8;
288 				break;
289 			case i855_STOLEN_MEMORY_16M:
290 				memorySize *= 16;
291 				break;
292 			case i855_STOLEN_MEMORY_32M:
293 				memorySize *= 32;
294 				break;
295 			case i855_STOLEN_MEMORY_48M:
296 				memorySize *= 48;
297 				break;
298 			case i855_STOLEN_MEMORY_64M:
299 				memorySize *= 64;
300 				break;
301 			case i855_STOLEN_MEMORY_128M:
302 				memorySize *= 128;
303 				break;
304 			case i855_STOLEN_MEMORY_256M:
305 				memorySize *= 256;
306 				break;
307 			case G4X_STOLEN_MEMORY_96MB:
308 				memorySize *= 96;
309 				break;
310 			case G4X_STOLEN_MEMORY_160MB:
311 				memorySize *= 160;
312 				break;
313 			case G4X_STOLEN_MEMORY_224MB:
314 				memorySize *= 224;
315 				break;
316 			case G4X_STOLEN_MEMORY_352MB:
317 				memorySize *= 352;
318 				break;
319 		}
320 	} else {
321 		// TODO: error out!
322 		memorySize = 4096;
323 	}
324 	return memorySize - 4096;
325 }
326 
327 
328 static size_t
329 determine_gtt_size(intel_info &info)
330 {
331 	uint16 memoryConfig = gtt_memory_config(info);
332 	size_t gttSize = 0;
333 
334 	if (info.type->IsModel(INTEL_MODEL_965)) {
335 		switch (memoryConfig & i965_GTT_MASK) {
336 			case i965_GTT_128K:
337 				gttSize = 128 << 10;
338 				break;
339 			case i965_GTT_256K:
340 				gttSize = 256 << 10;
341 				break;
342 			case i965_GTT_512K:
343 				gttSize = 512 << 10;
344 				break;
345 		}
346 	} else if (info.type->IsModel(INTEL_MODEL_G33)
347 	           || info.type->InGroup(INTEL_GROUP_PIN)) {
348 		switch (memoryConfig & G33_GTT_MASK) {
349 			case G33_GTT_1M:
350 				gttSize = 1 << 20;
351 				break;
352 			case G33_GTT_2M:
353 				gttSize = 2 << 20;
354 				break;
355 		}
356 	} else if (info.type->InGroup(INTEL_GROUP_G4x)
357 			|| info.type->InGroup(INTEL_GROUP_ILK)) {
358 		switch (memoryConfig & G4X_GTT_MASK) {
359 			case G4X_GTT_NONE:
360 				gttSize = 0;
361 				break;
362 			case G4X_GTT_1M_NO_IVT:
363 				gttSize = 1 << 20;
364 				break;
365 			case G4X_GTT_2M_NO_IVT:
366 			case G4X_GTT_2M_IVT:
367 				gttSize = 2 << 20;
368 				break;
369 			case G4X_GTT_3M_IVT:
370 				gttSize = 3 << 20;
371 				break;
372 			case G4X_GTT_4M_IVT:
373 				gttSize = 4 << 20;
374 				break;
375 		}
376 	} else if (info.type->InGroup(INTEL_GROUP_SNB)) {
377 		switch (memoryConfig & SNB_GTT_SIZE_MASK) {
378 			case SNB_GTT_SIZE_NONE:
379 				gttSize = 0;
380 				break;
381 			case SNB_GTT_SIZE_1MB:
382 				gttSize = 1 << 20;
383 				break;
384 			case SNB_GTT_SIZE_2MB:
385 				gttSize = 2 << 20;
386 				break;
387 		}
388 	} else {
389 		// older models have the GTT as large as their frame buffer mapping
390 		// TODO: check if the i9xx version works with the i8xx chips as well
391 		size_t frameBufferSize = 0;
392 		if (info.type->InFamily(INTEL_FAMILY_8xx)) {
393 			if (info.type->InGroup(INTEL_GROUP_83x)
394 				&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
395 				frameBufferSize = 64 << 20;
396 			else
397 				frameBufferSize = 128 << 20;
398 		} else if (info.type->Generation() >= 3) {
399 			frameBufferSize = info.display.u.h0.base_register_sizes[2];
400 		}
401 
402 		TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
403 		gttSize = frameBufferSize / 1024;
404 	}
405 	return gttSize;
406 }
407 
408 
409 static void
410 set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
411 {
412 	if (info.type->Generation() >= 8) {
413 		// CHV + BXT
414 		physicalAddress |= (physicalAddress >> 28) & 0x07f0;
415 		// TODO: cache control?
416 	} else if (info.type->Generation() >= 6) {
417 		// SandyBridge, IronLake, IvyBridge, Haswell
418 		physicalAddress |= (physicalAddress >> 28) & 0x0ff0;
419 		physicalAddress |= 0x02; // cache control, l3 cacheable
420 	} else if (info.type->Generation() >= 4) {
421 		// Intel 9xx minus 91x, 94x, G33
422 		// possible high bits are stored in the lower end
423 		physicalAddress |= (physicalAddress >> 28) & 0x00f0;
424 		// TODO: cache control?
425 	}
426 
427 	// TODO: this is not 64-bit safe!
428 	write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
429 		(uint32)physicalAddress | GTT_ENTRY_VALID);
430 }
431 
432 
433 static void
434 intel_unmap(intel_info &info)
435 {
436 	delete_area(info.registers_area);
437 	delete_area(info.gtt_area);
438 	delete_area(info.scratch_area);
439 	delete_area(info.aperture_area);
440 	info.aperture_size = 0;
441 }
442 
443 
444 static status_t
445 intel_map(intel_info &info)
446 {
447 	int fbIndex = 0;
448 	int mmioIndex = 1;
449 	if (info.type->Generation() >= 3) {
450 		// for some reason Intel saw the need to change the order of the
451 		// mappings with the introduction of the i9xx family
452 		mmioIndex = 0;
453 		fbIndex = 2;
454 	}
455 
456 	AreaKeeper mmioMapper;
457 	info.registers_area = mmioMapper.Map("intel GMCH mmio",
458 		info.display.u.h0.base_registers[mmioIndex],
459 		info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS,
460 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.registers);
461 
462 	if (mmioMapper.InitCheck() < B_OK) {
463 		ERROR("could not map memory I/O!\n");
464 		return info.registers_area;
465 	}
466 
467 	// make sure bus master, memory-mapped I/O, and frame buffer is enabled
468 	set_pci_config(info.display, PCI_command, 2,
469 		get_pci_config(info.display, PCI_command, 2)
470 			| PCI_command_io | PCI_command_memory | PCI_command_master);
471 
472 	void* scratchAddress;
473 	AreaKeeper scratchCreator;
474 	info.scratch_area = scratchCreator.Create("intel GMCH scratch",
475 		&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
476 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
477 	if (scratchCreator.InitCheck() < B_OK) {
478 		ERROR("could not create scratch page!\n");
479 		return info.scratch_area;
480 	}
481 
482 	physical_entry entry;
483 	if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
484 		return B_ERROR;
485 
486 	// TODO: Review these
487 	if (info.type->InFamily(INTEL_FAMILY_8xx)) {
488 		info.gtt_physical_base = read32(info.registers
489 			+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
490 		if (info.gtt_physical_base == 0) {
491 			// TODO: not sure how this is supposed to work under Linux/FreeBSD,
492 			// but on my i865, this code is needed for Haiku.
493 			ERROR("Use GTT address fallback.\n");
494 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
495 				+ i830_GTT_BASE;
496 		}
497 	} else if (info.type->InGroup(INTEL_GROUP_91x)) {
498 		info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4);
499 	} else {
500 		// 945+?
501 		info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
502 			+ (2UL << 20);
503 	}
504 
505 	size_t gttSize = determine_gtt_size(info);
506 	size_t stolenSize = determine_gtt_stolen(info);
507 
508 	info.gtt_entries = gttSize / 4096;
509 	info.gtt_stolen_entries = stolenSize / 4096;
510 
511 	TRACE("GTT base %" B_PRIxPHYSADDR ", size %lu, entries %lu, stolen %lu\n",
512 		info.gtt_physical_base, gttSize, info.gtt_entries, stolenSize);
513 
514 	AreaKeeper gttMapper;
515 	info.gtt_area = gttMapper.Map("intel GMCH gtt",
516 		info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
517 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.gtt_base);
518 	if (gttMapper.InitCheck() < B_OK) {
519 		ERROR("could not map GTT!\n");
520 		return info.gtt_area;
521 	}
522 
523 	info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex];
524 	info.aperture_stolen_size = stolenSize;
525 	if (info.aperture_size == 0)
526 		info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
527 
528 	ERROR("detected %ld MB of stolen memory, aperture size %ld MB, "
529 		"GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
530 		info.aperture_size >> 20, gttSize >> 10);
531 
532 	ERROR("GTT base = 0x%" B_PRIxPHYSADDR "\n", info.gtt_physical_base);
533 	ERROR("MMIO base = 0x%" B_PRIx32 "\n",
534 		info.display.u.h0.base_registers[mmioIndex]);
535 	ERROR("GMR base = 0x%" B_PRIxPHYSADDR "\n", info.aperture_physical_base);
536 
537 	AreaKeeper apertureMapper;
538 	info.aperture_area = apertureMapper.Map("intel graphics aperture",
539 		info.aperture_physical_base, info.aperture_size,
540 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
541 		B_READ_AREA | B_WRITE_AREA, (void**)&info.aperture_base);
542 	if (apertureMapper.InitCheck() < B_OK) {
543 		// try again without write combining
544 		ERROR("enabling write combined mode failed.\n");
545 
546 		info.aperture_area = apertureMapper.Map("intel graphics aperture",
547 			info.aperture_physical_base, info.aperture_size,
548 			B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA,
549 			(void**)&info.aperture_base);
550 	}
551 	if (apertureMapper.InitCheck() < B_OK) {
552 		ERROR("could not map graphics aperture!\n");
553 		return info.aperture_area;
554 	}
555 
556 	info.scratch_page = entry.address;
557 
558 	gttMapper.Detach();
559 	mmioMapper.Detach();
560 	scratchCreator.Detach();
561 	apertureMapper.Detach();
562 
563 	return B_OK;
564 }
565 
566 
567 //	#pragma mark - module interface
568 
569 
570 status_t
571 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
572 	void** _aperture)
573 {
574 	// TODO: we currently only support a single AGP bridge!
575 	if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device
576 			|| function != sInfo.bridge.function)
577 		&& (bus != sInfo.display.bus || device != sInfo.display.device
578 			|| function != sInfo.display.function))
579 		return B_BAD_VALUE;
580 
581 	sInfo.aperture_size = size;
582 
583 	if (intel_map(sInfo) < B_OK)
584 		return B_ERROR;
585 
586 	uint16 gmchControl = get_pci_config(sInfo.bridge,
587 		INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED;
588 	set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl);
589 
590 	write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL,
591 		sInfo.gtt_physical_base | PAGE_TABLE_ENABLED);
592 	read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL);
593 
594 	if (sInfo.scratch_page != 0) {
595 		for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) {
596 			set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page);
597 		}
598 		read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
599 	}
600 
601 	asm("wbinvd;");
602 
603 	*_aperture = NULL;
604 	return B_OK;
605 }
606 
607 
608 void
609 intel_delete_aperture(void* aperture)
610 {
611 	intel_unmap(sInfo);
612 }
613 
614 
615 static status_t
616 intel_get_aperture_info(void* aperture, aperture_info* info)
617 {
618 	if (info == NULL)
619 		return B_BAD_VALUE;
620 
621 	info->base = sInfo.aperture_base;
622 	info->physical_base = sInfo.aperture_physical_base;
623 	info->size = sInfo.aperture_size;
624 	info->reserved_size = sInfo.aperture_stolen_size;
625 
626 	return B_OK;
627 }
628 
629 
630 status_t
631 intel_set_aperture_size(void* aperture, size_t size)
632 {
633 	return B_ERROR;
634 }
635 
636 
637 static status_t
638 intel_bind_page(void* aperture, uint32 offset, phys_addr_t physicalAddress)
639 {
640 	//TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress);
641 
642 	set_gtt_entry(sInfo, offset, physicalAddress);
643 	return B_OK;
644 }
645 
646 
647 static status_t
648 intel_unbind_page(void* aperture, uint32 offset)
649 {
650 	//TRACE("unbind_page(offset %lx)\n", offset);
651 
652 	if (sInfo.scratch_page != 0)
653 		set_gtt_entry(sInfo, offset, sInfo.scratch_page);
654 
655 	return B_OK;
656 }
657 
658 
659 void
660 intel_flush_tlbs(void* aperture)
661 {
662 	read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
663 	asm("wbinvd;");
664 }
665 
666 
667 //	#pragma mark -
668 
669 
670 static status_t
671 intel_init()
672 {
673 	TRACE("bus manager init\n");
674 
675 	if (get_module(B_PCI_MODULE_NAME, (module_info**)&sPCI) != B_OK)
676 		return B_ERROR;
677 
678 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK;
679 			index++) {
680 		if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL
681 			|| sInfo.bridge.class_base != PCI_bridge)
682 			continue;
683 
684 		// check device
685 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
686 				/ sizeof(kSupportedDevices[0]); i++) {
687 			if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
688 				sInfo.type = new DeviceType(kSupportedDevices[i].type);
689 				if (has_display_device(sInfo.display,
690 						kSupportedDevices[i].display_id)) {
691 					TRACE("found intel bridge\n");
692 					return B_OK;
693 				}
694 			}
695 		}
696 	}
697 
698 	return ENODEV;
699 }
700 
701 
702 static void
703 intel_uninit()
704 {
705 	if (sInfo.type)
706 		delete sInfo.type;
707 }
708 
709 
710 static int32
711 intel_std_ops(int32 op, ...)
712 {
713 	switch (op) {
714 		case B_MODULE_INIT:
715 			return intel_init();
716 		case B_MODULE_UNINIT:
717 			intel_uninit();
718 			return B_OK;
719 	}
720 
721 	return B_BAD_VALUE;
722 }
723 
724 
725 static struct agp_gart_bus_module_info sIntelModuleInfo = {
726 	{
727 		"busses/agp_gart/intel/v0",
728 		0,
729 		intel_std_ops
730 	},
731 
732 	intel_create_aperture,
733 	intel_delete_aperture,
734 
735 	intel_get_aperture_info,
736 	intel_set_aperture_size,
737 	intel_bind_page,
738 	intel_unbind_page,
739 	intel_flush_tlbs
740 };
741 
742 module_info* modules[] = {
743 	(module_info*)&sIntelModuleInfo,
744 	NULL
745 };
746