]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c
98bc27c26c08b56100f622eee31815d60126b732
[mirror_edk2.git] / DuetPkg / PciRootBridgeNoEnumerationDxe / Ia32 / PcatIo.c
1 /*++
2
3 Copyright (c) 2005 - 2008, 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 BOOLEAN mPciOptionRomTableInstalled = FALSE;
26 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 >= 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 VOID
214 ScanPciBus(
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
301 VOID
302 CheckForRom (
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 == 0xaa55) {
440
441 ZeroMem (&Pcir, sizeof(Pcir));
442 IoDev->Mem.Read (
443 IoDev,
444 EfiPciWidthUint8,
445 RomBar + RomBarSize + EfiRomHeader.PcirOffset,
446 sizeof(Pcir),
447 &Pcir
448 );
449
450 if ((Pcir.Indicator & 0x80) == 0x00) {
451 LastImage = FALSE;
452 }
453
454 RomBarSize += Pcir.ImageLength * 512;
455 }
456 } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0);
457
458 if (RomBarSize > 0) {
459
460 //
461 // Allocate a memory buffer for the Option ROM contents.
462 //
463 Status = gBS->AllocatePages(
464 AllocateAnyPages,
465 EfiBootServicesData,
466 EFI_SIZE_TO_PAGES(RomBarSize),
467 &RomBuffer
468 );
469
470 if (!EFI_ERROR (Status)) {
471
472 //
473 // Copy the contents of the Option ROM to the memory buffer
474 //
475 IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer);
476
477 Status = gBS->AllocatePool(
478 EfiBootServicesData,
479 ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR),
480 (VOID*)&TempPciOptionRomDescriptors
481 );
482 if (mPciOptionRomTable.PciOptionRomCount > 0) {
483 CopyMem(
484 TempPciOptionRomDescriptors,
485 mPciOptionRomTable.PciOptionRomDescriptors,
486 (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR)
487 );
488
489 gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors);
490 }
491
492 mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors;
493
494 TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]);
495
496 TempPciOptionRomDescriptors->RomAddress = RomBuffer;
497 TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData;
498 TempPciOptionRomDescriptors->RomLength = RomBarSize;
499 TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber;
500 TempPciOptionRomDescriptors->Bus = (UINT8)Bus;
501 TempPciOptionRomDescriptors->Dev = (UINT8)Device;
502 TempPciOptionRomDescriptors->Func = (UINT8)Func;
503 TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE;
504 TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE;
505
506 mPciOptionRomTable.PciOptionRomCount++;
507 }
508 }
509
510 //
511 // Disable the Memory decode for the PCI-PCI Bridge
512 //
513 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
514 Register &= (~0x02);
515 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
516 }
517 }
518 }
519
520 //
521 // Restore the PCI Configuration Header
522 //
523 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
524 }
525
526 VOID
527 SaveCommandRegister (
528 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
529 UINT16 MinBus,
530 UINT16 MaxBus,
531 UINT16 MinDevice,
532 UINT16 MaxDevice,
533 UINT16 MinFunc,
534 UINT16 MaxFunc,
535 UINT16 Bus,
536 UINT16 Device,
537 UINT16 Func,
538 IN VOID *VoidContext
539 )
540
541 {
542 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
543 UINT64 Address;
544 UINTN Index;
545 UINT16 Command;
546
547 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
548
549 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
550
551 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
552
553 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
554
555 //
556 // Clear the memory enable bit
557 //
558 Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02));
559
560 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command);
561 }
562
563 VOID
564 RestoreCommandRegister (
565 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,
566 UINT16 MinBus,
567 UINT16 MaxBus,
568 UINT16 MinDevice,
569 UINT16 MaxDevice,
570 UINT16 MinFunc,
571 UINT16 MaxFunc,
572 UINT16 Bus,
573 UINT16 Device,
574 UINT16 Func,
575 IN VOID *VoidContext
576 )
577
578 {
579 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;
580 UINT64 Address;
581 UINTN Index;
582
583 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;
584
585 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);
586
587 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;
588
589 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);
590 }
591
592 EFI_STATUS
593 ScanPciRootBridgeForRoms(
594 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev
595 )
596
597 {
598 EFI_STATUS Status;
599 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
600 UINT16 MinBus;
601 UINT16 MaxBus;
602 UINT64 RootWindowBase;
603 UINT64 RootWindowLimit;
604 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context;
605
606 if (mPciOptionRomTableInstalled == FALSE) {
607 gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable);
608 mPciOptionRomTableInstalled = TRUE;
609 }
610
611 Status = IoDev->Configuration(IoDev, (VOID **)&Descriptors);
612 if (EFI_ERROR (Status) || Descriptors == NULL) {
613 return EFI_NOT_FOUND;
614 }
615
616 MinBus = 0xffff;
617 MaxBus = 0xffff;
618 RootWindowBase = 0;
619 RootWindowLimit = 0;
620 while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {
621 //
622 // Find bus range
623 //
624 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
625 MinBus = (UINT16)Descriptors->AddrRangeMin;
626 MaxBus = (UINT16)Descriptors->AddrRangeMax;
627 }
628 //
629 // Find memory descriptors that are not prefetchable
630 //
631 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) {
632 //
633 // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices
634 //
635 if (Descriptors->AddrRangeMax < 0x100000000ULL) {
636 //
637 // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB
638 //
639 if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) {
640 RootWindowBase = Descriptors->AddrRangeMin;
641 RootWindowLimit = Descriptors->AddrRangeMax;
642 }
643 }
644 }
645 Descriptors ++;
646 }
647
648 //
649 // Make sure a bus range was found
650 //
651 if (MinBus == 0xffff || MaxBus == 0xffff) {
652 return EFI_NOT_FOUND;
653 }
654
655 //
656 // Make sure a non-prefetchable memory region was found
657 //
658 if (RootWindowBase == 0 && RootWindowLimit == 0) {
659 return EFI_NOT_FOUND;
660 }
661
662 //
663 // Round the Base and Limit values to 1 MB boudaries
664 //
665 RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000;
666 RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1;
667
668 //
669 // Make sure that the size of the rounded window is greater than zero
670 //
671 if (RootWindowLimit <= RootWindowBase) {
672 return EFI_NOT_FOUND;
673 }
674
675 //
676 // Allocate buffer to save the Command register from all the PCI devices
677 //
678 Context.CommandRegisterBuffer = NULL;
679 Status = gBS->AllocatePool(
680 EfiBootServicesData,
681 sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1),
682 (VOID **)&Context.CommandRegisterBuffer
683 );
684
685 if (EFI_ERROR (Status)) {
686 return Status;
687 }
688
689 Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000);
690
691 //
692 // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits
693 //
694 ScanPciBus(
695 IoDev,
696 MinBus, MaxBus,
697 0, PCI_MAX_DEVICE,
698 0, PCI_MAX_FUNC,
699 SaveCommandRegister, &Context
700 );
701
702 //
703 // Recursively scan all the busses for PCI Option ROMs
704 //
705 ScanPciBus(
706 IoDev,
707 MinBus, MinBus,
708 0, PCI_MAX_DEVICE,
709 0, PCI_MAX_FUNC,
710 CheckForRom, &Context
711 );
712
713 //
714 // Restore the Command register in all the PCI devices
715 //
716 ScanPciBus(
717 IoDev,
718 MinBus, MaxBus,
719 0, PCI_MAX_DEVICE,
720 0, PCI_MAX_FUNC,
721 RestoreCommandRegister, &Context
722 );
723
724 //
725 // Free the buffer used to save all the Command register values
726 //
727 gBS->FreePool(Context.CommandRegisterBuffer);
728
729 return EFI_SUCCESS;
730 }