]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c
Pass X64 GCC building
[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
e56dd2ce 25BOOLEAN mPciOptionRomTableInstalled = FALSE;\r
26EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL};\r
c69dd9df 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
394bbc59 125 CopyMem (&PciAddress, &UserAddress, sizeof(UINT64));\r
c69dd9df 126\r
127 if (PciAddress.ExtendedRegister > 0xFF) {\r
128 //\r
129 // Check PciExpressBaseAddress\r
130 //\r
131 if ((PrivateData->PciExpressBaseAddress == 0) ||\r
eea53ce1 132 (PrivateData->PciExpressBaseAddress >= MAX_ADDRESS)) {\r
c69dd9df 133 return EFI_UNSUPPORTED;\r
134 } else {\r
135 UsePciExpressAccess = TRUE;\r
136 }\r
137 } else {\r
138 if (PciAddress.ExtendedRegister != 0) {\r
394bbc59 139 Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF;\r
c69dd9df 140 } else {\r
394bbc59 141 Pci.Bits.Reg = PciAddress.Register;\r
c69dd9df 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
394bbc59 149 Pci.Bits.Func = PciAddress.Function;\r
150 Pci.Bits.Dev = PciAddress.Device;\r
151 Pci.Bits.Bus = PciAddress.Bus;\r
152 Pci.Bits.Reserved = 0;\r
153 Pci.Bits.Enable = 1;\r
c69dd9df 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
394bbc59 163 PciDataStride = Pci.Bits.Reg & 0x03;\r
c69dd9df 164\r
165 while (Count) {\r
166 PciAligned = Pci;\r
394bbc59 167 PciAligned.Bits.Reg &= 0xfc;\r
c69dd9df 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
394bbc59 179 Pci.Bits.Reg += InStride;\r
c69dd9df 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
c69dd9df 211VOID\r
212ScanPciBus(\r
213 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,\r
214 UINT16 MinBus,\r
215 UINT16 MaxBus,\r
216 UINT16 MinDevice,\r
217 UINT16 MaxDevice,\r
218 UINT16 MinFunc,\r
219 UINT16 MaxFunc,\r
220 EFI_PCI_BUS_SCAN_CALLBACK Callback,\r
221 VOID *Context\r
222 )\r
223 \r
224{\r
225 UINT16 Bus;\r
226 UINT16 Device;\r
227 UINT16 Func;\r
228 UINT64 Address;\r
229 PCI_TYPE00 PciHeader;\r
230\r
231 //\r
232 // Loop through all busses\r
233 //\r
234 for (Bus = MinBus; Bus <= MaxBus; Bus++) {\r
235 // \r
236 // Loop 32 devices per bus\r
237 //\r
238 for (Device = MinDevice; Device <= MaxDevice; Device++) {\r
239 //\r
240 // Loop through 8 functions per device\r
241 //\r
242 for (Func = MinFunc; Func <= MaxFunc; Func++) {\r
243\r
244 //\r
245 // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device\r
246 //\r
247 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
248\r
249 //\r
250 // Read the VendorID from this PCI Device's Confioguration Header\r
251 //\r
252 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId);\r
253 \r
254 //\r
255 // If VendorId = 0xffff, there does not exist a device at this \r
256 // location. For each device, if there is any function on it, \r
257 // there must be 1 function at Function 0. So if Func = 0, there\r
258 // will be no more functions in the same device, so we can break\r
259 // loop to deal with the next device.\r
260 // \r
261 if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) {\r
262 break;\r
263 }\r
264 \r
265 if (PciHeader.Hdr.VendorId != 0xffff) {\r
266\r
267 //\r
268 // Read the HeaderType to determine if this is a multi-function device\r
269 //\r
270 IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType);\r
271\r
272 //\r
273 // Call the callback function for the device that was found\r
274 //\r
275 Callback(\r
276 IoDev, \r
277 MinBus, MaxBus,\r
278 MinDevice, MaxDevice,\r
279 MinFunc, MaxFunc,\r
280 Bus,\r
281 Device,\r
282 Func,\r
283 Context\r
284 );\r
285\r
286 //\r
287 // If this is not a multi-function device, we can leave the loop \r
288 // to deal with the next device.\r
289 //\r
290 if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) {\r
291 break;\r
292 }\r
293 } \r
294 }\r
295 }\r
296 }\r
297}\r
298\r
c69dd9df 299VOID\r
300CheckForRom (\r
301 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,\r
302 UINT16 MinBus,\r
303 UINT16 MaxBus,\r
304 UINT16 MinDevice,\r
305 UINT16 MaxDevice,\r
306 UINT16 MinFunc,\r
307 UINT16 MaxFunc,\r
308 UINT16 Bus,\r
309 UINT16 Device,\r
310 UINT16 Func,\r
311 IN VOID *VoidContext\r
312 )\r
313{\r
314 EFI_STATUS Status;\r
315 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;\r
316 UINT64 Address;\r
317 PCI_TYPE00 PciHeader;\r
318 PCI_TYPE01 *PciBridgeHeader;\r
319 UINT32 Register;\r
320 UINT32 RomBar;\r
321 UINT32 RomBarSize;\r
322 EFI_PHYSICAL_ADDRESS RomBuffer;\r
323 UINT32 MaxRomSize;\r
324 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader;\r
325 PCI_DATA_STRUCTURE Pcir;\r
326 EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors;\r
327 BOOLEAN LastImage;\r
328\r
329 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;\r
330\r
331 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
332\r
333 //\r
334 // Save the contents of the PCI Configuration Header\r
335 //\r
336 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);\r
337\r
338 if (IS_PCI_BRIDGE(&PciHeader)) {\r
339\r
340 PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader);\r
341\r
342 //\r
343 // See if the PCI-PCI Bridge has its secondary interface enabled.\r
344 //\r
345 if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) {\r
346\r
347 //\r
348 // Disable the Prefetchable Memory Window\r
349 //\r
350 Register = 0x00000000;\r
351 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register);\r
352 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register);\r
353 Register = 0xffffffff;\r
354 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register);\r
355 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register);\r
356\r
357 //\r
358 // Program Memory Window to the PCI Root Bridge Memory Window\r
359 //\r
360 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow);\r
361\r
362 //\r
363 // Enable the Memory decode for the PCI-PCI Bridge\r
364 //\r
365 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
366 Register |= 0x02;\r
367 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
368\r
369 //\r
370 // Recurse on the Secondary Bus Number\r
371 //\r
372 ScanPciBus(\r
373 IoDev,\r
374 PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, \r
375 0, PCI_MAX_DEVICE, \r
376 0, PCI_MAX_FUNC, \r
377 CheckForRom, Context\r
378 );\r
379 }\r
380 } else {\r
381\r
382 //\r
383 // Check if an Option ROM Register is present and save the Option ROM Window Register\r
384 //\r
385 RomBar = 0xffffffff;\r
386 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
387 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
388\r
389 RomBarSize = (~(RomBar & 0xfffff800)) + 1;\r
390\r
391 //\r
392 // Make sure the size of the ROM is between 0 and 16 MB\r
393 //\r
394 if (RomBarSize > 0 && RomBarSize <= 0x01000000) {\r
395\r
396 //\r
397 // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window\r
398 //\r
399 RomBar = (Context->PpbMemoryWindow & 0xffff) << 16;\r
400 RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize;\r
401 if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) {\r
402 MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar;\r
403 RomBar = RomBar + 1;\r
404 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
405 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
406 RomBar = RomBar - 1;\r
407\r
408 //\r
409 // Enable the Memory decode for the PCI Device\r
410 //\r
411 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
412 Register |= 0x02;\r
413 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
414\r
415 //\r
416 // Follow the chain of images to determine the size of the Option ROM present\r
417 // Keep going until the last image is found by looking at the Indicator field\r
418 // or the size of an image is 0, or the size of all the images is bigger than the\r
419 // size of the window programmed into the PPB.\r
420 //\r
421 RomBarSize = 0;\r
422 do {\r
423\r
424 LastImage = TRUE;\r
425\r
394bbc59 426 ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader));\r
c69dd9df 427 IoDev->Mem.Read (\r
428 IoDev, \r
429 EfiPciWidthUint8, \r
430 RomBar + RomBarSize, \r
431 sizeof(EfiRomHeader),\r
432 &EfiRomHeader\r
433 );\r
434\r
435 Pcir.ImageLength = 0;\r
436\r
437 if (EfiRomHeader.Signature == 0xaa55) {\r
438\r
394bbc59 439 ZeroMem (&Pcir, sizeof(Pcir));\r
c69dd9df 440 IoDev->Mem.Read (\r
441 IoDev, \r
442 EfiPciWidthUint8, \r
443 RomBar + RomBarSize + EfiRomHeader.PcirOffset, \r
444 sizeof(Pcir),\r
445 &Pcir\r
446 );\r
447\r
448 if ((Pcir.Indicator & 0x80) == 0x00) {\r
449 LastImage = FALSE;\r
450 }\r
451\r
452 RomBarSize += Pcir.ImageLength * 512;\r
453 }\r
454 } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0);\r
455\r
456 if (RomBarSize > 0) {\r
457\r
458 //\r
459 // Allocate a memory buffer for the Option ROM contents.\r
460 //\r
461 Status = gBS->AllocatePages(\r
462 AllocateAnyPages,\r
463 EfiBootServicesData,\r
464 EFI_SIZE_TO_PAGES(RomBarSize),\r
465 &RomBuffer\r
466 );\r
467\r
468 if (!EFI_ERROR (Status)) {\r
469\r
470 //\r
471 // Copy the contents of the Option ROM to the memory buffer\r
472 //\r
473 IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer);\r
474\r
475 Status = gBS->AllocatePool(\r
476 EfiBootServicesData,\r
477 ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR),\r
3a0a1473 478 (VOID **) &TempPciOptionRomDescriptors\r
c69dd9df 479 );\r
480 if (mPciOptionRomTable.PciOptionRomCount > 0) {\r
394bbc59 481 CopyMem(\r
c69dd9df 482 TempPciOptionRomDescriptors, \r
483 mPciOptionRomTable.PciOptionRomDescriptors, \r
484 (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR)\r
485 );\r
486\r
487 gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors);\r
488 }\r
489\r
490 mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; \r
491\r
492 TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]);\r
493\r
494 TempPciOptionRomDescriptors->RomAddress = RomBuffer;\r
495 TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData;\r
496 TempPciOptionRomDescriptors->RomLength = RomBarSize;\r
497 TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber;\r
498 TempPciOptionRomDescriptors->Bus = (UINT8)Bus;\r
499 TempPciOptionRomDescriptors->Dev = (UINT8)Device;\r
500 TempPciOptionRomDescriptors->Func = (UINT8)Func;\r
501 TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE;\r
502 TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE;\r
503\r
504 mPciOptionRomTable.PciOptionRomCount++;\r
505 }\r
506 }\r
507\r
508 //\r
509 // Disable the Memory decode for the PCI-PCI Bridge\r
510 //\r
511 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
512 Register &= (~0x02);\r
513 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
514 }\r
515 }\r
516 }\r
517\r
518 //\r
519 // Restore the PCI Configuration Header \r
520 //\r
521 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);\r
522}\r
523\r
c69dd9df 524VOID\r
525SaveCommandRegister (\r
526 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,\r
527 UINT16 MinBus,\r
528 UINT16 MaxBus,\r
529 UINT16 MinDevice,\r
530 UINT16 MaxDevice,\r
531 UINT16 MinFunc,\r
532 UINT16 MaxFunc,\r
533 UINT16 Bus,\r
534 UINT16 Device,\r
535 UINT16 Func,\r
536 IN VOID *VoidContext\r
537 )\r
538\r
539{\r
540 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;\r
541 UINT64 Address;\r
542 UINTN Index;\r
543 UINT16 Command;\r
544\r
545 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;\r
546\r
547 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);\r
548\r
549 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;\r
550\r
551 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);\r
552\r
553 //\r
554 // Clear the memory enable bit\r
555 //\r
3a0a1473 556 Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02));\r
c69dd9df 557\r
558 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command);\r
559}\r
560\r
c69dd9df 561VOID\r
562RestoreCommandRegister (\r
563 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev,\r
564 UINT16 MinBus,\r
565 UINT16 MaxBus,\r
566 UINT16 MinDevice,\r
567 UINT16 MaxDevice,\r
568 UINT16 MinFunc,\r
569 UINT16 MaxFunc,\r
570 UINT16 Bus,\r
571 UINT16 Device,\r
572 UINT16 Func,\r
573 IN VOID *VoidContext\r
574 )\r
575\r
576{\r
577 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context;\r
578 UINT64 Address;\r
579 UINTN Index;\r
580\r
581 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;\r
582\r
583 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);\r
584\r
585 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;\r
586\r
587 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);\r
588}\r
589\r
590EFI_STATUS\r
591ScanPciRootBridgeForRoms(\r
592 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev\r
593 )\r
594 \r
595{\r
596 EFI_STATUS Status;\r
597 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; \r
598 UINT16 MinBus;\r
599 UINT16 MaxBus;\r
600 UINT64 RootWindowBase;\r
601 UINT64 RootWindowLimit;\r
602 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context;\r
603\r
604 if (mPciOptionRomTableInstalled == FALSE) {\r
605 gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable);\r
606 mPciOptionRomTableInstalled = TRUE;\r
607 }\r
608\r
3a0a1473 609 Status = IoDev->Configuration(IoDev, (VOID **) &Descriptors);\r
c69dd9df 610 if (EFI_ERROR (Status) || Descriptors == NULL) {\r
611 return EFI_NOT_FOUND;\r
612 }\r
613\r
614 MinBus = 0xffff;\r
615 MaxBus = 0xffff;\r
616 RootWindowBase = 0;\r
617 RootWindowLimit = 0;\r
618 while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
619 //\r
620 // Find bus range\r
621 //\r
622 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
623 MinBus = (UINT16)Descriptors->AddrRangeMin;\r
624 MaxBus = (UINT16)Descriptors->AddrRangeMax;\r
625 }\r
626 //\r
627 // Find memory descriptors that are not prefetchable\r
628 //\r
629 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) {\r
630 //\r
631 // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices\r
632 //\r
99032c45 633 if (Descriptors->AddrRangeMax < 0x100000000ULL) {\r
c69dd9df 634 //\r
635 // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB\r
636 //\r
637 if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) {\r
638 RootWindowBase = Descriptors->AddrRangeMin;\r
639 RootWindowLimit = Descriptors->AddrRangeMax;\r
640 }\r
641 }\r
642 }\r
643 Descriptors ++;\r
644 }\r
645\r
646 //\r
647 // Make sure a bus range was found\r
648 //\r
649 if (MinBus == 0xffff || MaxBus == 0xffff) {\r
650 return EFI_NOT_FOUND;\r
651 }\r
652\r
653 //\r
654 // Make sure a non-prefetchable memory region was found\r
655 //\r
656 if (RootWindowBase == 0 && RootWindowLimit == 0) {\r
657 return EFI_NOT_FOUND;\r
658 }\r
659\r
660 //\r
661 // Round the Base and Limit values to 1 MB boudaries\r
662 //\r
663 RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000;\r
664 RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1;\r
665\r
666 //\r
667 // Make sure that the size of the rounded window is greater than zero\r
668 //\r
669 if (RootWindowLimit <= RootWindowBase) {\r
670 return EFI_NOT_FOUND;\r
671 }\r
672\r
673 //\r
674 // Allocate buffer to save the Command register from all the PCI devices\r
675 //\r
676 Context.CommandRegisterBuffer = NULL;\r
677 Status = gBS->AllocatePool(\r
678 EfiBootServicesData,\r
679 sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1),\r
3a0a1473 680 (VOID **) &Context.CommandRegisterBuffer\r
c69dd9df 681 );\r
682\r
683 if (EFI_ERROR (Status)) {\r
684 return Status;\r
685 }\r
686\r
687 Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000);\r
688\r
689 //\r
690 // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits\r
691 //\r
692 ScanPciBus(\r
693 IoDev,\r
694 MinBus, MaxBus, \r
695 0, PCI_MAX_DEVICE, \r
696 0, PCI_MAX_FUNC, \r
697 SaveCommandRegister, &Context\r
698 );\r
699\r
700 //\r
701 // Recursively scan all the busses for PCI Option ROMs\r
702 //\r
703 ScanPciBus(\r
704 IoDev,\r
705 MinBus, MinBus, \r
706 0, PCI_MAX_DEVICE, \r
707 0, PCI_MAX_FUNC, \r
708 CheckForRom, &Context\r
709 );\r
710\r
711 //\r
712 // Restore the Command register in all the PCI devices\r
713 //\r
714 ScanPciBus(\r
715 IoDev,\r
716 MinBus, MaxBus, \r
717 0, PCI_MAX_DEVICE, \r
718 0, PCI_MAX_FUNC, \r
719 RestoreCommandRegister, &Context\r
720 );\r
721\r
722 //\r
723 // Free the buffer used to save all the Command register values\r
724 //\r
725 gBS->FreePool(Context.CommandRegisterBuffer);\r
726\r
727 return EFI_SUCCESS;\r
728}\r