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