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