1 /*++
2 
3 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4 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
PcatRootBridgeIoIoRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)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
PcatRootBridgeIoIoWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)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
PcatRootBridgeIoGetIoPortMapping(OUT EFI_PHYSICAL_ADDRESS * IoPortMapping,OUT EFI_PHYSICAL_ADDRESS * MemoryPortMapping)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
PcatRootBridgeIoPciRW(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN BOOLEAN Write,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)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 ((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 
213 VOID
ScanPciBus(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,EFI_PCI_BUS_SCAN_CALLBACK Callback,VOID * Context)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
CheckForRom(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,UINT16 Bus,UINT16 Device,UINT16 Func,IN VOID * VoidContext)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 == 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 
534 VOID
SaveCommandRegister(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,UINT16 Bus,UINT16 Device,UINT16 Func,IN VOID * VoidContext)535 SaveCommandRegister (
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 
571 VOID
RestoreCommandRegister(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev,UINT16 MinBus,UINT16 MaxBus,UINT16 MinDevice,UINT16 MaxDevice,UINT16 MinFunc,UINT16 MaxFunc,UINT16 Bus,UINT16 Device,UINT16 Func,IN VOID * VoidContext)572 RestoreCommandRegister (
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 
600 EFI_STATUS
ScanPciRootBridgeForRoms(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev)601 ScanPciRootBridgeForRoms(
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 }
739