]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c
d697390fa9531b3fd39874a19abbf264057c40fa
[mirror_edk2.git] / DuetPkg / PciRootBridgeNoEnumerationDxe / Ia32 / PcatIo.c
1 /*++
2
3 Copyright (c) 2005 - 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13 PcatPciRootBridgeIo.c
14
15 Abstract:
16
17 EFI PC AT PCI Root Bridge Io Protocol
18
19 Revision History
20
21 --*/
22
23 #include "PcatPciRootBridge.h"
24
25 static BOOLEAN mPciOptionRomTableInstalled = FALSE;
26 static EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL};
27
28 EFI_STATUS
29 EFIAPI
30 PcatRootBridgeIoIoRead (
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
47 EFI_STATUS
48 EFIAPI
49 PcatRootBridgeIoIoWrite (
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
67 EFI_STATUS
68 PcatRootBridgeIoGetIoPortMapping (
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
84 EFI_STATUS
85 PcatRootBridgeIoPciRW (
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 (Width < 0 || 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 >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
118 InStride = 0;
119 }
120
121 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {
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 >= EFI_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
213 static
214 VOID
215 ScanPciBus(
216 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
217 UINT16 MinBus,
218 UINT16 MaxBus,
219 UINT16 MinDevice,
220 UINT16 MaxDevice,
221 UINT16 MinFunc,
222 UINT16 MaxFunc,
223 EFI_PCI_BUS_SCAN_CALLBACK Callback,
224 VOID *Context
225 )
226
227 {
228 UINT16 Bus;
229 UINT16 Device;
230 UINT16 Func;
231 UINT64 Address;
232 PCI_TYPE00 PciHeader;
233
234 //
235 // Loop through all busses
236 //
237 for (Bus = MinBus; Bus <= MaxBus; Bus++) {
238 //
239 // Loop 32 devices per bus
240 //
241 for (Device = MinDevice; Device <= MaxDevice; Device++) {
242 //
243 // Loop through 8 functions per device
244 //
245 for (Func = MinFunc; Func <= MaxFunc; Func++) {
246
247 //
248 // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device
249 //
250 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
251
252 //
253 // Read the VendorID from this PCI Device's Confioguration Header
254 //
255 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId);
256
257 //
258 // If VendorId = 0xffff, there does not exist a device at this
259 // location. For each device, if there is any function on it,
260 // there must be 1 function at Function 0. So if Func = 0, there
261 // will be no more functions in the same device, so we can break
262 // loop to deal with the next device.
263 //
264 if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) {
265 break;
266 }
267
268 if (PciHeader.Hdr.VendorId != 0xffff) {
269
270 //
271 // Read the HeaderType to determine if this is a multi-function device
272 //
273 IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType);
274
275 //
276 // Call the callback function for the device that was found
277 //
278 Callback(
279 IoDev,
280 MinBus, MaxBus,
281 MinDevice, MaxDevice,
282 MinFunc, MaxFunc,
283 Bus,
284 Device,
285 Func,
286 Context
287 );
288
289 //
290 // If this is not a multi-function device, we can leave the loop
291 // to deal with the next device.
292 //
293 if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) {
294 break;
295 }
296 }
297 }
298 }
299 }
300 }
301
302 static
303 VOID
304 CheckForRom (
305 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
306 UINT16 MinBus,
307 UINT16 MaxBus,
308 UINT16 MinDevice,
309 UINT16 MaxDevice,
310 UINT16 MinFunc,
311 UINT16 MaxFunc,
312 UINT16 Bus,
313 UINT16 Device,
314 UINT16 Func,
315 IN VOID *VoidContext
316 )
317 {
318 EFI_STATUS Status;
319 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
320 UINT64 Address;
321 PCI_TYPE00 PciHeader;
322 PCI_TYPE01 *PciBridgeHeader;
323 UINT32 Register;
324 UINT32 RomBar;
325 UINT32 RomBarSize;
326 EFI_PHYSICAL_ADDRESS RomBuffer;
327 UINT32 MaxRomSize;
328 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader;
329 PCI_DATA_STRUCTURE Pcir;
330 EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors;
331 BOOLEAN LastImage;
332
333 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
334
335 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
336
337 //
338 // Save the contents of the PCI Configuration Header
339 //
340 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
341
342 if (IS_PCI_BRIDGE(&PciHeader)) {
343
344 PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader);
345
346 //
347 // See if the PCI-PCI Bridge has its secondary interface enabled.
348 //
349 if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) {
350
351 //
352 // Disable the Prefetchable Memory Window
353 //
354 Register = 0x00000000;
355 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register);
356 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register);
357 Register = 0xffffffff;
358 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register);
359 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register);
360
361 //
362 // Program Memory Window to the PCI Root Bridge Memory Window
363 //
364 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow);
365
366 //
367 // Enable the Memory decode for the PCI-PCI Bridge
368 //
369 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
370 Register |= 0x02;
371 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
372
373 //
374 // Recurse on the Secondary Bus Number
375 //
376 ScanPciBus(
377 IoDev,
378 PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus,
379 0, PCI_MAX_DEVICE,
380 0, PCI_MAX_FUNC,
381 CheckForRom, Context
382 );
383 }
384 } else {
385
386 //
387 // Check if an Option ROM Register is present and save the Option ROM Window Register
388 //
389 RomBar = 0xffffffff;
390 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
391 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
392
393 RomBarSize = (~(RomBar & 0xfffff800)) + 1;
394
395 //
396 // Make sure the size of the ROM is between 0 and 16 MB
397 //
398 if (RomBarSize > 0 && RomBarSize <= 0x01000000) {
399
400 //
401 // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window
402 //
403 RomBar = (Context->PpbMemoryWindow & 0xffff) << 16;
404 RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize;
405 if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) {
406 MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar;
407 RomBar = RomBar + 1;
408 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
409 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
410 RomBar = RomBar - 1;
411
412 //
413 // Enable the Memory decode for the PCI Device
414 //
415 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
416 Register |= 0x02;
417 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
418
419 //
420 // Follow the chain of images to determine the size of the Option ROM present
421 // Keep going until the last image is found by looking at the Indicator field
422 // or the size of an image is 0, or the size of all the images is bigger than the
423 // size of the window programmed into the PPB.
424 //
425 RomBarSize = 0;
426 do {
427
428 LastImage = TRUE;
429
430 ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader));
431 IoDev->Mem.Read (
432 IoDev,
433 EfiPciWidthUint8,
434 RomBar + RomBarSize,
435 sizeof(EfiRomHeader),
436 &EfiRomHeader
437 );
438
439 Pcir.ImageLength = 0;
440
441 if (EfiRomHeader.Signature == 0xaa55) {
442
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.Indicator & 0x80) == 0x00) {
453 LastImage = FALSE;
454 }
455
456 RomBarSize += Pcir.ImageLength * 512;
457 }
458 } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0);
459
460 if (RomBarSize > 0) {
461
462 //
463 // Allocate a memory buffer for the Option ROM contents.
464 //
465 Status = gBS->AllocatePages(
466 AllocateAnyPages,
467 EfiBootServicesData,
468 EFI_SIZE_TO_PAGES(RomBarSize),
469 &RomBuffer
470 );
471
472 if (!EFI_ERROR (Status)) {
473
474 //
475 // Copy the contents of the Option ROM to the memory buffer
476 //
477 IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer);
478
479 Status = gBS->AllocatePool(
480 EfiBootServicesData,
481 ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR),
482 (VOID*)&TempPciOptionRomDescriptors
483 );
484 if (mPciOptionRomTable.PciOptionRomCount > 0) {
485 CopyMem(
486 TempPciOptionRomDescriptors,
487 mPciOptionRomTable.PciOptionRomDescriptors,
488 (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR)
489 );
490
491 gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors);
492 }
493
494 mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors;
495
496 TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]);
497
498 TempPciOptionRomDescriptors->RomAddress = RomBuffer;
499 TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData;
500 TempPciOptionRomDescriptors->RomLength = RomBarSize;
501 TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber;
502 TempPciOptionRomDescriptors->Bus = (UINT8)Bus;
503 TempPciOptionRomDescriptors->Dev = (UINT8)Device;
504 TempPciOptionRomDescriptors->Func = (UINT8)Func;
505 TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE;
506 TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE;
507
508 mPciOptionRomTable.PciOptionRomCount++;
509 }
510 }
511
512 //
513 // Disable the Memory decode for the PCI-PCI Bridge
514 //
515 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
516 Register &= (~0x02);
517 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
518 }
519 }
520 }
521
522 //
523 // Restore the PCI Configuration Header
524 //
525 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
526 }
527
528 static
529 VOID
530 SaveCommandRegister (
531 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
532 UINT16 MinBus,
533 UINT16 MaxBus,
534 UINT16 MinDevice,
535 UINT16 MaxDevice,
536 UINT16 MinFunc,
537 UINT16 MaxFunc,
538 UINT16 Bus,
539 UINT16 Device,
540 UINT16 Func,
541 IN VOID *VoidContext
542 )
543
544 {
545 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
546 UINT64 Address;
547 UINTN Index;
548 UINT16 Command;
549
550 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
551
552 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
553
554 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
555
556 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
557
558 //
559 // Clear the memory enable bit
560 //
561 Command = Context->CommandRegisterBuffer[Index] & (~0x02);
562
563 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command);
564 }
565
566 static
567 VOID
568 RestoreCommandRegister (
569 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
570 UINT16 MinBus,
571 UINT16 MaxBus,
572 UINT16 MinDevice,
573 UINT16 MaxDevice,
574 UINT16 MinFunc,
575 UINT16 MaxFunc,
576 UINT16 Bus,
577 UINT16 Device,
578 UINT16 Func,
579 IN VOID *VoidContext
580 )
581
582 {
583 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
584 UINT64 Address;
585 UINTN Index;
586
587 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
588
589 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
590
591 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
592
593 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
594 }
595
596 EFI_STATUS
597 ScanPciRootBridgeForRoms(
598 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev
599 )
600
601 {
602 EFI_STATUS Status;
603 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
604 UINT16 MinBus;
605 UINT16 MaxBus;
606 UINT64 RootWindowBase;
607 UINT64 RootWindowLimit;
608 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context;
609
610 if (mPciOptionRomTableInstalled == FALSE) {
611 gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable);
612 mPciOptionRomTableInstalled = TRUE;
613 }
614
615 Status = IoDev->Configuration(IoDev, &Descriptors);
616 if (EFI_ERROR (Status) || Descriptors == NULL) {
617 return EFI_NOT_FOUND;
618 }
619
620 MinBus = 0xffff;
621 MaxBus = 0xffff;
622 RootWindowBase = 0;
623 RootWindowLimit = 0;
624 while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {
625 //
626 // Find bus range
627 //
628 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
629 MinBus = (UINT16)Descriptors->AddrRangeMin;
630 MaxBus = (UINT16)Descriptors->AddrRangeMax;
631 }
632 //
633 // Find memory descriptors that are not prefetchable
634 //
635 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) {
636 //
637 // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices
638 //
639 if (Descriptors->AddrRangeMax < 0x100000000) {
640 //
641 // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB
642 //
643 if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) {
644 RootWindowBase = Descriptors->AddrRangeMin;
645 RootWindowLimit = Descriptors->AddrRangeMax;
646 }
647 }
648 }
649 Descriptors ++;
650 }
651
652 //
653 // Make sure a bus range was found
654 //
655 if (MinBus == 0xffff || MaxBus == 0xffff) {
656 return EFI_NOT_FOUND;
657 }
658
659 //
660 // Make sure a non-prefetchable memory region was found
661 //
662 if (RootWindowBase == 0 && RootWindowLimit == 0) {
663 return EFI_NOT_FOUND;
664 }
665
666 //
667 // Round the Base and Limit values to 1 MB boudaries
668 //
669 RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000;
670 RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1;
671
672 //
673 // Make sure that the size of the rounded window is greater than zero
674 //
675 if (RootWindowLimit <= RootWindowBase) {
676 return EFI_NOT_FOUND;
677 }
678
679 //
680 // Allocate buffer to save the Command register from all the PCI devices
681 //
682 Context.CommandRegisterBuffer = NULL;
683 Status = gBS->AllocatePool(
684 EfiBootServicesData,
685 sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1),
686 &Context.CommandRegisterBuffer
687 );
688
689 if (EFI_ERROR (Status)) {
690 return Status;
691 }
692
693 Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000);
694
695 //
696 // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits
697 //
698 ScanPciBus(
699 IoDev,
700 MinBus, MaxBus,
701 0, PCI_MAX_DEVICE,
702 0, PCI_MAX_FUNC,
703 SaveCommandRegister, &Context
704 );
705
706 //
707 // Recursively scan all the busses for PCI Option ROMs
708 //
709 ScanPciBus(
710 IoDev,
711 MinBus, MinBus,
712 0, PCI_MAX_DEVICE,
713 0, PCI_MAX_FUNC,
714 CheckForRom, &Context
715 );
716
717 //
718 // Restore the Command register in all the PCI devices
719 //
720 ScanPciBus(
721 IoDev,
722 MinBus, MaxBus,
723 0, PCI_MAX_DEVICE,
724 0, PCI_MAX_FUNC,
725 RestoreCommandRegister, &Context
726 );
727
728 //
729 // Free the buffer used to save all the Command register values
730 //
731 gBS->FreePool(Context.CommandRegisterBuffer);
732
733 return EFI_SUCCESS;
734 }