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