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