]> git.proxmox.com Git - mirror_edk2.git/blame - CorebootModulePkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c
IntelFsp2Pkg/Tools: Add BSF bit field support in GenCfgOpt tool
[mirror_edk2.git] / CorebootModulePkg / PciRootBridgeNoEnumerationDxe / X64 / PcatIo.c
CommitLineData
81a23a0f
LL
1/*++
2
3Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
5are 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 PcatPciRootBridgeIo.c
14
15Abstract:
16
17 EFI PC AT PCI Root Bridge Io Protocol
18
19Revision History
20
21--*/
22
23#include "PcatPciRootBridge.h"
24
25BOOLEAN mPciOptionRomTableInstalled = FALSE;
26EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL};
27
28EFI_STATUS
29EFIAPI
30PcatRootBridgeIoIoRead (
31 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
32 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
33 IN UINT64 UserAddress,
34 IN UINTN Count,
35 IN OUT VOID *UserBuffer
36 )
37{
38 return gCpuIo->Io.Read (
39 gCpuIo,
40 (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
41 UserAddress,
42 Count,
43 UserBuffer
44 );
45}
46
47EFI_STATUS
48EFIAPI
49PcatRootBridgeIoIoWrite (
50 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
51 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
52 IN UINT64 UserAddress,
53 IN UINTN Count,
54 IN OUT VOID *UserBuffer
55 )
56{
57 return gCpuIo->Io.Write (
58 gCpuIo,
59 (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
60 UserAddress,
61 Count,
62 UserBuffer
63 );
64
65}
66
67EFI_STATUS
68PcatRootBridgeIoGetIoPortMapping (
69 OUT EFI_PHYSICAL_ADDRESS *IoPortMapping,
70 OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping
71 )
72/*++
73
74 Get the IO Port Mapping. For IA-32 it is always 0.
75
76--*/
77{
78 *IoPortMapping = 0;
79 *MemoryPortMapping = 0;
80
81 return EFI_SUCCESS;
82}
83
84EFI_STATUS
85PcatRootBridgeIoPciRW (
86 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
87 IN BOOLEAN Write,
88 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
89 IN UINT64 UserAddress,
90 IN UINTN Count,
91 IN OUT VOID *UserBuffer
92 )
93{
94 PCI_CONFIG_ACCESS_CF8 Pci;
95 PCI_CONFIG_ACCESS_CF8 PciAligned;
96 UINT32 InStride;
97 UINT32 OutStride;
98 UINTN PciData;
99 UINTN PciDataStride;
100 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
101 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress;
102 UINT64 PciExpressRegAddr;
103 BOOLEAN UsePciExpressAccess;
104
105 if ((UINT32)Width >= EfiPciWidthMaximum) {
106 return EFI_INVALID_PARAMETER;
107 }
108
109 if ((Width & 0x03) >= EfiPciWidthUint64) {
110 return EFI_INVALID_PARAMETER;
111 }
112
113 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
114
115 InStride = 1 << (Width & 0x03);
116 OutStride = InStride;
117 if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
118 InStride = 0;
119 }
120
121 if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {
122 OutStride = 0;
123 }
124
125 UsePciExpressAccess = FALSE;
126
127 CopyMem (&PciAddress, &UserAddress, sizeof(UINT64));
128
129 if (PciAddress.ExtendedRegister > 0xFF) {
130 //
131 // Check PciExpressBaseAddress
132 //
133 if ((PrivateData->PciExpressBaseAddress == 0) ||
134 (PrivateData->PciExpressBaseAddress >= MAX_ADDRESS)) {
135 return EFI_UNSUPPORTED;
136 } else {
137 UsePciExpressAccess = TRUE;
138 }
139 } else {
140 if (PciAddress.ExtendedRegister != 0) {
141 Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF;
142 } else {
143 Pci.Bits.Reg = PciAddress.Register;
144 }
145 //
146 // Note: We can also use PciExpress access here, if wanted.
147 //
148 }
149
150 if (!UsePciExpressAccess) {
151 Pci.Bits.Func = PciAddress.Function;
152 Pci.Bits.Dev = PciAddress.Device;
153 Pci.Bits.Bus = PciAddress.Bus;
154 Pci.Bits.Reserved = 0;
155 Pci.Bits.Enable = 1;
156
157 //
158 // PCI Config access are all 32-bit alligned, but by accessing the
159 // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types
160 // are possible on PCI.
161 //
162 // To read a byte of PCI config space you load 0xcf8 and
163 // read 0xcfc, 0xcfd, 0xcfe, 0xcff
164 //
165 PciDataStride = Pci.Bits.Reg & 0x03;
166
167 while (Count) {
168 PciAligned = Pci;
169 PciAligned.Bits.Reg &= 0xfc;
170 PciData = (UINTN)PrivateData->PciData + PciDataStride;
171 EfiAcquireLock(&PrivateData->PciLock);
172 This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned);
173 if (Write) {
174 This->Io.Write (This, Width, PciData, 1, UserBuffer);
175 } else {
176 This->Io.Read (This, Width, PciData, 1, UserBuffer);
177 }
178 EfiReleaseLock(&PrivateData->PciLock);
179 UserBuffer = ((UINT8 *)UserBuffer) + OutStride;
180 PciDataStride = (PciDataStride + InStride) % 4;
181 Pci.Bits.Reg += InStride;
182 Count -= 1;
183 }
184 } else {
185 //
186 // Access PCI-Express space by using memory mapped method.
187 //
188 PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) |
189 (PciAddress.Bus << 20) |
190 (PciAddress.Device << 15) |
191 (PciAddress.Function << 12);
192 if (PciAddress.ExtendedRegister != 0) {
193 PciExpressRegAddr += PciAddress.ExtendedRegister;
194 } else {
195 PciExpressRegAddr += PciAddress.Register;
196 }
197 while (Count) {
198 if (Write) {
199 This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer);
200 } else {
201 This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer);
202 }
203
204 UserBuffer = ((UINT8 *) UserBuffer) + OutStride;
205 PciExpressRegAddr += InStride;
206 Count -= 1;
207 }
208 }
209
210 return EFI_SUCCESS;
211}
212
213VOID
214ScanPciBus(
215 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
216 UINT16 MinBus,
217 UINT16 MaxBus,
218 UINT16 MinDevice,
219 UINT16 MaxDevice,
220 UINT16 MinFunc,
221 UINT16 MaxFunc,
222 EFI_PCI_BUS_SCAN_CALLBACK Callback,
223 VOID *Context
224 )
225
226{
227 UINT16 Bus;
228 UINT16 Device;
229 UINT16 Func;
230 UINT64 Address;
231 PCI_TYPE00 PciHeader;
232
233 //
234 // Loop through all busses
235 //
236 for (Bus = MinBus; Bus <= MaxBus; Bus++) {
237 //
238 // Loop 32 devices per bus
239 //
240 for (Device = MinDevice; Device <= MaxDevice; Device++) {
241 //
242 // Loop through 8 functions per device
243 //
244 for (Func = MinFunc; Func <= MaxFunc; Func++) {
245
246 //
247 // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device
248 //
249 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
250
251 //
252 // Read the VendorID from this PCI Device's Confioguration Header
253 //
254 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId);
255
256 //
257 // If VendorId = 0xffff, there does not exist a device at this
258 // location. For each device, if there is any function on it,
259 // there must be 1 function at Function 0. So if Func = 0, there
260 // will be no more functions in the same device, so we can break
261 // loop to deal with the next device.
262 //
263 if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) {
264 break;
265 }
266
267 if (PciHeader.Hdr.VendorId != 0xffff) {
268
269 //
270 // Read the HeaderType to determine if this is a multi-function device
271 //
272 IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType);
273
274 //
275 // Call the callback function for the device that was found
276 //
277 Callback(
278 IoDev,
279 MinBus, MaxBus,
280 MinDevice, MaxDevice,
281 MinFunc, MaxFunc,
282 Bus,
283 Device,
284 Func,
285 Context
286 );
287
288 //
289 // If this is not a multi-function device, we can leave the loop
290 // to deal with the next device.
291 //
292 if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) {
293 break;
294 }
295 }
296 }
297 }
298 }
299}
300
301VOID
302CheckForRom (
303 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
304 UINT16 MinBus,
305 UINT16 MaxBus,
306 UINT16 MinDevice,
307 UINT16 MaxDevice,
308 UINT16 MinFunc,
309 UINT16 MaxFunc,
310 UINT16 Bus,
311 UINT16 Device,
312 UINT16 Func,
313 IN VOID *VoidContext
314 )
315{
316 EFI_STATUS Status;
317 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
318 UINT64 Address;
319 PCI_TYPE00 PciHeader;
320 PCI_TYPE01 *PciBridgeHeader;
321 UINT32 Register;
322 UINT32 RomBar;
323 UINT32 RomBarSize;
324 EFI_PHYSICAL_ADDRESS RomBuffer;
325 UINT32 MaxRomSize;
326 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader;
327 PCI_DATA_STRUCTURE Pcir;
328 EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors;
329 BOOLEAN LastImage;
330
331 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
332
333 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
334
335 //
336 // Save the contents of the PCI Configuration Header
337 //
338 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
339
340 if (IS_PCI_BRIDGE(&PciHeader)) {
341
342 PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader);
343
344 //
345 // See if the PCI-PCI Bridge has its secondary interface enabled.
346 //
347 if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) {
348
349 //
350 // Disable the Prefetchable Memory Window
351 //
352 Register = 0x00000000;
353 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register);
354 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register);
355 Register = 0xffffffff;
356 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register);
357 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register);
358
359 //
360 // Program Memory Window to the PCI Root Bridge Memory Window
361 //
362 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow);
363
364 //
365 // Enable the Memory decode for the PCI-PCI Bridge
366 //
367 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
368 Register |= 0x02;
369 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
370
371 //
372 // Recurse on the Secondary Bus Number
373 //
374 ScanPciBus(
375 IoDev,
376 PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus,
377 0, PCI_MAX_DEVICE,
378 0, PCI_MAX_FUNC,
379 CheckForRom, Context
380 );
381 }
382 } else {
383
384 //
385 // Check if an Option ROM Register is present and save the Option ROM Window Register
386 //
387 RomBar = 0xffffffff;
388 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
389 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
390
391 RomBarSize = (~(RomBar & 0xfffff800)) + 1;
392
393 //
394 // Make sure the size of the ROM is between 0 and 16 MB
395 //
396 if (RomBarSize > 0 && RomBarSize <= 0x01000000) {
397
398 //
399 // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window
400 //
401 RomBar = (Context->PpbMemoryWindow & 0xffff) << 16;
402 RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize;
403 if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) {
404 MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar;
405 RomBar = RomBar + 1;
406 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
407 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
408 RomBar = RomBar - 1;
409
410 //
411 // Enable the Memory decode for the PCI Device
412 //
413 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
414 Register |= 0x02;
415 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
416
417 //
418 // Follow the chain of images to determine the size of the Option ROM present
419 // Keep going until the last image is found by looking at the Indicator field
420 // or the size of an image is 0, or the size of all the images is bigger than the
421 // size of the window programmed into the PPB.
422 //
423 RomBarSize = 0;
424 do {
425
426 LastImage = TRUE;
427
428 ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader));
429 IoDev->Mem.Read (
430 IoDev,
431 EfiPciWidthUint8,
432 RomBar + RomBarSize,
433 sizeof(EfiRomHeader),
434 &EfiRomHeader
435 );
436
437 Pcir.ImageLength = 0;
438
439 if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE &&
440 EfiRomHeader.PcirOffset != 0 &&
441 (EfiRomHeader.PcirOffset & 3) == 0 &&
442 RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) {
443 ZeroMem (&Pcir, sizeof(Pcir));
444 IoDev->Mem.Read (
445 IoDev,
446 EfiPciWidthUint8,
447 RomBar + RomBarSize + EfiRomHeader.PcirOffset,
448 sizeof(Pcir),
449 &Pcir
450 );
451
452 if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
453 break;
454 }
455 if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) {
456 break;
457 }
458 if ((Pcir.Indicator & 0x80) == 0x00) {
459 LastImage = FALSE;
460 }
461
462 RomBarSize += Pcir.ImageLength * 512;
463 }
464 } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0);
465
466 if (RomBarSize > 0) {
467
468 //
469 // Allocate a memory buffer for the Option ROM contents.
470 //
471 Status = gBS->AllocatePages(
472 AllocateAnyPages,
473 EfiBootServicesData,
474 EFI_SIZE_TO_PAGES(RomBarSize),
475 &RomBuffer
476 );
477
478 if (!EFI_ERROR (Status)) {
479
480 //
481 // Copy the contents of the Option ROM to the memory buffer
482 //
483 IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer);
484
485 Status = gBS->AllocatePool(
486 EfiBootServicesData,
487 ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR),
488 (VOID **) &TempPciOptionRomDescriptors
489 );
490 if (mPciOptionRomTable.PciOptionRomCount > 0) {
491 CopyMem(
492 TempPciOptionRomDescriptors,
493 mPciOptionRomTable.PciOptionRomDescriptors,
494 (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR)
495 );
496
497 gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors);
498 }
499
500 mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors;
501
502 TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]);
503
504 TempPciOptionRomDescriptors->RomAddress = RomBuffer;
505 TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData;
506 TempPciOptionRomDescriptors->RomLength = RomBarSize;
507 TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber;
508 TempPciOptionRomDescriptors->Bus = (UINT8)Bus;
509 TempPciOptionRomDescriptors->Dev = (UINT8)Device;
510 TempPciOptionRomDescriptors->Func = (UINT8)Func;
511 TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE;
512 TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE;
513
514 mPciOptionRomTable.PciOptionRomCount++;
515 }
516 }
517
518 //
519 // Disable the Memory decode for the PCI-PCI Bridge
520 //
521 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
522 Register &= (~0x02);
523 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
524 }
525 }
526 }
527
528 //
529 // Restore the PCI Configuration Header
530 //
531 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
532}
533
534VOID
535SaveCommandRegister (
536 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
537 UINT16 MinBus,
538 UINT16 MaxBus,
539 UINT16 MinDevice,
540 UINT16 MaxDevice,
541 UINT16 MinFunc,
542 UINT16 MaxFunc,
543 UINT16 Bus,
544 UINT16 Device,
545 UINT16 Func,
546 IN VOID *VoidContext
547 )
548
549{
550 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
551 UINT64 Address;
552 UINTN Index;
553 UINT16 Command;
554
555 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
556
557 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
558
559 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
560
561 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
562
563 //
564 // Clear the memory enable bit
565 //
566 Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02));
567
568 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command);
569}
570
571VOID
572RestoreCommandRegister (
573 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
574 UINT16 MinBus,
575 UINT16 MaxBus,
576 UINT16 MinDevice,
577 UINT16 MaxDevice,
578 UINT16 MinFunc,
579 UINT16 MaxFunc,
580 UINT16 Bus,
581 UINT16 Device,
582 UINT16 Func,
583 IN VOID *VoidContext
584 )
585
586{
587 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
588 UINT64 Address;
589 UINTN Index;
590
591 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
592
593 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
594
595 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
596
597 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
598}
599
600EFI_STATUS
601ScanPciRootBridgeForRoms(
602 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev
603 )
604
605{
606 EFI_STATUS Status;
607 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
608 UINT16 MinBus;
609 UINT16 MaxBus;
610 UINT64 RootWindowBase;
611 UINT64 RootWindowLimit;
612 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context;
613
614 if (mPciOptionRomTableInstalled == FALSE) {
615 gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable);
616 mPciOptionRomTableInstalled = TRUE;
617 }
618
619 Status = IoDev->Configuration(IoDev, (VOID **) &Descriptors);
620 if (EFI_ERROR (Status) || Descriptors == NULL) {
621 return EFI_NOT_FOUND;
622 }
623
624 MinBus = 0xffff;
625 MaxBus = 0xffff;
626 RootWindowBase = 0;
627 RootWindowLimit = 0;
628 while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {
629 //
630 // Find bus range
631 //
632 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
633 MinBus = (UINT16)Descriptors->AddrRangeMin;
634 MaxBus = (UINT16)Descriptors->AddrRangeMax;
635 }
636 //
637 // Find memory descriptors that are not prefetchable
638 //
639 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) {
640 //
641 // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices
642 //
643 if (Descriptors->AddrRangeMax < 0x100000000ULL) {
644 //
645 // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB
646 //
647 if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) {
648 RootWindowBase = Descriptors->AddrRangeMin;
649 RootWindowLimit = Descriptors->AddrRangeMax;
650 }
651 }
652 }
653 Descriptors ++;
654 }
655
656 //
657 // Make sure a bus range was found
658 //
659 if (MinBus == 0xffff || MaxBus == 0xffff) {
660 return EFI_NOT_FOUND;
661 }
662
663 //
664 // Make sure a non-prefetchable memory region was found
665 //
666 if (RootWindowBase == 0 && RootWindowLimit == 0) {
667 return EFI_NOT_FOUND;
668 }
669
670 //
671 // Round the Base and Limit values to 1 MB boudaries
672 //
673 RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000;
674 RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1;
675
676 //
677 // Make sure that the size of the rounded window is greater than zero
678 //
679 if (RootWindowLimit <= RootWindowBase) {
680 return EFI_NOT_FOUND;
681 }
682
683 //
684 // Allocate buffer to save the Command register from all the PCI devices
685 //
686 Context.CommandRegisterBuffer = NULL;
687 Status = gBS->AllocatePool(
688 EfiBootServicesData,
689 sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1),
690 (VOID **) &Context.CommandRegisterBuffer
691 );
692
693 if (EFI_ERROR (Status)) {
694 return Status;
695 }
696
697 Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000);
698
699 //
700 // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits
701 //
702 ScanPciBus(
703 IoDev,
704 MinBus, MaxBus,
705 0, PCI_MAX_DEVICE,
706 0, PCI_MAX_FUNC,
707 SaveCommandRegister, &Context
708 );
709
710 //
711 // Recursively scan all the busses for PCI Option ROMs
712 //
713 ScanPciBus(
714 IoDev,
715 MinBus, MinBus,
716 0, PCI_MAX_DEVICE,
717 0, PCI_MAX_FUNC,
718 CheckForRom, &Context
719 );
720
721 //
722 // Restore the Command register in all the PCI devices
723 //
724 ScanPciBus(
725 IoDev,
726 MinBus, MaxBus,
727 0, PCI_MAX_DEVICE,
728 0, PCI_MAX_FUNC,
729 RestoreCommandRegister, &Context
730 );
731
732 //
733 // Free the buffer used to save all the Command register values
734 //
735 gBS->FreePool(Context.CommandRegisterBuffer);
736
737 return EFI_SUCCESS;
738}