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