xref: /haiku/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp (revision 19ae20e67e91fc09cc9fc5c0e60e21e24e7a53eb)
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 
98 struct intel_info {
99 	pci_info	bridge;
100 	pci_info	display;
101 	uint32		type;
102 
103 	uint32		*gtt_base;
104 	addr_t		gtt_physical_base;
105 	area_id		gtt_area;
106 	size_t		gtt_entries;
107 	size_t		gtt_stolen_entries;
108 
109 	vuint32		*registers;
110 	area_id		registers_area;
111 
112 	addr_t		aperture_base;
113 	addr_t		aperture_physical_base;
114 	area_id		aperture_area;
115 	size_t		aperture_size;
116 	size_t		aperture_stolen_size;
117 
118 	phys_addr_t	scratch_page;
119 	area_id		scratch_area;
120 };
121 
122 static intel_info sInfo;
123 static pci_module_info* sPCI;
124 
125 
126 static bool
127 has_display_device(pci_info &info, uint32 deviceID)
128 {
129 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK;
130 			index++) {
131 		if (info.vendor_id != VENDOR_ID_INTEL
132 			|| info.device_id != deviceID
133 			|| info.class_base != PCI_display)
134 			continue;
135 
136 		return true;
137 	}
138 
139 	return false;
140 }
141 
142 
143 static void
144 determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
145 {
146 	// read stolen memory from the PCI configuration of the PCI bridge
147 	uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL;
148 	if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB)
149 		controlRegister = SNB_GRAPHICS_MEMORY_CONTROL;
150 
151 	uint16 memoryConfig = get_pci_config(info.bridge, controlRegister, 2);
152 	size_t memorySize = 1 << 20; // 1 MB
153 	gttSize = 0;
154 	stolenSize = 0;
155 
156 	if (info.type == INTEL_TYPE_965) {
157 		switch (memoryConfig & i965_GTT_MASK) {
158 			case i965_GTT_128K:
159 				gttSize = 128 << 10;
160 				break;
161 			case i965_GTT_256K:
162 				gttSize = 256 << 10;
163 				break;
164 			case i965_GTT_512K:
165 				gttSize = 512 << 10;
166 				break;
167 		}
168 	} else if (info.type == INTEL_TYPE_G33
169 	           || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_IGD) {
170 		switch (memoryConfig & G33_GTT_MASK) {
171 			case G33_GTT_1M:
172 				gttSize = 1 << 20;
173 				break;
174 			case G33_GTT_2M:
175 				gttSize = 2 << 20;
176 				break;
177 		}
178 	} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
179 			|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK) {
180 		switch (memoryConfig & G4X_GTT_MASK) {
181 			case G4X_GTT_NONE:
182 				gttSize = 0;
183 				break;
184 			case G4X_GTT_1M_NO_IVT:
185 				gttSize = 1 << 20;
186 				break;
187 			case G4X_GTT_2M_NO_IVT:
188 			case G4X_GTT_2M_IVT:
189 				gttSize = 2 << 20;
190 				break;
191 			case G4X_GTT_3M_IVT:
192 				gttSize = 3 << 20;
193 				break;
194 			case G4X_GTT_4M_IVT:
195 				gttSize = 4 << 20;
196 				break;
197 		}
198 	} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
199 		switch (memoryConfig & SNB_GTT_SIZE_MASK) {
200 			case SNB_GTT_SIZE_NONE:
201 				gttSize = 0;
202 				break;
203 			case SNB_GTT_SIZE_1MB:
204 				gttSize = 1 << 20;
205 				break;
206 			case SNB_GTT_SIZE_2MB:
207 				gttSize = 2 << 20;
208 				break;
209 		}
210 	} else {
211 		// older models have the GTT as large as their frame buffer mapping
212 		// TODO: check if the i9xx version works with the i8xx chips as well
213 		size_t frameBufferSize = 0;
214 		if ((info.type & INTEL_TYPE_8xx) != 0) {
215 			if (info.type == INTEL_TYPE_83x
216 				&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
217 				frameBufferSize = 64 << 20;
218 			else
219 				frameBufferSize = 128 << 20;
220 		} else if ((info.type & INTEL_TYPE_9xx) != 0)
221 			frameBufferSize = info.display.u.h0.base_register_sizes[2];
222 
223 		TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
224 		gttSize = frameBufferSize / 1024;
225 	}
226 
227 	// TODO: test with different models!
228 
229 	if (info.type == INTEL_TYPE_83x) {
230 		// Older chips
231 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
232 			case i830_LOCAL_MEMORY_ONLY:
233 				// TODO: determine its size!
234 				dprintf("intel_gart: getting local memory size not "
235 					"implemented.\n");
236 				break;
237 			case i830_STOLEN_512K:
238 				memorySize >>= 1;
239 				break;
240 			case i830_STOLEN_1M:
241 				// default case
242 				break;
243 			case i830_STOLEN_8M:
244 				memorySize *= 8;
245 				break;
246 		}
247 	} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
248 		switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) {
249 			case SNB_STOLEN_MEMORY_32MB:
250 				memorySize *= 32;
251 				break;
252 			case SNB_STOLEN_MEMORY_64MB:
253 				memorySize *= 64;
254 				break;
255 			case SNB_STOLEN_MEMORY_96MB:
256 				memorySize *= 96;
257 				break;
258 			case SNB_STOLEN_MEMORY_128MB:
259 				memorySize *= 128;
260 				break;
261 			case SNB_STOLEN_MEMORY_160MB:
262 				memorySize *= 160;
263 				break;
264 			case SNB_STOLEN_MEMORY_192MB:
265 				memorySize *= 192;
266 				break;
267 			case SNB_STOLEN_MEMORY_224MB:
268 				memorySize *= 224;
269 				break;
270 			case SNB_STOLEN_MEMORY_256MB:
271 				memorySize *= 256;
272 				break;
273 			case SNB_STOLEN_MEMORY_288MB:
274 				memorySize *= 288;
275 				break;
276 			case SNB_STOLEN_MEMORY_320MB:
277 				memorySize *= 320;
278 				break;
279 			case SNB_STOLEN_MEMORY_352MB:
280 				memorySize *= 352;
281 				break;
282 			case SNB_STOLEN_MEMORY_384MB:
283 				memorySize *= 384;
284 				break;
285 			case SNB_STOLEN_MEMORY_416MB:
286 				memorySize *= 416;
287 				break;
288 			case SNB_STOLEN_MEMORY_448MB:
289 				memorySize *= 448;
290 				break;
291 			case SNB_STOLEN_MEMORY_480MB:
292 				memorySize *= 480;
293 				break;
294 			case SNB_STOLEN_MEMORY_512MB:
295 				memorySize *= 512;
296 				break;
297 		}
298 	} else if (info.type == INTEL_TYPE_85x
299 		|| (info.type & INTEL_TYPE_9xx) == INTEL_TYPE_9xx) {
300 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
301 			case i855_STOLEN_MEMORY_4M:
302 				memorySize *= 4;
303 				break;
304 			case i855_STOLEN_MEMORY_8M:
305 				memorySize *= 8;
306 				break;
307 			case i855_STOLEN_MEMORY_16M:
308 				memorySize *= 16;
309 				break;
310 			case i855_STOLEN_MEMORY_32M:
311 				memorySize *= 32;
312 				break;
313 			case i855_STOLEN_MEMORY_48M:
314 				memorySize *= 48;
315 				break;
316 			case i855_STOLEN_MEMORY_64M:
317 				memorySize *= 64;
318 				break;
319 			case i855_STOLEN_MEMORY_128M:
320 				memorySize *= 128;
321 				break;
322 			case i855_STOLEN_MEMORY_256M:
323 				memorySize *= 256;
324 				break;
325 			case G4X_STOLEN_MEMORY_96MB:
326 				memorySize *= 96;
327 				break;
328 			case G4X_STOLEN_MEMORY_160MB:
329 				memorySize *= 160;
330 				break;
331 			case G4X_STOLEN_MEMORY_224MB:
332 				memorySize *= 224;
333 				break;
334 			case G4X_STOLEN_MEMORY_352MB:
335 				memorySize *= 352;
336 				break;
337 		}
338 	} else {
339 		// TODO: error out!
340 		memorySize = 4096;
341 	}
342 
343 	stolenSize = memorySize - 4096;
344 }
345 
346 
347 static void
348 set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
349 {
350 	// TODO: this is not 64-bit safe!
351 	write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
352 		(uint32)physicalAddress | GTT_ENTRY_VALID);
353 }
354 
355 
356 static void
357 intel_unmap(intel_info &info)
358 {
359 	delete_area(info.registers_area);
360 	delete_area(info.gtt_area);
361 	delete_area(info.scratch_area);
362 	delete_area(info.aperture_area);
363 	info.aperture_size = 0;
364 }
365 
366 
367 static status_t
368 intel_map(intel_info &info)
369 {
370 	int fbIndex = 0;
371 	int mmioIndex = 1;
372 	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
373 		// for some reason Intel saw the need to change the order of the
374 		// mappings with the introduction of the i9xx family
375 		mmioIndex = 0;
376 		fbIndex = 2;
377 	}
378 
379 	AreaKeeper mmioMapper;
380 	info.registers_area = mmioMapper.Map("intel GMCH mmio",
381 		(void*)info.display.u.h0.base_registers[mmioIndex],
382 		info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS,
383 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.registers);
384 	if (mmioMapper.InitCheck() < B_OK) {
385 		dprintf("agp_intel: could not map memory I/O!\n");
386 		return info.registers_area;
387 	}
388 
389 	// make sure bus master, memory-mapped I/O, and frame buffer is enabled
390 	set_pci_config(info.display, PCI_command, 2,
391 		get_pci_config(info.display, PCI_command, 2)
392 			| PCI_command_io | PCI_command_memory | PCI_command_master);
393 
394 	void* scratchAddress;
395 	AreaKeeper scratchCreator;
396 	info.scratch_area = scratchCreator.Create("intel GMCH scratch",
397 		&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
398 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
399 	if (scratchCreator.InitCheck() < B_OK) {
400 		dprintf("agp_intel: could not create scratch page!\n");
401 		return info.scratch_area;
402 	}
403 
404 	physical_entry entry;
405 	if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
406 		return B_ERROR;
407 
408 	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
409 		if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
410 			|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK
411 			|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
412 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
413 					+ (2UL << 20);
414 		} else
415 			info.gtt_physical_base
416 				= get_pci_config(info.display, i915_GTT_BASE, 4);
417 	} else {
418 		info.gtt_physical_base = read32(info.registers
419 			+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
420 		if (info.gtt_physical_base == 0) {
421 			// TODO: not sure how this is supposed to work under Linux/FreeBSD,
422 			// but on my i865, this code is needed for Haiku.
423 			dprintf("intel_gart: Use GTT address fallback.\n");
424 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
425 				+ i830_GTT_BASE;
426 		}
427 	}
428 
429 	size_t gttSize, stolenSize;
430 	determine_memory_sizes(info, gttSize, stolenSize);
431 
432 	info.gtt_entries = gttSize / 4096;
433 	info.gtt_stolen_entries = stolenSize / 4096;
434 
435 	TRACE("GTT base %lx, size %lu, entries %lu, stolen %lu\n",
436 		info.gtt_physical_base, gttSize, info.gtt_entries, stolenSize);
437 
438 	AreaKeeper gttMapper;
439 	info.gtt_area = gttMapper.Map("intel GMCH gtt",
440 		(void*)info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
441 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.gtt_base);
442 	if (gttMapper.InitCheck() < B_OK) {
443 		dprintf("intel_gart: could not map GTT!\n");
444 		return info.gtt_area;
445 	}
446 
447 	info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex];
448 	info.aperture_stolen_size = stolenSize;
449 	if (info.aperture_size == 0)
450 		info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
451 
452 	dprintf("intel_gart: detected %ld MB of stolen memory, aperture "
453 		"size %ld MB, GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
454 		info.aperture_size >> 20, gttSize >> 10);
455 
456 	dprintf("intel_gart: GTT base = 0x%lx\n", info.gtt_physical_base);
457 	dprintf("intel_gart: MMIO base = 0x%lx\n",
458 		info.display.u.h0.base_registers[mmioIndex]);
459 	dprintf("intel_gart: GMR base = 0x%lx\n", info.aperture_physical_base);
460 
461 	AreaKeeper apertureMapper;
462 	info.aperture_area = apertureMapper.Map("intel graphics aperture",
463 		(void*)info.aperture_physical_base, info.aperture_size,
464 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
465 		B_READ_AREA | B_WRITE_AREA, (void**)&info.aperture_base);
466 	if (apertureMapper.InitCheck() < B_OK) {
467 		// try again without write combining
468 		dprintf(DEVICE_NAME ": enabling write combined mode failed.\n");
469 
470 		info.aperture_area = apertureMapper.Map("intel graphics aperture",
471 			(void*)info.aperture_physical_base, info.aperture_size,
472 			B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA,
473 			(void**)&info.aperture_base);
474 	}
475 	if (apertureMapper.InitCheck() < B_OK) {
476 		dprintf(DEVICE_NAME ": could not map graphics aperture!\n");
477 		return info.aperture_area;
478 	}
479 
480 	info.scratch_page = entry.address;
481 
482 	gttMapper.Detach();
483 	mmioMapper.Detach();
484 	scratchCreator.Detach();
485 	apertureMapper.Detach();
486 
487 	return B_OK;
488 }
489 
490 
491 //	#pragma mark - module interface
492 
493 
494 status_t
495 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
496 	void** _aperture)
497 {
498 	// TODO: we currently only support a single AGP bridge!
499 	if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device
500 			|| function != sInfo.bridge.function)
501 		&& (bus != sInfo.display.bus || device != sInfo.display.device
502 			|| function != sInfo.display.function))
503 		return B_BAD_VALUE;
504 
505 	sInfo.aperture_size = size;
506 
507 	if (intel_map(sInfo) < B_OK)
508 		return B_ERROR;
509 
510 	uint16 gmchControl = get_pci_config(sInfo.bridge,
511 		INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED;
512 	set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl);
513 
514 	write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL,
515 		sInfo.gtt_physical_base | PAGE_TABLE_ENABLED);
516 	read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL);
517 
518 	if (sInfo.scratch_page != 0) {
519 		for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) {
520 			set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page);
521 		}
522 		read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
523 	}
524 
525 	asm("wbinvd;");
526 
527 	*_aperture = NULL;
528 	return B_OK;
529 }
530 
531 
532 void
533 intel_delete_aperture(void* aperture)
534 {
535 	intel_unmap(sInfo);
536 }
537 
538 
539 static status_t
540 intel_get_aperture_info(void* aperture, aperture_info* info)
541 {
542 	if (info == NULL)
543 		return B_BAD_VALUE;
544 
545 	info->base = sInfo.aperture_base;
546 	info->physical_base = sInfo.aperture_physical_base;
547 	info->size = sInfo.aperture_size;
548 	info->reserved_size = sInfo.aperture_stolen_size;
549 
550 	return B_OK;
551 }
552 
553 
554 status_t
555 intel_set_aperture_size(void* aperture, size_t size)
556 {
557 	return B_ERROR;
558 }
559 
560 
561 static status_t
562 intel_bind_page(void* aperture, uint32 offset, phys_addr_t physicalAddress)
563 {
564 	//TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress);
565 
566 	set_gtt_entry(sInfo, offset, physicalAddress);
567 	return B_OK;
568 }
569 
570 
571 static status_t
572 intel_unbind_page(void* aperture, uint32 offset)
573 {
574 	//TRACE("unbind_page(offset %lx)\n", offset);
575 
576 	if (sInfo.scratch_page != 0)
577 		set_gtt_entry(sInfo, offset, sInfo.scratch_page);
578 
579 	return B_OK;
580 }
581 
582 
583 void
584 intel_flush_tlbs(void* aperture)
585 {
586 	read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
587 	asm("wbinvd;");
588 }
589 
590 
591 //	#pragma mark -
592 
593 
594 static status_t
595 intel_init()
596 {
597 	TRACE("bus manager init\n");
598 
599 	if (get_module(B_PCI_MODULE_NAME, (module_info**)&sPCI) != B_OK)
600 		return B_ERROR;
601 
602 	bool found = false;
603 
604 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK;
605 			index++) {
606 		if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL
607 			|| sInfo.bridge.class_base != PCI_bridge)
608 			continue;
609 
610 		// check device
611 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
612 				/ sizeof(kSupportedDevices[0]); i++) {
613 			if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
614 				sInfo.type = kSupportedDevices[i].type;
615 				found = has_display_device(sInfo.display,
616 					kSupportedDevices[i].display_id);
617 			}
618 		}
619 
620 		if (found)
621 			break;
622 	}
623 
624 	if (!found)
625 		return ENODEV;
626 
627 	TRACE("found intel bridge\n");
628 	return B_OK;
629 }
630 
631 
632 static void
633 intel_uninit()
634 {
635 }
636 
637 
638 static int32
639 intel_std_ops(int32 op, ...)
640 {
641 	switch (op) {
642 		case B_MODULE_INIT:
643 			return intel_init();
644 		case B_MODULE_UNINIT:
645 			intel_uninit();
646 			return B_OK;
647 	}
648 
649 	return B_BAD_VALUE;
650 }
651 
652 
653 static struct agp_gart_bus_module_info sIntelModuleInfo = {
654 	{
655 		"busses/agp_gart/intel/v0",
656 		0,
657 		intel_std_ops
658 	},
659 
660 	intel_create_aperture,
661 	intel_delete_aperture,
662 
663 	intel_get_aperture_info,
664 	intel_set_aperture_size,
665 	intel_bind_page,
666 	intel_unbind_page,
667 	intel_flush_tlbs
668 };
669 
670 module_info* modules[] = {
671 	(module_info*)&sIntelModuleInfo,
672 	NULL
673 };
674