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