blob: f633533835381d19c3bfcbf909ec42a5723abbd9 [file] [log] [blame]
klu2c69dd9d2008-04-17 05:48:13 +00001/*++
2
hhtianb1f700a2010-04-28 12:39:50 +00003Copyright (c) 2005 - 2009, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
klu2c69dd9d2008-04-17 05:48:13 +00005are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution. The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13 PcatPciRootBridge.c
14
15Abstract:
16
17 EFI PC-AT PCI Root Bridge Controller
18
19--*/
20
21#include "PcatPciRootBridge.h"
22#include "DeviceIo.h"
23
xli24b6d793e2009-12-07 12:48:53 +000024EFI_CPU_IO2_PROTOCOL *gCpuIo;
klu2c69dd9d2008-04-17 05:48:13 +000025
26EFI_STATUS
27EFIAPI
28InitializePcatPciRootBridge (
29 IN EFI_HANDLE ImageHandle,
30 IN EFI_SYSTEM_TABLE *SystemTable
31 )
32/*++
33
34Routine Description:
35 Initializes the PCI Root Bridge Controller
36
37Arguments:
38 ImageHandle -
39 SystemTable -
40
41Returns:
42 None
43
44--*/
45{
qhuang8b29a8232009-08-21 02:51:09 +000046 EFI_STATUS Status;
klu2c69dd9d2008-04-17 05:48:13 +000047 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
48 UINTN PciSegmentIndex;
49 UINTN PciRootBridgeIndex;
50 UINTN PrimaryBusIndex;
51 UINTN NumberOfPciRootBridges;
52 UINTN NumberOfPciDevices;
53 UINTN Device;
54 UINTN Function;
55 UINT16 VendorId;
56 PCI_TYPE01 PciConfigurationHeader;
57 UINT64 Address;
58 UINT64 Value;
59 UINT64 Base;
60 UINT64 Limit;
61
62 //
63 // Initialize gCpuIo now since the chipset init code requires it.
64 //
xli24b6d793e2009-12-07 12:48:53 +000065 Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **)&gCpuIo);
klu2c69dd9d2008-04-17 05:48:13 +000066 ASSERT_EFI_ERROR (Status);
67
68 //
69 // Initialize variables required to search all PCI segments for PCI devices
70 //
71 PciSegmentIndex = 0;
72 PciRootBridgeIndex = 0;
73 NumberOfPciRootBridges = 0;
74 PrimaryBusIndex = 0;
75
76 while (PciSegmentIndex <= PCI_MAX_SEGMENT) {
77
78 PrivateData = NULL;
79 Status = gBS->AllocatePool(
80 EfiBootServicesData,
81 sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE),
jljusten8e53d242008-11-23 23:55:02 +000082 (VOID **)&PrivateData
klu2c69dd9d2008-04-17 05:48:13 +000083 );
84 if (EFI_ERROR (Status)) {
85 goto Done;
86 }
87
88 ZeroMem (PrivateData, sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE));
89
90 //
91 // Initialize the signature of the private data structure
92 //
93 PrivateData->Signature = PCAT_PCI_ROOT_BRIDGE_SIGNATURE;
94 PrivateData->Handle = NULL;
95 PrivateData->DevicePath = NULL;
qhuang8b29a8232009-08-21 02:51:09 +000096 InitializeListHead (&PrivateData->MapInfo);
klu2c69dd9d2008-04-17 05:48:13 +000097
98 //
99 // Initialize the PCI root bridge number and the bus range for that root bridge
100 //
101 PrivateData->RootBridgeNumber = (UINT32)PciRootBridgeIndex;
102 PrivateData->PrimaryBus = (UINT32)PrimaryBusIndex;
103 PrivateData->SubordinateBus = (UINT32)PrimaryBusIndex;
104
105 PrivateData->IoBase = 0xffffffff;
106 PrivateData->MemBase = 0xffffffff;
jljusten8e53d242008-11-23 23:55:02 +0000107 PrivateData->Mem32Base = 0xffffffffffffffffULL;
108 PrivateData->Pmem32Base = 0xffffffffffffffffULL;
109 PrivateData->Mem64Base = 0xffffffffffffffffULL;
110 PrivateData->Pmem64Base = 0xffffffffffffffffULL;
klu2c69dd9d2008-04-17 05:48:13 +0000111
112 //
113 // The default mechanism for performing PCI Configuration cycles is to
114 // use the I/O ports at 0xCF8 and 0xCFC. This is only used for IA-32.
115 // IPF uses SAL calls to perform PCI COnfiguration cycles
116 //
117 PrivateData->PciAddress = 0xCF8;
118 PrivateData->PciData = 0xCFC;
119
120 //
121 // Get the physical I/O base for performing PCI I/O cycles
122 // For IA-32, this is always 0, because IA-32 has IN and OUT instructions
123 // For IPF, a SAL call is made to retrieve the base address for PCI I/O cycles
124 //
125 Status = PcatRootBridgeIoGetIoPortMapping (
126 &PrivateData->PhysicalIoBase,
127 &PrivateData->PhysicalMemoryBase
128 );
129 if (EFI_ERROR (Status)) {
130 goto Done;
131 }
132
133 //
134 // Get PCI Express Base Address
135 //
136 PrivateData->PciExpressBaseAddress = GetPciExpressBaseAddressForRootBridge (PciSegmentIndex, PciRootBridgeIndex);
137 if (PrivateData->PciExpressBaseAddress != 0) {
138 DEBUG ((EFI_D_ERROR, "PCIE Base - 0x%lx\n", PrivateData->PciExpressBaseAddress));
139 }
140
141 //
142 // Create a lock for performing PCI Configuration cycles
143 //
144 EfiInitializeLock (&PrivateData->PciLock, TPL_HIGH_LEVEL);
145
146 //
147 // Initialize the attributes for this PCI root bridge
148 //
149 PrivateData->Attributes = 0;
150
151 //
152 // Build the EFI Device Path Protocol instance for this PCI Root Bridge
153 //
klu22b7d16c2008-11-27 09:11:41 +0000154 Status = PcatRootBridgeDevicePathConstructor (&PrivateData->DevicePath, PciRootBridgeIndex, (BOOLEAN)((PrivateData->PciExpressBaseAddress != 0) ? TRUE : FALSE));
klu2c69dd9d2008-04-17 05:48:13 +0000155 if (EFI_ERROR (Status)) {
156 goto Done;
157 }
158
159 //
160 // Build the PCI Root Bridge I/O Protocol instance for this PCI Root Bridge
161 //
162 Status = PcatRootBridgeIoConstructor (&PrivateData->Io, PciSegmentIndex);
163 if (EFI_ERROR (Status)) {
164 goto Done;
165 }
166
167 //
168 // Scan all the PCI devices on the primary bus of the PCI root bridge
169 //
170 for (Device = 0, NumberOfPciDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {
171
172 for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
173
174 //
175 // Compute the PCI configuration address of the PCI device to probe
176 //
177 Address = EFI_PCI_ADDRESS (PrimaryBusIndex, Device, Function, 0);
178
179 //
180 // Read the Vendor ID from the PCI Configuration Header
181 //
182 Status = PrivateData->Io.Pci.Read (
183 &PrivateData->Io,
184 EfiPciWidthUint16,
185 Address,
klu21d0cab22009-02-23 14:05:41 +0000186 sizeof (VendorId) / sizeof (UINT16),
klu2c69dd9d2008-04-17 05:48:13 +0000187 &VendorId
188 );
189 if ((EFI_ERROR (Status)) || ((VendorId == 0xffff) && (Function == 0))) {
190 //
191 // If the PCI Configuration Read fails, or a PCI device does not exist, then
192 // skip this entire PCI device
193 //
194 break;
195 }
196 if (VendorId == 0xffff) {
197 //
198 // If PCI function != 0, VendorId == 0xFFFF, we continue to search PCI function.
199 //
200 continue;
201 }
202
203 //
204 // Read the entire PCI Configuration Header
205 //
206 Status = PrivateData->Io.Pci.Read (
207 &PrivateData->Io,
klu21d0cab22009-02-23 14:05:41 +0000208 EfiPciWidthUint16,
klu2c69dd9d2008-04-17 05:48:13 +0000209 Address,
klu21d0cab22009-02-23 14:05:41 +0000210 sizeof (PciConfigurationHeader) / sizeof (UINT16),
klu2c69dd9d2008-04-17 05:48:13 +0000211 &PciConfigurationHeader
212 );
213 if (EFI_ERROR (Status)) {
214 //
215 // If the entire PCI Configuration Header can not be read, then skip this entire PCI device
216 //
217 break;
218 }
219
jljusten8e53d242008-11-23 23:55:02 +0000220
klu2c69dd9d2008-04-17 05:48:13 +0000221 //
222 // Increment the number of PCI device found on the primary bus of the PCI root bridge
223 //
224 NumberOfPciDevices++;
225
226 //
227 // Look for devices with the VGA Palette Snoop enabled in the COMMAND register of the PCI Config Header
228 //
229 if (PciConfigurationHeader.Hdr.Command & 0x20) {
230 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
231 }
232
233 //
234 // If the device is a PCI-PCI Bridge, then look at the Subordinate Bus Number
235 //
236 if (IS_PCI_BRIDGE(&PciConfigurationHeader)) {
237 //
238 // Get the Bus range that the PPB is decoding
239 //
240 if (PciConfigurationHeader.Bridge.SubordinateBus > PrivateData->SubordinateBus) {
241 //
242 // If the suborinate bus number of the PCI-PCI bridge is greater than the PCI root bridge's
243 // current subordinate bus number, then update the PCI root bridge's subordinate bus number
244 //
245 PrivateData->SubordinateBus = PciConfigurationHeader.Bridge.SubordinateBus;
246 }
247
248 //
249 // Get the I/O range that the PPB is decoding
250 //
251 Value = PciConfigurationHeader.Bridge.IoBase & 0x0f;
252 Base = ((UINT32)PciConfigurationHeader.Bridge.IoBase & 0xf0) << 8;
253 Limit = (((UINT32)PciConfigurationHeader.Bridge.IoLimit & 0xf0) << 8) | 0x0fff;
254 if (Value == 0x01) {
255 Base |= ((UINT32)PciConfigurationHeader.Bridge.IoBaseUpper16 << 16);
256 Limit |= ((UINT32)PciConfigurationHeader.Bridge.IoLimitUpper16 << 16);
257 }
258 if (Base < Limit) {
259 if (PrivateData->IoBase > Base) {
260 PrivateData->IoBase = Base;
261 }
262 if (PrivateData->IoLimit < Limit) {
263 PrivateData->IoLimit = Limit;
264 }
265 }
266
267 //
268 // Get the Memory range that the PPB is decoding
269 //
270 Base = ((UINT32)PciConfigurationHeader.Bridge.MemoryBase & 0xfff0) << 16;
271 Limit = (((UINT32)PciConfigurationHeader.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
272 if (Base < Limit) {
273 if (PrivateData->MemBase > Base) {
274 PrivateData->MemBase = Base;
275 }
276 if (PrivateData->MemLimit < Limit) {
277 PrivateData->MemLimit = Limit;
278 }
279 if (PrivateData->Mem32Base > Base) {
280 PrivateData->Mem32Base = Base;
281 }
282 if (PrivateData->Mem32Limit < Limit) {
283 PrivateData->Mem32Limit = Limit;
284 }
285 }
286
287 //
288 // Get the Prefetchable Memory range that the PPB is decoding
289 //
290 Value = PciConfigurationHeader.Bridge.PrefetchableMemoryBase & 0x0f;
291 Base = ((UINT32)PciConfigurationHeader.Bridge.PrefetchableMemoryBase & 0xfff0) << 16;
292 Limit = (((UINT32)PciConfigurationHeader.Bridge.PrefetchableMemoryLimit & 0xfff0) << 16) | 0xffffff;
293 if (Value == 0x01) {
294 Base |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.PrefetchableBaseUpper32,32);
295 Limit |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.PrefetchableLimitUpper32,32);
296 }
297 if (Base < Limit) {
298 if (PrivateData->MemBase > Base) {
299 PrivateData->MemBase = Base;
300 }
301 if (PrivateData->MemLimit < Limit) {
302 PrivateData->MemLimit = Limit;
303 }
304 if (Value == 0x00) {
305 if (PrivateData->Pmem32Base > Base) {
306 PrivateData->Pmem32Base = Base;
307 }
308 if (PrivateData->Pmem32Limit < Limit) {
309 PrivateData->Pmem32Limit = Limit;
310 }
311 }
312 if (Value == 0x01) {
313 if (PrivateData->Pmem64Base > Base) {
314 PrivateData->Pmem64Base = Base;
315 }
316 if (PrivateData->Pmem64Limit < Limit) {
317 PrivateData->Pmem64Limit = Limit;
318 }
319 }
320 }
321
322 //
323 // Look at the PPB Configuration for legacy decoding attributes
324 //
325 if (PciConfigurationHeader.Bridge.BridgeControl & 0x04) {
326 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
327 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
328 }
329 if (PciConfigurationHeader.Bridge.BridgeControl & 0x08) {
330 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
331 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
332 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
333 }
334
335 } else {
336 //
337 // Parse the BARs of the PCI device to determine what I/O Ranges,
338 // Memory Ranges, and Prefetchable Memory Ranges the device is decoding
339 //
340 if ((PciConfigurationHeader.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
341 Status = PcatPciRootBridgeParseBars (
342 PrivateData,
343 PciConfigurationHeader.Hdr.Command,
344 PrimaryBusIndex,
345 Device,
346 Function
347 );
348 }
349
350 //
351 // See if the PCI device is an IDE controller
352 //
353 if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x01 &&
354 PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) {
355 if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x80) {
356 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
357 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
358 }
359 if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x01) {
360 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
361 }
362 if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x04) {
363 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
364 }
365 }
366
367 //
368 // See if the PCI device is a legacy VGA controller
369 //
370 if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x00 &&
371 PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) {
372 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
373 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
374 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
375 }
376
377 //
378 // See if the PCI device is a standard VGA controller
379 //
380 if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x03 &&
381 PciConfigurationHeader.Hdr.ClassCode[1] == 0x00 ) {
382 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
383 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
384 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
385 }
386
387 //
388 // See if the PCI Device is a PCI - ISA or PCI - EISA
389 // or ISA_POSITIVIE_DECODE Bridge device
390 //
391 if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x06) {
392 if (PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ||
393 PciConfigurationHeader.Hdr.ClassCode[1] == 0x02 ||
394 PciConfigurationHeader.Hdr.ClassCode[1] == 0x80 ) {
395 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
396 PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
397
398 if (PrivateData->MemBase > 0xa0000) {
399 PrivateData->MemBase = 0xa0000;
400 }
401 if (PrivateData->MemLimit < 0xbffff) {
402 PrivateData->MemLimit = 0xbffff;
403 }
404 }
405 }
406 }
407
408 //
409 // If this device is not a multi function device, then skip the rest of this PCI device
410 //
411 if (Function == 0 && !(PciConfigurationHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)) {
412 break;
413 }
414 }
415 }
416
417 //
418 // After scanning all the PCI devices on the PCI root bridge's primary bus, update the
419 // Primary Bus Number for the next PCI root bridge to be this PCI root bridge's subordinate
420 // bus number + 1.
421 //
422 PrimaryBusIndex = PrivateData->SubordinateBus + 1;
423
424 //
425 // If at least one PCI device was found on the primary bus of this PCI root bridge, then the PCI root bridge
426 // exists.
427 //
428 if (NumberOfPciDevices > 0) {
429
430 //
431 // Adjust the I/O range used for bounds checking for the legacy decoding attributed
432 //
433 if (PrivateData->Attributes & 0x7f) {
434 PrivateData->IoBase = 0;
435 if (PrivateData->IoLimit < 0xffff) {
436 PrivateData->IoLimit = 0xffff;
437 }
438 }
439
440 //
441 // Adjust the Memory range used for bounds checking for the legacy decoding attributed
442 //
443 if (PrivateData->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) {
444 if (PrivateData->MemBase > 0xa0000) {
445 PrivateData->MemBase = 0xa0000;
446 }
447 if (PrivateData->MemLimit < 0xbffff) {
448 PrivateData->MemLimit = 0xbffff;
449 }
450 }
451
452 //
453 // Build ACPI descriptors for the resources on the PCI Root Bridge
454 //
455 Status = ConstructConfiguration(PrivateData);
456 ASSERT_EFI_ERROR (Status);
457
458 //
459 // Create the handle for this PCI Root Bridge
460 //
461 Status = gBS->InstallMultipleProtocolInterfaces (
462 &PrivateData->Handle,
463 &gEfiDevicePathProtocolGuid,
464 PrivateData->DevicePath,
465 &gEfiPciRootBridgeIoProtocolGuid,
466 &PrivateData->Io,
467 NULL
468 );
469 ASSERT_EFI_ERROR (Status);
470
471 //
472 // Contruct DeviceIoProtocol
473 //
474 Status = DeviceIoConstructor (
475 PrivateData->Handle,
476 &PrivateData->Io,
477 PrivateData->DevicePath,
478 (UINT16)PrivateData->PrimaryBus,
479 (UINT16)PrivateData->SubordinateBus
480 );
481 ASSERT_EFI_ERROR (Status);
482
483 //
484 // Scan this PCI Root Bridge for PCI Option ROMs and add them to the PCI Option ROM Table
485 //
486 Status = ScanPciRootBridgeForRoms(&PrivateData->Io);
487
488 //
489 // Increment the index for the next PCI Root Bridge
490 //
491 PciRootBridgeIndex++;
492
493 } else {
494
495 //
496 // If no PCI Root Bridges were found on the current PCI segment, then exit
497 //
498 if (NumberOfPciRootBridges == 0) {
499 Status = EFI_SUCCESS;
500 goto Done;
501 }
502
503 }
504
505 //
506 // If the PrimaryBusIndex is greater than the maximum allowable PCI bus number, then
507 // the PCI Segment Number is incremented, and the next segment is searched starting at Bus #0
508 // Otherwise, the search is continued on the next PCI Root Bridge
509 //
510 if (PrimaryBusIndex > PCI_MAX_BUS) {
511 PciSegmentIndex++;
512 NumberOfPciRootBridges = 0;
513 PrimaryBusIndex = 0;
514 } else {
515 NumberOfPciRootBridges++;
516 }
517
518 }
519
520 return EFI_SUCCESS;
521
522Done:
523 //
524 // Clean up memory allocated for the PCI Root Bridge that was searched but not created.
525 //
526 if (PrivateData) {
527 if (PrivateData->DevicePath) {
528 gBS->FreePool(PrivateData->DevicePath);
529 }
530 gBS->FreePool (PrivateData);
531 }
532
533 //
534 // If no PCI Root Bridges were discovered, then return the error condition from scanning the
535 // first PCI Root Bridge
536 //
537 if (PciRootBridgeIndex == 0) {
538 return Status;
539 }
540
541 return EFI_SUCCESS;
542}
543
544EFI_STATUS
545ConstructConfiguration(
546 IN OUT PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData
547 )
548/*++
549
550Routine Description:
551
552Arguments:
553
554Returns:
555
556 None
557
558--*/
559
560{
561 EFI_STATUS Status;
562 UINT8 NumConfig;
563 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
564 EFI_ACPI_END_TAG_DESCRIPTOR *ConfigurationEnd;
565
566 NumConfig = 0;
567 PrivateData->Configuration = NULL;
568
569 if (PrivateData->SubordinateBus >= PrivateData->PrimaryBus) {
570 NumConfig++;
571 }
572 if (PrivateData->IoLimit >= PrivateData->IoBase) {
573 NumConfig++;
574 }
575 if (PrivateData->Mem32Limit >= PrivateData->Mem32Base) {
576 NumConfig++;
577 }
578 if (PrivateData->Pmem32Limit >= PrivateData->Pmem32Base) {
579 NumConfig++;
580 }
581 if (PrivateData->Mem64Limit >= PrivateData->Mem64Base) {
582 NumConfig++;
583 }
584 if (PrivateData->Pmem64Limit >= PrivateData->Pmem64Base) {
585 NumConfig++;
586 }
587
588 if ( NumConfig == 0 ) {
589
590 //
591 // If there is no resource request
592 //
593 Status = gBS->AllocatePool (
594 EfiBootServicesData,
595 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
jljusten8e53d242008-11-23 23:55:02 +0000596 (VOID **)&PrivateData->Configuration
klu2c69dd9d2008-04-17 05:48:13 +0000597 );
598 if (EFI_ERROR (Status )) {
599 return Status;
600 }
601
602 Configuration = PrivateData->Configuration;
603
604 ZeroMem (
605 Configuration,
606 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
607 );
608
609 Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
610 Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
611 Configuration++;
612
613 ConfigurationEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Configuration);
614 ConfigurationEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
615 ConfigurationEnd->Checksum = 0;
616 }
617
618 //
619 // If there is at least one type of resource request,
620 // allocate a acpi resource node
621 //
622 Status = gBS->AllocatePool (
623 EfiBootServicesData,
624 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
jljusten8e53d242008-11-23 23:55:02 +0000625 (VOID **)&PrivateData->Configuration
klu2c69dd9d2008-04-17 05:48:13 +0000626 );
627 if (EFI_ERROR (Status )) {
628 return Status;
629 }
630
631 Configuration = PrivateData->Configuration;
632
633 ZeroMem (
634 Configuration,
635 sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
636 );
637
638 if (PrivateData->SubordinateBus >= PrivateData->PrimaryBus) {
639 Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
640 Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
641 Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
642 Configuration->SpecificFlag = 0;
643 Configuration->AddrRangeMin = PrivateData->PrimaryBus;
644 Configuration->AddrRangeMax = PrivateData->SubordinateBus;
645 Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1;
646 Configuration++;
647 }
648 //
649 // Deal with io aperture
650 //
651 if (PrivateData->IoLimit >= PrivateData->IoBase) {
652 Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
653 Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
654 Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
655 Configuration->SpecificFlag = 1; //non ISA range
656 Configuration->AddrRangeMin = PrivateData->IoBase;
657 Configuration->AddrRangeMax = PrivateData->IoLimit;
658 Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1;
659 Configuration++;
660 }
661
662 //
663 // Deal with mem32 aperture
664 //
665 if (PrivateData->Mem32Limit >= PrivateData->Mem32Base) {
666 Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
667 Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
668 Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
669 Configuration->SpecificFlag = 0; //Nonprefechable
670 Configuration->AddrSpaceGranularity = 32; //32 bit
671 Configuration->AddrRangeMin = PrivateData->Mem32Base;
672 Configuration->AddrRangeMax = PrivateData->Mem32Limit;
673 Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1;
674 Configuration++;
675 }
676
677 //
678 // Deal with Pmem32 aperture
679 //
680 if (PrivateData->Pmem32Limit >= PrivateData->Pmem32Base) {
681 Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
682 Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
683 Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
684 Configuration->SpecificFlag = 0x6; //prefechable
685 Configuration->AddrSpaceGranularity = 32; //32 bit
686 Configuration->AddrRangeMin = PrivateData->Pmem32Base;
687 Configuration->AddrRangeMax = PrivateData->Pmem32Limit;
688 Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1;
689 Configuration++;
690 }
691
692 //
693 // Deal with mem64 aperture
694 //
695 if (PrivateData->Mem64Limit >= PrivateData->Mem64Base) {
696 Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
697 Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
698 Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
699 Configuration->SpecificFlag = 0; //nonprefechable
700 Configuration->AddrSpaceGranularity = 64; //32 bit
701 Configuration->AddrRangeMin = PrivateData->Mem64Base;
702 Configuration->AddrRangeMax = PrivateData->Mem64Limit;
703 Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1;
704 Configuration++;
705 }
706
707 //
708 // Deal with Pmem64 aperture
709 //
710 if (PrivateData->Pmem64Limit >= PrivateData->Pmem64Base) {
711 Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
712 Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
713 Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
714 Configuration->SpecificFlag = 0x06; //prefechable
715 Configuration->AddrSpaceGranularity = 64; //32 bit
716 Configuration->AddrRangeMin = PrivateData->Pmem64Base;
717 Configuration->AddrRangeMax = PrivateData->Pmem64Limit;
718 Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1;
719 Configuration++;
720 }
721
722 //
723 // put the checksum
724 //
725 ConfigurationEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Configuration);
726 ConfigurationEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
727 ConfigurationEnd->Checksum = 0;
728
729 return EFI_SUCCESS;
730}
731
732EFI_STATUS
733PcatPciRootBridgeBarExisted (
734 IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData,
735 IN UINT64 Address,
736 OUT UINT32 *OriginalValue,
737 OUT UINT32 *Value
738 )
739/*++
740
741Routine Description:
742
743Arguments:
744
745Returns:
746
747 None
748
749--*/
750{
751 EFI_STATUS Status;
752 UINT32 AllOnes;
753 EFI_TPL OldTpl;
754
755 //
756 // Preserve the original value
757 //
758 Status = PrivateData->Io.Pci.Read (
759 &PrivateData->Io,
760 EfiPciWidthUint32,
761 Address,
762 1,
763 OriginalValue
764 );
765
766 //
767 // Raise TPL to high level to disable timer interrupt while the BAR is probed
768 //
769 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
770
771 AllOnes = 0xffffffff;
772
773 Status = PrivateData->Io.Pci.Write (
774 &PrivateData->Io,
775 EfiPciWidthUint32,
776 Address,
777 1,
778 &AllOnes
779 );
780 Status = PrivateData->Io.Pci.Read (
781 &PrivateData->Io,
782 EfiPciWidthUint32,
783 Address,
784 1,
785 Value
786 );
787
788 //
789 //Write back the original value
790 //
791 Status = PrivateData->Io.Pci.Write (
792 &PrivateData->Io,
793 EfiPciWidthUint32,
794 Address,
795 1,
796 OriginalValue
797 );
798
799 //
800 // Restore TPL to its original level
801 //
802 gBS->RestoreTPL (OldTpl);
803
804 if ( *Value == 0 ) {
805 return EFI_DEVICE_ERROR;
806 }
klu22b7d16c2008-11-27 09:11:41 +0000807 return Status;
klu2c69dd9d2008-04-17 05:48:13 +0000808}
809
810EFI_STATUS
811PcatPciRootBridgeParseBars (
812 IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData,
813 IN UINT16 Command,
814 IN UINTN Bus,
815 IN UINTN Device,
816 IN UINTN Function
817 )
818/*++
819
820Routine Description:
821
822Arguments:
823
824Returns:
825
826 None
827
828--*/
829{
830 EFI_STATUS Status;
831 UINT64 Address;
832 UINT32 OriginalValue;
833 UINT32 Value;
834 UINT32 OriginalUpperValue;
835 UINT32 UpperValue;
836 UINT64 Mask;
837 UINTN Offset;
838 UINT64 Base;
839 UINT64 Length;
840 UINT64 Limit;
841
842 for (Offset = 0x10; Offset < 0x28; Offset += 4) {
843 Address = EFI_PCI_ADDRESS (Bus, Device, Function, Offset);
844 Status = PcatPciRootBridgeBarExisted (
845 PrivateData,
846 Address,
847 &OriginalValue,
848 &Value
849 );
850
851 if (!EFI_ERROR (Status )) {
852 if ( Value & 0x01 ) {
853 if (Command & 0x0001) {
854 //
855 //Device I/Os
856 //
857 Mask = 0xfffffffc;
858 Base = OriginalValue & Mask;
859 Length = ((~(Value & Mask)) & Mask) + 0x04;
860 if (!(Value & 0xFFFF0000)){
861 Length &= 0x0000FFFF;
862 }
863 Limit = Base + Length - 1;
864
865 if (Base < Limit) {
866 if (PrivateData->IoBase > Base) {
867 PrivateData->IoBase = (UINT32)Base;
868 }
869 if (PrivateData->IoLimit < Limit) {
870 PrivateData->IoLimit = (UINT32)Limit;
871 }
872 }
873 }
874
875 } else {
876
877 if (Command & 0x0002) {
878
879 Mask = 0xfffffff0;
880 Base = OriginalValue & Mask;
881 Length = Value & Mask;
882
883 if ((Value & 0x07) != 0x04) {
884 Length = ((~Length) + 1) & 0xffffffff;
885 } else {
886 Offset += 4;
887 Address = EFI_PCI_ADDRESS (Bus, Device, Function, Offset);
888
889 Status = PcatPciRootBridgeBarExisted (
890 PrivateData,
891 Address,
892 &OriginalUpperValue,
893 &UpperValue
894 );
895
896 Base = Base | LShiftU64((UINT64)OriginalUpperValue,32);
897 Length = Length | LShiftU64((UINT64)UpperValue,32);
898 Length = (~Length) + 1;
899 }
900
901 Limit = Base + Length - 1;
902
903 if (Base < Limit) {
904 if (PrivateData->MemBase > Base) {
905 PrivateData->MemBase = Base;
906 }
907 if (PrivateData->MemLimit < Limit) {
908 PrivateData->MemLimit = Limit;
909 }
910
911 switch (Value &0x07) {
912 case 0x00: ////memory space; anywhere in 32 bit address space
913 if (Value & 0x08) {
914 if (PrivateData->Pmem32Base > Base) {
915 PrivateData->Pmem32Base = Base;
916 }
917 if (PrivateData->Pmem32Limit < Limit) {
918 PrivateData->Pmem32Limit = Limit;
919 }
920 } else {
921 if (PrivateData->Mem32Base > Base) {
922 PrivateData->Mem32Base = Base;
923 }
924 if (PrivateData->Mem32Limit < Limit) {
925 PrivateData->Mem32Limit = Limit;
926 }
927 }
928 break;
929 case 0x04: //memory space; anywhere in 64 bit address space
930 if (Value & 0x08) {
931 if (PrivateData->Pmem64Base > Base) {
932 PrivateData->Pmem64Base = Base;
933 }
934 if (PrivateData->Pmem64Limit < Limit) {
935 PrivateData->Pmem64Limit = Limit;
936 }
937 } else {
938 if (PrivateData->Mem64Base > Base) {
939 PrivateData->Mem64Base = Base;
940 }
941 if (PrivateData->Mem64Limit < Limit) {
942 PrivateData->Mem64Limit = Limit;
943 }
944 }
945 break;
946 }
947 }
948 }
949 }
950 }
951 }
952 return EFI_SUCCESS;
953}
954
955UINT64
956GetPciExpressBaseAddressForRootBridge (
957 IN UINTN HostBridgeNumber,
958 IN UINTN RootBridgeNumber
959 )
960/*++
961
962Routine Description:
963 This routine is to get PciExpress Base Address for this RootBridge
964
965Arguments:
966 HostBridgeNumber - The number of HostBridge
967 RootBridgeNumber - The number of RootBridge
968
969Returns:
970 UINT64 - PciExpressBaseAddress for this HostBridge and RootBridge
971
972--*/
973{
974 EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION *PciExpressBaseAddressInfo;
975 UINTN BufferSize;
976 UINT32 Index;
977 UINT32 Number;
klu2c69dd9d2008-04-17 05:48:13 +0000978 EFI_PEI_HOB_POINTERS GuidHob;
979
980 //
klu2c69dd9d2008-04-17 05:48:13 +0000981 // Get PciExpressAddressInfo Hob
982 //
983 PciExpressBaseAddressInfo = NULL;
984 BufferSize = 0;
jljusten8e53d242008-11-23 23:55:02 +0000985 GuidHob.Raw = GetFirstGuidHob (&gEfiPciExpressBaseAddressGuid);
klu2c69dd9d2008-04-17 05:48:13 +0000986 if (GuidHob.Raw != NULL) {
987 PciExpressBaseAddressInfo = GET_GUID_HOB_DATA (GuidHob.Guid);
988 BufferSize = GET_GUID_HOB_DATA_SIZE (GuidHob.Guid);
989 } else {
990 return 0;
991 }
992
993 //
994 // Search the PciExpress Base Address in the Hob for current RootBridge
995 //
996 Number = (UINT32)(BufferSize / sizeof(EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION));
997 for (Index = 0; Index < Number; Index++) {
998 if ((PciExpressBaseAddressInfo[Index].HostBridgeNumber == HostBridgeNumber) &&
999 (PciExpressBaseAddressInfo[Index].RootBridgeNumber == RootBridgeNumber)) {
1000 return PciExpressBaseAddressInfo[Index].PciExpressBaseAddress;
1001 }
1002 }
1003
1004 //
1005 // Do not find the PciExpress Base Address in the Hob
1006 //
1007 return 0;
1008}
1009