]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
1) Add type cast for better coding style.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
CommitLineData
9060e3ec 1/** @file\r
2 PCI emumeration support functions implementation for PCI Bus module.\r
3\r
b0bc24af 4Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 5This program and the accompanying materials\r
9060e3ec 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "PciBus.h"\r
16\r
8db6a82c
RN
17extern CHAR16 *mBarTypeStr[];\r
18\r
9060e3ec 19/**\r
20 This routine is used to check whether the pci device is present.\r
21\r
22 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
23 @param Pci Output buffer for PCI device configuration space.\r
24 @param Bus PCI bus NO.\r
25 @param Device PCI device NO.\r
26 @param Func PCI Func NO.\r
27\r
28 @retval EFI_NOT_FOUND PCI device not present.\r
29 @retval EFI_SUCCESS PCI device is found.\r
30\r
31**/\r
32EFI_STATUS\r
33PciDevicePresent (\r
34 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
35 OUT PCI_TYPE00 *Pci,\r
36 IN UINT8 Bus,\r
37 IN UINT8 Device,\r
38 IN UINT8 Func\r
39 )\r
40{\r
41 UINT64 Address;\r
42 EFI_STATUS Status;\r
43\r
44 //\r
45 // Create PCI address map in terms of Bus, Device and Func\r
46 //\r
47 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
48\r
49 //\r
50 // Read the Vendor ID register\r
51 //\r
52 Status = PciRootBridgeIo->Pci.Read (\r
53 PciRootBridgeIo,\r
54 EfiPciWidthUint32,\r
55 Address,\r
56 1,\r
57 Pci\r
58 );\r
59\r
60 if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {\r
61 //\r
62 // Read the entire config header for the device\r
63 //\r
64 Status = PciRootBridgeIo->Pci.Read (\r
65 PciRootBridgeIo,\r
66 EfiPciWidthUint32,\r
67 Address,\r
68 sizeof (PCI_TYPE00) / sizeof (UINT32),\r
69 Pci\r
70 );\r
71\r
72 return EFI_SUCCESS;\r
73 }\r
74\r
75 return EFI_NOT_FOUND;\r
76}\r
77\r
78/**\r
79 Collect all the resource information under this root bridge.\r
80\r
81 A database that records all the information about pci device subject to this\r
82 root bridge will then be created.\r
83\r
84 @param Bridge Parent bridge instance.\r
85 @param StartBusNumber Bus number of begining.\r
86\r
87 @retval EFI_SUCCESS PCI device is found.\r
88 @retval other Some error occurred when reading PCI bridge information.\r
89\r
90**/\r
91EFI_STATUS\r
92PciPciDeviceInfoCollector (\r
93 IN PCI_IO_DEVICE *Bridge,\r
94 IN UINT8 StartBusNumber\r
95 )\r
96{\r
97 EFI_STATUS Status;\r
98 PCI_TYPE00 Pci;\r
99 UINT8 Device;\r
100 UINT8 Func;\r
101 UINT8 SecBus;\r
102 PCI_IO_DEVICE *PciIoDevice;\r
103 EFI_PCI_IO_PROTOCOL *PciIo;\r
104\r
105 Status = EFI_SUCCESS;\r
106 SecBus = 0;\r
107\r
108 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
109\r
110 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
111\r
112 //\r
113 // Check to see whether PCI device is present\r
114 //\r
115 Status = PciDevicePresent (\r
116 Bridge->PciRootBridgeIo,\r
117 &Pci,\r
118 (UINT8) StartBusNumber,\r
119 (UINT8) Device,\r
120 (UINT8) Func\r
121 );\r
122 if (!EFI_ERROR (Status)) {\r
123\r
124 //\r
125 // Call back to host bridge function\r
126 //\r
127 PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);\r
128\r
129 //\r
130 // Collect all the information about the PCI device discovered\r
131 //\r
132 Status = PciSearchDevice (\r
133 Bridge,\r
134 &Pci,\r
135 (UINT8) StartBusNumber,\r
136 Device,\r
137 Func,\r
138 &PciIoDevice\r
139 );\r
140\r
141 //\r
142 // Recursively scan PCI busses on the other side of PCI-PCI bridges\r
143 //\r
144 //\r
145 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {\r
146\r
147 //\r
148 // If it is PPB, we need to get the secondary bus to continue the enumeration\r
149 //\r
150 PciIo = &(PciIoDevice->PciIo);\r
151\r
152 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);\r
153\r
154 if (EFI_ERROR (Status)) {\r
155 return Status;\r
156 }\r
157\r
158 //\r
159 // Get resource padding for PPB\r
160 //\r
161 GetResourcePaddingPpb (PciIoDevice);\r
162\r
163 //\r
164 // Deep enumerate the next level bus\r
165 //\r
166 Status = PciPciDeviceInfoCollector (\r
167 PciIoDevice,\r
168 (UINT8) (SecBus)\r
169 );\r
170\r
171 }\r
172\r
173 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
174\r
175 //\r
176 // Skip sub functions, this is not a multi function device\r
177 //\r
178 Func = PCI_MAX_FUNC;\r
179 }\r
180 }\r
181\r
182 }\r
183 }\r
184\r
185 return EFI_SUCCESS;\r
186}\r
187\r
188/**\r
189 Seach required device and create PCI device instance.\r
190\r
191 @param Bridge Parent bridge instance.\r
192 @param Pci Input PCI device information block.\r
193 @param Bus PCI bus NO.\r
194 @param Device PCI device NO.\r
195 @param Func PCI func NO.\r
196 @param PciDevice Output of searched PCI device instance.\r
197\r
198 @retval EFI_SUCCESS Successfully created PCI device instance.\r
199 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.\r
200\r
201**/\r
202EFI_STATUS\r
203PciSearchDevice (\r
204 IN PCI_IO_DEVICE *Bridge,\r
205 IN PCI_TYPE00 *Pci,\r
206 IN UINT8 Bus,\r
207 IN UINT8 Device,\r
208 IN UINT8 Func,\r
209 OUT PCI_IO_DEVICE **PciDevice\r
210 )\r
211{\r
212 PCI_IO_DEVICE *PciIoDevice;\r
213\r
214 PciIoDevice = NULL;\r
215\r
8db6a82c
RN
216 DEBUG ((\r
217 EFI_D_INFO,\r
218 "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",\r
219 IS_PCI_BRIDGE (Pci) ? L"PPB" :\r
220 IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :\r
221 L"PCI",\r
222 Bus, Device, Func\r
223 ));\r
224\r
9060e3ec 225 if (!IS_PCI_BRIDGE (Pci)) {\r
226\r
227 if (IS_CARDBUS_BRIDGE (Pci)) {\r
228 PciIoDevice = GatherP2CInfo (\r
229 Bridge,\r
230 Pci,\r
231 Bus,\r
232 Device,\r
233 Func\r
234 );\r
235 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
236 InitializeP2C (PciIoDevice);\r
237 }\r
238 } else {\r
239\r
240 //\r
241 // Create private data for Pci Device\r
242 //\r
243 PciIoDevice = GatherDeviceInfo (\r
244 Bridge,\r
245 Pci,\r
246 Bus,\r
247 Device,\r
248 Func\r
249 );\r
250\r
251 }\r
252\r
253 } else {\r
254\r
255 //\r
256 // Create private data for PPB\r
257 //\r
258 PciIoDevice = GatherPpbInfo (\r
259 Bridge,\r
260 Pci,\r
261 Bus,\r
262 Device,\r
263 Func\r
264 );\r
265\r
266 //\r
267 // Special initialization for PPB including making the PPB quiet\r
268 //\r
269 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
270 InitializePpb (PciIoDevice);\r
271 }\r
272 }\r
273\r
274 if (PciIoDevice == NULL) {\r
275 return EFI_OUT_OF_RESOURCES;\r
276 }\r
277\r
278 //\r
279 // Update the bar information for this PCI device so as to support some specific device\r
280 //\r
281 UpdatePciInfo (PciIoDevice);\r
282\r
283 if (PciIoDevice->DevicePath == NULL) {\r
284 return EFI_OUT_OF_RESOURCES;\r
285 }\r
286\r
287 //\r
288 // Detect this function has option rom\r
289 //\r
290 if (gFullEnumeration) {\r
291\r
292 if (!IS_CARDBUS_BRIDGE (Pci)) {\r
293\r
294 GetOpRomInfo (PciIoDevice);\r
295\r
296 }\r
297\r
298 ResetPowerManagementFeature (PciIoDevice);\r
299\r
300 }\r
301\r
302 //\r
303 // Insert it into a global tree for future reference\r
304 //\r
305 InsertPciDevice (Bridge, PciIoDevice);\r
306\r
307 //\r
308 // Determine PCI device attributes\r
309 //\r
310\r
311 if (PciDevice != NULL) {\r
312 *PciDevice = PciIoDevice;\r
313 }\r
314\r
315 return EFI_SUCCESS;\r
316}\r
317\r
8db6a82c
RN
318/**\r
319 Dump the PCI BAR information.\r
320\r
321 @param PciIoDevice PCI IO instance.\r
322**/\r
323VOID\r
324DumpPciBars (\r
325 IN PCI_IO_DEVICE *PciIoDevice\r
326 )\r
327{\r
328 UINTN Index;\r
329\r
330 for (Index = 0; Index < PCI_MAX_BAR; Index++) {\r
331 if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {\r
332 continue;\r
333 }\r
334\r
335 DEBUG ((\r
336 EFI_D_INFO,\r
980050bc 337 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",\r
8db6a82c
RN
338 Index, mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)],\r
339 PciIoDevice->PciBar[Index].Alignment, PciIoDevice->PciBar[Index].Length, PciIoDevice->PciBar[Index].Offset\r
340 ));\r
341 }\r
342\r
343 for (Index = 0; Index < PCI_MAX_BAR; Index++) {\r
344 if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) {\r
345 continue;\r
346 }\r
347\r
348 DEBUG ((\r
349 EFI_D_INFO,\r
980050bc 350 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",\r
8db6a82c
RN
351 Index, mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)],\r
352 PciIoDevice->VfPciBar[Index].Alignment, PciIoDevice->VfPciBar[Index].Length, PciIoDevice->VfPciBar[Index].Offset\r
353 ));\r
354 }\r
355 DEBUG ((EFI_D_INFO, "\n"));\r
356}\r
357\r
9060e3ec 358/**\r
359 Create PCI device instance for PCI device.\r
360\r
361 @param Bridge Parent bridge instance.\r
362 @param Pci Input PCI device information block.\r
363 @param Bus PCI device Bus NO.\r
364 @param Device PCI device Device NO.\r
365 @param Func PCI device's func NO.\r
366\r
367 @return Created PCI device instance.\r
368\r
369**/\r
370PCI_IO_DEVICE *\r
371GatherDeviceInfo (\r
372 IN PCI_IO_DEVICE *Bridge,\r
373 IN PCI_TYPE00 *Pci,\r
374 IN UINT8 Bus,\r
375 IN UINT8 Device,\r
376 IN UINT8 Func\r
377 )\r
378{\r
379 UINTN Offset;\r
380 UINTN BarIndex;\r
381 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 382\r
9060e3ec 383 PciIoDevice = CreatePciIoDevice (\r
d4048391 384 Bridge,\r
9060e3ec 385 Pci,\r
386 Bus,\r
387 Device,\r
388 Func\r
389 );\r
390\r
391 if (PciIoDevice == NULL) {\r
392 return NULL;\r
393 }\r
394\r
9060e3ec 395 //\r
396 // If it is a full enumeration, disconnect the device in advance\r
397 //\r
398 if (gFullEnumeration) {\r
399\r
400 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
401\r
402 }\r
403\r
404 //\r
405 // Start to parse the bars\r
406 //\r
407 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {\r
408 Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
409 }\r
410\r
411 //\r
412 // Parse the SR-IOV VF bars\r
413 //\r
d4048391 414 if (PcdGetBool (PcdSrIovSupport) && PciIoDevice->SrIovCapabilityOffset != 0) {\r
9060e3ec 415 for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;\r
416 Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;\r
417 BarIndex++) {\r
418\r
419 ASSERT (BarIndex < PCI_MAX_BAR);\r
420 Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);\r
421 }\r
422 }\r
8db6a82c
RN
423\r
424 DEBUG_CODE (DumpPciBars (PciIoDevice););\r
9060e3ec 425 return PciIoDevice;\r
426}\r
427\r
428/**\r
429 Create PCI device instance for PCI-PCI bridge.\r
430\r
431 @param Bridge Parent bridge instance.\r
432 @param Pci Input PCI device information block.\r
433 @param Bus PCI device Bus NO.\r
434 @param Device PCI device Device NO.\r
435 @param Func PCI device's func NO.\r
436\r
437 @return Created PCI device instance.\r
438\r
439**/\r
440PCI_IO_DEVICE *\r
441GatherPpbInfo (\r
442 IN PCI_IO_DEVICE *Bridge,\r
443 IN PCI_TYPE00 *Pci,\r
444 IN UINT8 Bus,\r
445 IN UINT8 Device,\r
446 IN UINT8 Func\r
447 )\r
448{\r
9060e3ec 449 PCI_IO_DEVICE *PciIoDevice;\r
450 EFI_STATUS Status;\r
451 UINT8 Value;\r
452 EFI_PCI_IO_PROTOCOL *PciIo;\r
453 UINT8 Temp;\r
07bcff9d 454 UINT32 PMemBaseLimit;\r
455 UINT16 PrefetchableMemoryBase;\r
456 UINT16 PrefetchableMemoryLimit;\r
9060e3ec 457\r
9060e3ec 458 PciIoDevice = CreatePciIoDevice (\r
d4048391 459 Bridge,\r
9060e3ec 460 Pci,\r
461 Bus,\r
462 Device,\r
463 Func\r
464 );\r
465\r
466 if (PciIoDevice == NULL) {\r
467 return NULL;\r
468 }\r
469\r
9060e3ec 470 if (gFullEnumeration) {\r
471 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
472\r
473 //\r
474 // Initalize the bridge control register\r
475 //\r
476 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);\r
477\r
478 }\r
479\r
480 //\r
481 // PPB can have two BARs\r
482 //\r
483 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {\r
484 //\r
485 // Not 64-bit bar\r
486 //\r
487 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);\r
488 }\r
489\r
490 PciIo = &PciIoDevice->PciIo;\r
491\r
492 //\r
493 // Test whether it support 32 decode or not\r
494 //\r
495 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
496 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
497 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
498 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
499\r
500 if (Value != 0) {\r
501 if ((Value & 0x01) != 0) {\r
502 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
503 } else {\r
504 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;\r
505 }\r
506 }\r
507\r
1ef26783 508 //\r
509 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes\r
510 // PCI bridge supporting non-stardard I/O window alignment less than 4K.\r
511 //\r
512\r
513 PciIoDevice->BridgeIoAlignment = 0xFFF;\r
514 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {\r
515 //\r
516 // Check any bits of bit 3-1 of I/O Base Register are writable.\r
517 // if so, it is assumed non-stardard I/O window alignment is supported by this bridge.\r
518 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.\r
519 //\r
f00b5d83 520 Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));\r
1ef26783 521 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
522 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
523 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
f00b5d83 524 Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));\r
1ef26783 525 switch (Value) {\r
526 case BIT3:\r
527 PciIoDevice->BridgeIoAlignment = 0x7FF;\r
528 break;\r
529 case BIT3 | BIT2:\r
530 PciIoDevice->BridgeIoAlignment = 0x3FF;\r
531 break;\r
532 case BIT3 | BIT2 | BIT1:\r
533 PciIoDevice->BridgeIoAlignment = 0x1FF;\r
534 break;\r
535 }\r
536 }\r
537\r
9060e3ec 538 Status = BarExisted (\r
539 PciIoDevice,\r
540 0x24,\r
541 NULL,\r
07bcff9d 542 &PMemBaseLimit\r
9060e3ec 543 );\r
544\r
545 //\r
546 // Test if it supports 64 memory or not\r
547 //\r
07bcff9d 548 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit\r
549 // registers:\r
550 // 0 - the bridge supports only 32 bit addresses.\r
551 // 1 - the bridge supports 64-bit addresses.\r
552 //\r
571e9831 553 PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);\r
554 PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);\r
07bcff9d 555 if (!EFI_ERROR (Status) &&\r
556 (PrefetchableMemoryBase & 0x000f) == 0x0001 &&\r
557 (PrefetchableMemoryLimit & 0x000f) == 0x0001) {\r
9060e3ec 558 Status = BarExisted (\r
559 PciIoDevice,\r
560 0x28,\r
561 NULL,\r
562 NULL\r
563 );\r
564\r
565 if (!EFI_ERROR (Status)) {\r
566 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
567 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;\r
568 } else {\r
569 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
570 }\r
571 }\r
572\r
573 //\r
574 // Memory 32 code is required for ppb\r
575 //\r
576 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;\r
577\r
578 GetResourcePaddingPpb (PciIoDevice);\r
579\r
8db6a82c
RN
580 DEBUG_CODE (DumpPciBars (PciIoDevice););\r
581\r
9060e3ec 582 return PciIoDevice;\r
583}\r
584\r
585\r
586/**\r
587 Create PCI device instance for PCI Card bridge device.\r
588\r
589 @param Bridge Parent bridge instance.\r
590 @param Pci Input PCI device information block.\r
591 @param Bus PCI device Bus NO.\r
592 @param Device PCI device Device NO.\r
593 @param Func PCI device's func NO.\r
594\r
595 @return Created PCI device instance.\r
596\r
597**/\r
598PCI_IO_DEVICE *\r
599GatherP2CInfo (\r
600 IN PCI_IO_DEVICE *Bridge,\r
601 IN PCI_TYPE00 *Pci,\r
602 IN UINT8 Bus,\r
603 IN UINT8 Device,\r
604 IN UINT8 Func\r
605 )\r
606{\r
9060e3ec 607 PCI_IO_DEVICE *PciIoDevice;\r
608\r
9060e3ec 609 PciIoDevice = CreatePciIoDevice (\r
d4048391 610 Bridge,\r
9060e3ec 611 Pci,\r
612 Bus,\r
613 Device,\r
614 Func\r
615 );\r
616\r
617 if (PciIoDevice == NULL) {\r
618 return NULL;\r
619 }\r
620\r
9060e3ec 621 if (gFullEnumeration) {\r
622 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
623\r
624 //\r
625 // Initalize the bridge control register\r
626 //\r
627 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);\r
628 }\r
629\r
630 //\r
631 // P2C only has one bar that is in 0x10\r
632 //\r
633 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);\r
634\r
635 //\r
636 // Read PciBar information from the bar register\r
637 //\r
638 GetBackPcCardBar (PciIoDevice);\r
639 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |\r
640 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |\r
641 EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
642\r
8db6a82c
RN
643 DEBUG_CODE (DumpPciBars (PciIoDevice););\r
644\r
9060e3ec 645 return PciIoDevice;\r
646}\r
647\r
648/**\r
649 Create device path for pci deivce.\r
650\r
651 @param ParentDevicePath Parent bridge's path.\r
652 @param PciIoDevice Pci device instance.\r
653\r
654 @return Device path protocol instance for specific pci device.\r
655\r
656**/\r
657EFI_DEVICE_PATH_PROTOCOL *\r
658CreatePciDevicePath (\r
659 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
660 IN PCI_IO_DEVICE *PciIoDevice\r
661 )\r
662{\r
663\r
664 PCI_DEVICE_PATH PciNode;\r
665\r
666 //\r
667 // Create PCI device path\r
668 //\r
669 PciNode.Header.Type = HARDWARE_DEVICE_PATH;\r
670 PciNode.Header.SubType = HW_PCI_DP;\r
671 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
672\r
673 PciNode.Device = PciIoDevice->DeviceNumber;\r
674 PciNode.Function = PciIoDevice->FunctionNumber;\r
675 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);\r
676\r
677 return PciIoDevice->DevicePath;\r
678}\r
679\r
680/**\r
681 Check whether the PCI IOV VF bar is existed or not.\r
682\r
683 @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
684 @param Offset The offset.\r
685 @param BarLengthValue The bar length value returned.\r
686 @param OriginalBarValue The original bar value returned.\r
687\r
688 @retval EFI_NOT_FOUND The bar doesn't exist.\r
689 @retval EFI_SUCCESS The bar exist.\r
690\r
691**/\r
692EFI_STATUS\r
693VfBarExisted (\r
694 IN PCI_IO_DEVICE *PciIoDevice,\r
695 IN UINTN Offset,\r
696 OUT UINT32 *BarLengthValue,\r
697 OUT UINT32 *OriginalBarValue\r
698 )\r
699{\r
700 EFI_PCI_IO_PROTOCOL *PciIo;\r
701 UINT32 OriginalValue;\r
702 UINT32 Value;\r
703 EFI_TPL OldTpl;\r
704\r
705 //\r
706 // Ensure it is called properly\r
707 //\r
708 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
709 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
710 return EFI_NOT_FOUND;\r
711 }\r
712\r
713 PciIo = &PciIoDevice->PciIo;\r
714\r
715 //\r
716 // Preserve the original value\r
717 //\r
718\r
719 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
720\r
721 //\r
722 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
723 //\r
724 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
725\r
726 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);\r
727 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);\r
728\r
729 //\r
730 // Write back the original value\r
731 //\r
732 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
733\r
734 //\r
735 // Restore TPL to its original level\r
736 //\r
737 gBS->RestoreTPL (OldTpl);\r
738\r
739 if (BarLengthValue != NULL) {\r
740 *BarLengthValue = Value;\r
741 }\r
742\r
743 if (OriginalBarValue != NULL) {\r
744 *OriginalBarValue = OriginalValue;\r
745 }\r
746\r
747 if (Value == 0) {\r
748 return EFI_NOT_FOUND;\r
749 } else {\r
750 return EFI_SUCCESS;\r
751 }\r
752}\r
753\r
754/**\r
755 Check whether the bar is existed or not.\r
756\r
757 @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
758 @param Offset The offset.\r
759 @param BarLengthValue The bar length value returned.\r
760 @param OriginalBarValue The original bar value returned.\r
761\r
762 @retval EFI_NOT_FOUND The bar doesn't exist.\r
763 @retval EFI_SUCCESS The bar exist.\r
764\r
765**/\r
766EFI_STATUS\r
767BarExisted (\r
768 IN PCI_IO_DEVICE *PciIoDevice,\r
769 IN UINTN Offset,\r
770 OUT UINT32 *BarLengthValue,\r
771 OUT UINT32 *OriginalBarValue\r
772 )\r
773{\r
774 EFI_PCI_IO_PROTOCOL *PciIo;\r
775 UINT32 OriginalValue;\r
776 UINT32 Value;\r
777 EFI_TPL OldTpl;\r
778\r
779 PciIo = &PciIoDevice->PciIo;\r
780\r
781 //\r
782 // Preserve the original value\r
783 //\r
784 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
785\r
786 //\r
787 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
788 //\r
789 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
790\r
791 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);\r
792 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);\r
793\r
794 //\r
795 // Write back the original value\r
796 //\r
797 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
798\r
799 //\r
800 // Restore TPL to its original level\r
801 //\r
802 gBS->RestoreTPL (OldTpl);\r
803\r
804 if (BarLengthValue != NULL) {\r
805 *BarLengthValue = Value;\r
806 }\r
807\r
808 if (OriginalBarValue != NULL) {\r
809 *OriginalBarValue = OriginalValue;\r
810 }\r
811\r
812 if (Value == 0) {\r
813 return EFI_NOT_FOUND;\r
814 } else {\r
815 return EFI_SUCCESS;\r
816 }\r
817}\r
818\r
819/**\r
820 Test whether the device can support given attributes.\r
821\r
822 @param PciIoDevice Pci device instance.\r
823 @param Command Input command register value, and\r
824 returned supported register value.\r
825 @param BridgeControl Inout bridge control value for PPB or P2C, and\r
826 returned supported bridge control value.\r
827 @param OldCommand Returned and stored old command register offset.\r
828 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.\r
829\r
830**/\r
831VOID\r
832PciTestSupportedAttribute (\r
833 IN PCI_IO_DEVICE *PciIoDevice,\r
834 IN OUT UINT16 *Command,\r
835 IN OUT UINT16 *BridgeControl,\r
836 OUT UINT16 *OldCommand,\r
837 OUT UINT16 *OldBridgeControl\r
838 )\r
839{\r
840 EFI_TPL OldTpl;\r
841\r
842 //\r
843 // Preserve the original value\r
844 //\r
845 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);\r
846\r
847 //\r
848 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
849 //\r
850 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
851\r
852 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);\r
853 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);\r
854\r
855 //\r
856 // Write back the original value\r
857 //\r
858 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);\r
859\r
860 //\r
861 // Restore TPL to its original level\r
862 //\r
863 gBS->RestoreTPL (OldTpl);\r
864\r
865 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
866\r
867 //\r
868 // Preserve the original value\r
869 //\r
870 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);\r
871\r
872 //\r
873 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
874 //\r
875 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
876\r
877 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);\r
878 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);\r
879\r
880 //\r
881 // Write back the original value\r
882 //\r
883 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);\r
884\r
885 //\r
886 // Restore TPL to its original level\r
887 //\r
888 gBS->RestoreTPL (OldTpl);\r
889\r
890 } else {\r
891 *OldBridgeControl = 0;\r
892 *BridgeControl = 0;\r
893 }\r
894}\r
895\r
896/**\r
897 Set the supported or current attributes of a PCI device.\r
898\r
899 @param PciIoDevice Structure pointer for PCI device.\r
900 @param Command Command register value.\r
901 @param BridgeControl Bridge control value for PPB or P2C.\r
902 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.\r
903\r
904**/\r
905VOID\r
906PciSetDeviceAttribute (\r
907 IN PCI_IO_DEVICE *PciIoDevice,\r
908 IN UINT16 Command,\r
909 IN UINT16 BridgeControl,\r
910 IN UINTN Option\r
911 )\r
912{\r
913 UINT64 Attributes;\r
914\r
915 Attributes = 0;\r
916\r
917 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {\r
918 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
919 }\r
920\r
921 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {\r
922 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
923 }\r
924\r
925 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {\r
926 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
927 }\r
928\r
929 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {\r
930 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
931 }\r
932\r
933 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {\r
934 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
935 }\r
936\r
937 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {\r
938 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
939 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
940 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
941 }\r
942\r
943 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {\r
944 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
945 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;\r
946 }\r
947\r
948 if (Option == EFI_SET_SUPPORTS) {\r
949\r
6e1e5405 950 Attributes |= (UINT64) (EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
9060e3ec 951 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |\r
952 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |\r
953 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
954 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
6e1e5405 955 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
9060e3ec 956\r
e0ee9d93 957 if (IS_PCI_LPC (&PciIoDevice->Pci)) {\r
958 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
980050bc
RN
959 Attributes |= (mReserveIsaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO : \\r
960 (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);\r
9060e3ec 961 }\r
962\r
963 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
964 //\r
965 // For bridge, it should support IDE attributes\r
966 //\r
967 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
968 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
e0ee9d93 969\r
970 if (mReserveVgaAliases) {\r
971 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \\r
972 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);\r
973 } else {\r
974 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \\r
975 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);\r
976 }\r
9060e3ec 977 } else {\r
978\r
979 if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
980 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
981 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
982 }\r
983\r
984 if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
985 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
980050bc
RN
986 Attributes |= (mReserveVgaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO : \\r
987 (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
9060e3ec 988 }\r
989 }\r
990\r
991 PciIoDevice->Supports = Attributes;\r
992 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \\r
993 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
994 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );\r
995\r
996 } else {\r
4ed4e19c 997 //\r
998 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were\r
999 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.\r
1000 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize\r
1001 // fields is not from the the ROM BAR of the PCI controller.\r
1002 //\r
1003 if (!PciIoDevice->EmbeddedRom) {\r
1004 Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;\r
1005 }\r
9060e3ec 1006 PciIoDevice->Attributes = Attributes;\r
1007 }\r
1008}\r
1009\r
1010/**\r
1011 Determine if the device can support Fast Back to Back attribute.\r
1012\r
1013 @param PciIoDevice Pci device instance.\r
1014 @param StatusIndex Status register value.\r
1015\r
1016 @retval EFI_SUCCESS This device support Fast Back to Back attribute.\r
1017 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.\r
1018\r
1019**/\r
1020EFI_STATUS\r
1021GetFastBackToBackSupport (\r
1022 IN PCI_IO_DEVICE *PciIoDevice,\r
1023 IN UINT8 StatusIndex\r
1024 )\r
1025{\r
1026 EFI_PCI_IO_PROTOCOL *PciIo;\r
1027 EFI_STATUS Status;\r
1028 UINT32 StatusRegister;\r
1029\r
1030 //\r
1031 // Read the status register\r
1032 //\r
1033 PciIo = &PciIoDevice->PciIo;\r
1034 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
1035 if (EFI_ERROR (Status)) {\r
1036 return EFI_UNSUPPORTED;\r
1037 }\r
1038\r
1039 //\r
1040 // Check the Fast B2B bit\r
1041 //\r
1042 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {\r
1043 return EFI_SUCCESS;\r
1044 } else {\r
1045 return EFI_UNSUPPORTED;\r
1046 }\r
1047}\r
1048\r
1049/**\r
1050 Process the option ROM for all the children of the specified parent PCI device.\r
1051 It can only be used after the first full Option ROM process.\r
1052\r
1053 @param PciIoDevice Pci device instance.\r
1054\r
1055**/\r
1056VOID\r
1057ProcessOptionRomLight (\r
1058 IN PCI_IO_DEVICE *PciIoDevice\r
1059 )\r
1060{\r
1061 PCI_IO_DEVICE *Temp;\r
1062 LIST_ENTRY *CurrentLink;\r
1063\r
1064 //\r
1065 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1066 //\r
1067 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1068 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1069\r
1070 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1071\r
1072 if (!IsListEmpty (&Temp->ChildList)) {\r
1073 ProcessOptionRomLight (Temp);\r
1074 }\r
1075\r
1076 PciRomGetImageMapping (Temp);\r
1077\r
1078 //\r
1079 // The OpRom has already been processed in the first round\r
1080 //\r
1081 Temp->AllOpRomProcessed = TRUE;\r
1082\r
1083 CurrentLink = CurrentLink->ForwardLink;\r
1084 }\r
1085}\r
1086\r
1087/**\r
1088 Determine the related attributes of all devices under a Root Bridge.\r
1089\r
1090 @param PciIoDevice PCI device instance.\r
1091\r
1092**/\r
1093EFI_STATUS\r
1094DetermineDeviceAttribute (\r
1095 IN PCI_IO_DEVICE *PciIoDevice\r
1096 )\r
1097{\r
1098 UINT16 Command;\r
1099 UINT16 BridgeControl;\r
1100 UINT16 OldCommand;\r
1101 UINT16 OldBridgeControl;\r
1102 BOOLEAN FastB2BSupport;\r
1103 PCI_IO_DEVICE *Temp;\r
1104 LIST_ENTRY *CurrentLink;\r
1105 EFI_STATUS Status;\r
1106\r
1107 //\r
1108 // For Root Bridge, just copy it by RootBridgeIo proctocol\r
1109 // so as to keep consistent with the actual attribute\r
1110 //\r
1111 if (PciIoDevice->Parent == NULL) {\r
1112 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
1113 PciIoDevice->PciRootBridgeIo,\r
1114 &PciIoDevice->Supports,\r
1115 &PciIoDevice->Attributes\r
1116 );\r
1117 if (EFI_ERROR (Status)) {\r
1118 return Status;\r
1119 }\r
5a3a6aa7 1120 //\r
1121 // Assume the PCI Root Bridge supports DAC\r
1122 //\r
6e1e5405 1123 PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
5a3a6aa7 1124 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
1125 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
7afa5ea8 1126\r
9060e3ec 1127 } else {\r
1128\r
1129 //\r
1130 // Set the attributes to be checked for common PCI devices and PPB or P2C\r
1131 // Since some devices only support part of them, it is better to set the\r
1132 // attribute according to its command or bridge control register\r
1133 //\r
1134 Command = EFI_PCI_COMMAND_IO_SPACE |\r
1135 EFI_PCI_COMMAND_MEMORY_SPACE |\r
1136 EFI_PCI_COMMAND_BUS_MASTER |\r
1137 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1138\r
1139 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
1140\r
1141 //\r
1142 // Test whether the device can support attributes above\r
1143 //\r
1144 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
1145\r
1146 //\r
1147 // Set the supported attributes for specified PCI device\r
1148 //\r
1149 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
1150\r
1151 //\r
1152 // Set the current attributes for specified PCI device\r
1153 //\r
1154 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
1155\r
1156 //\r
1157 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL\r
1158 //\r
1159 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
1160 }\r
1161\r
1162 FastB2BSupport = TRUE;\r
1163\r
1164 //\r
1165 // P2C can not support FB2B on the secondary side\r
1166 //\r
1167 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1168 FastB2BSupport = FALSE;\r
1169 }\r
1170\r
1171 //\r
1172 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1173 //\r
1174 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1175 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1176\r
1177 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1178 Status = DetermineDeviceAttribute (Temp);\r
1179 if (EFI_ERROR (Status)) {\r
1180 return Status;\r
1181 }\r
1182 //\r
1183 // Detect Fast Bact to Bact support for the device under the bridge\r
1184 //\r
1185 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1186 if (FastB2BSupport && EFI_ERROR (Status)) {\r
1187 FastB2BSupport = FALSE;\r
1188 }\r
1189\r
1190 CurrentLink = CurrentLink->ForwardLink;\r
1191 }\r
1192 //\r
1193 // Set or clear Fast Back to Back bit for the whole bridge\r
1194 //\r
1195 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
1196\r
1197 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1198\r
1199 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1200\r
1201 if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1202 FastB2BSupport = FALSE;\r
1203 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1204 } else {\r
1205 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1206 }\r
1207 }\r
1208\r
1209 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1210 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1211 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1212 if (FastB2BSupport) {\r
1213 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1214 } else {\r
1215 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1216 }\r
1217\r
1218 CurrentLink = CurrentLink->ForwardLink;\r
1219 }\r
1220 }\r
1221 //\r
1222 // End for IsListEmpty\r
1223 //\r
1224 return EFI_SUCCESS;\r
1225}\r
1226\r
1227/**\r
1228 This routine is used to update the bar information for those incompatible PCI device.\r
1229\r
1230 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated\r
1231 Bar information.\r
1232\r
1233 @retval EFI_SUCCESS Successfully updated bar information.\r
1234 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.\r
1235\r
1236**/\r
1237EFI_STATUS\r
1238UpdatePciInfo (\r
1239 IN OUT PCI_IO_DEVICE *PciIoDevice\r
1240 )\r
1241{\r
1242 EFI_STATUS Status;\r
1243 UINTN BarIndex;\r
1244 UINTN BarEndIndex;\r
1245 BOOLEAN SetFlag;\r
1246 VOID *Configuration;\r
1247 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1248\r
1249 Configuration = NULL;\r
1250 Status = EFI_SUCCESS;\r
1251\r
1252 if (gEfiIncompatiblePciDeviceSupport == NULL) {\r
1253 //\r
1254 // It can only be supported after the Incompatible PCI Device\r
1255 // Support Protocol has been installed\r
1256 //\r
1257 Status = gBS->LocateProtocol (\r
1258 &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
1259 NULL,\r
1260 (VOID **) &gEfiIncompatiblePciDeviceSupport\r
1261 );\r
1262 }\r
1263 if (Status == EFI_SUCCESS) {\r
1264 //\r
1265 // Check whether the device belongs to incompatible devices from protocol or not\r
1266 // If it is , then get its special requirement in the ACPI table\r
1267 //\r
1268 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (\r
1269 gEfiIncompatiblePciDeviceSupport,\r
1270 PciIoDevice->Pci.Hdr.VendorId,\r
1271 PciIoDevice->Pci.Hdr.DeviceId,\r
1272 PciIoDevice->Pci.Hdr.RevisionID,\r
1273 PciIoDevice->Pci.Device.SubsystemVendorID,\r
1274 PciIoDevice->Pci.Device.SubsystemID,\r
1275 &Configuration\r
1276 );\r
1277\r
1278 }\r
1279\r
1280 if (EFI_ERROR (Status) || Configuration == NULL ) {\r
1281 return EFI_UNSUPPORTED;\r
1282 }\r
1283\r
1284 //\r
1285 // Update PCI device information from the ACPI table\r
1286 //\r
1287 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1288\r
1289 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1290\r
1291 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1292 //\r
1293 // The format is not support\r
1294 //\r
1295 break;\r
1296 }\r
1297\r
1298 BarIndex = (UINTN) Ptr->AddrTranslationOffset;\r
1299 BarEndIndex = BarIndex;\r
1300\r
1301 //\r
1302 // Update all the bars in the device\r
1303 //\r
1304 if (BarIndex == PCI_BAR_ALL) {\r
1305 BarIndex = 0;\r
1306 BarEndIndex = PCI_MAX_BAR - 1;\r
1307 }\r
1308\r
1309 if (BarIndex > PCI_MAX_BAR) {\r
1310 Ptr++;\r
1311 continue;\r
1312 }\r
1313\r
1314 for (; BarIndex <= BarEndIndex; BarIndex++) {\r
1315 SetFlag = FALSE;\r
1316 switch (Ptr->ResType) {\r
1317 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1318\r
1319 //\r
1320 // Make sure the bar is memory type\r
1321 //\r
1322 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {\r
1323 SetFlag = TRUE;\r
1324 }\r
1325 break;\r
1326\r
1327 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1328\r
1329 //\r
1330 // Make sure the bar is IO type\r
1331 //\r
1332 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
1333 SetFlag = TRUE;\r
1334 }\r
1335 break;\r
1336 }\r
1337\r
1338 if (SetFlag) {\r
1339\r
1340 //\r
1341 // Update the new alignment for the device\r
1342 //\r
1343 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1344\r
1345 //\r
1346 // Update the new length for the device\r
1347 //\r
1348 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {\r
1349 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1350 }\r
1351 }\r
1352 }\r
1353\r
1354 Ptr++;\r
1355 }\r
1356\r
1357 FreePool (Configuration);\r
1358\r
1359 return EFI_SUCCESS;\r
1360}\r
1361\r
1362/**\r
1363 This routine will update the alignment with the new alignment.\r
1364\r
1365 @param Alignment Input Old alignment. Output updated alignment.\r
1366 @param NewAlignment New alignment.\r
1367\r
1368**/\r
1369VOID\r
1370SetNewAlign (\r
1371 IN OUT UINT64 *Alignment,\r
1372 IN UINT64 NewAlignment\r
1373 )\r
1374{\r
1375 UINT64 OldAlignment;\r
1376 UINTN ShiftBit;\r
1377\r
1378 //\r
1379 // The new alignment is the same as the original,\r
1380 // so skip it\r
1381 //\r
1382 if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
1383 return ;\r
1384 }\r
1385 //\r
1386 // Check the validity of the parameter\r
1387 //\r
1388 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&\r
1389 NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
1390 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
1391 *Alignment = NewAlignment;\r
1392 return ;\r
1393 }\r
1394\r
1395 OldAlignment = (*Alignment) + 1;\r
1396 ShiftBit = 0;\r
1397\r
1398 //\r
1399 // Get the first non-zero hex value of the length\r
1400 //\r
1401 while ((OldAlignment & 0x0F) == 0x00) {\r
1402 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1403 ShiftBit += 4;\r
1404 }\r
1405\r
1406 //\r
1407 // Adjust the alignment to even, quad or double quad boundary\r
1408 //\r
1409 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
1410 if ((OldAlignment & 0x01) != 0) {\r
1411 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1412 }\r
1413 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
1414 if ((OldAlignment & 0x03) != 0) {\r
1415 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1416 }\r
1417 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
1418 if ((OldAlignment & 0x07) != 0) {\r
1419 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1420 }\r
1421 }\r
1422\r
1423 //\r
1424 // Update the old value\r
1425 //\r
1426 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1427 *Alignment = NewAlignment;\r
1428\r
1429 return ;\r
1430}\r
1431\r
1432/**\r
1433 Parse PCI IOV VF bar information and fill them into PCI device instance.\r
1434\r
1435 @param PciIoDevice Pci device instance.\r
1436 @param Offset Bar offset.\r
1437 @param BarIndex Bar index.\r
1438\r
1439 @return Next bar offset.\r
1440\r
1441**/\r
1442UINTN\r
1443PciIovParseVfBar (\r
1444 IN PCI_IO_DEVICE *PciIoDevice,\r
1445 IN UINTN Offset,\r
1446 IN UINTN BarIndex\r
1447 )\r
1448{\r
1449 UINT32 Value;\r
1450 UINT32 OriginalValue;\r
1451 UINT32 Mask;\r
9060e3ec 1452 EFI_STATUS Status;\r
1453\r
1454 //\r
1455 // Ensure it is called properly\r
1456 //\r
1457 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
1458 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
1459 return 0;\r
1460 }\r
1461\r
1462 OriginalValue = 0;\r
1463 Value = 0;\r
1464\r
1465 Status = VfBarExisted (\r
1466 PciIoDevice,\r
1467 Offset,\r
1468 &Value,\r
1469 &OriginalValue\r
1470 );\r
1471\r
1472 if (EFI_ERROR (Status)) {\r
1473 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1474 PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
1475 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1476\r
1477 //\r
1478 // Scan all the BARs anyway\r
1479 //\r
d4048391 1480 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
9060e3ec 1481 return Offset + 4;\r
1482 }\r
1483\r
d4048391 1484 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
aa75dfec 1485 if ((Value & 0x01) != 0) {\r
9060e3ec 1486 //\r
1487 // Device I/Os. Impossible\r
1488 //\r
1489 ASSERT (FALSE);\r
1490 return Offset + 4;\r
1491\r
1492 } else {\r
1493\r
1494 Mask = 0xfffffff0;\r
1495\r
1496 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1497\r
1498 switch (Value & 0x07) {\r
1499\r
1500 //\r
1501 //memory space; anywhere in 32 bit address space\r
1502 //\r
1503 case 0x00:\r
aa75dfec 1504 if ((Value & 0x08) != 0) {\r
9060e3ec 1505 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
1506 } else {\r
1507 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
1508 }\r
1509\r
1510 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1511 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1512\r
1513 //\r
1514 // Adjust Length\r
1515 //\r
1516 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1517 //\r
1518 // Adjust Alignment\r
1519 //\r
1520 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1521 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1522 }\r
1523\r
1524 break;\r
1525\r
1526 //\r
1527 // memory space; anywhere in 64 bit address space\r
1528 //\r
1529 case 0x04:\r
aa75dfec 1530 if ((Value & 0x08) != 0) {\r
9060e3ec 1531 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
1532 } else {\r
1533 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
1534 }\r
1535\r
1536 //\r
1537 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1538 // is regarded as an extension for the first bar. As a result\r
1539 // the sizing will be conducted on combined 64 bit value\r
1540 // Here just store the masked first 32bit value for future size\r
1541 // calculation\r
1542 //\r
1543 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
1544 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1545\r
1546 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1547 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1548 }\r
1549\r
1550 //\r
1551 // Increment the offset to point to next DWORD\r
1552 //\r
1553 Offset += 4;\r
1554\r
1555 Status = VfBarExisted (\r
1556 PciIoDevice,\r
1557 Offset,\r
1558 &Value,\r
1559 &OriginalValue\r
1560 );\r
1561\r
1562 if (EFI_ERROR (Status)) {\r
1563 return Offset + 4;\r
1564 }\r
1565\r
1566 //\r
1567 // Fix the length to support some spefic 64 bit BAR\r
1568 //\r
c0394e04 1569 Value |= ((UINT32) -1 << HighBitSet32 (Value));\r
9060e3ec 1570\r
1571 //\r
1572 // Calculate the size of 64bit bar\r
1573 //\r
1574 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1575\r
1576 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1577 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
1578 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1579\r
1580 //\r
1581 // Adjust Length\r
1582 //\r
1583 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1584 //\r
1585 // Adjust Alignment\r
1586 //\r
1587 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1588 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1589 }\r
1590\r
1591 break;\r
1592\r
1593 //\r
1594 // reserved\r
1595 //\r
1596 default:\r
1597 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1598 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1599 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1600\r
1601 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1602 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1603 }\r
1604\r
1605 break;\r
1606 }\r
1607 }\r
1608 \r
1609 //\r
1610 // Check the length again so as to keep compatible with some special bars\r
1611 //\r
1612 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
1613 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1614 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1615 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1616 }\r
1617 \r
1618 //\r
1619 // Increment number of bar\r
1620 //\r
1621 return Offset + 4;\r
1622}\r
1623\r
1624/**\r
1625 Parse PCI bar information and fill them into PCI device instance.\r
1626\r
1627 @param PciIoDevice Pci device instance.\r
1628 @param Offset Bar offset.\r
1629 @param BarIndex Bar index.\r
1630\r
1631 @return Next bar offset.\r
1632\r
1633**/\r
1634UINTN\r
1635PciParseBar (\r
1636 IN PCI_IO_DEVICE *PciIoDevice,\r
1637 IN UINTN Offset,\r
1638 IN UINTN BarIndex\r
1639 )\r
1640{\r
1641 UINT32 Value;\r
1642 UINT32 OriginalValue;\r
1643 UINT32 Mask;\r
9060e3ec 1644 EFI_STATUS Status;\r
1645\r
1646 OriginalValue = 0;\r
1647 Value = 0;\r
1648\r
1649 Status = BarExisted (\r
1650 PciIoDevice,\r
1651 Offset,\r
1652 &Value,\r
1653 &OriginalValue\r
1654 );\r
1655\r
1656 if (EFI_ERROR (Status)) {\r
1657 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1658 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1659 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1660\r
1661 //\r
1662 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1663 //\r
1664 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1665 return Offset + 4;\r
1666 }\r
1667\r
1668 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1669 if ((Value & 0x01) != 0) {\r
1670 //\r
1671 // Device I/Os\r
1672 //\r
1673 Mask = 0xfffffffc;\r
1674\r
1675 if ((Value & 0xFFFF0000) != 0) {\r
1676 //\r
1677 // It is a IO32 bar\r
1678 //\r
1679 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1680 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1681 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1682\r
1683 } else {\r
1684 //\r
1685 // It is a IO16 bar\r
1686 //\r
1687 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1688 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1689 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1690\r
1691 }\r
1692 //\r
1693 // Workaround. Some platforms inplement IO bar with 0 length\r
1694 // Need to treat it as no-bar\r
1695 //\r
1696 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1697 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1698 }\r
1699\r
1700 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
1701 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1702\r
1703 } else {\r
1704\r
1705 Mask = 0xfffffff0;\r
1706\r
1707 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1708\r
1709 switch (Value & 0x07) {\r
1710\r
1711 //\r
1712 //memory space; anywhere in 32 bit address space\r
1713 //\r
1714 case 0x00:\r
1715 if ((Value & 0x08) != 0) {\r
1716 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1717 } else {\r
1718 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1719 }\r
1720\r
1721 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1722 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1723 //\r
1724 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1725 //\r
1726 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1727 } else {\r
1728 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1729 }\r
1730 break;\r
1731\r
1732 //\r
1733 // memory space; anywhere in 64 bit address space\r
1734 //\r
1735 case 0x04:\r
1736 if ((Value & 0x08) != 0) {\r
1737 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1738 } else {\r
1739 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1740 }\r
1741\r
1742 //\r
1743 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1744 // is regarded as an extension for the first bar. As a result\r
1745 // the sizing will be conducted on combined 64 bit value\r
1746 // Here just store the masked first 32bit value for future size\r
1747 // calculation\r
1748 //\r
1749 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1750 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1751\r
1752 //\r
1753 // Increment the offset to point to next DWORD\r
1754 //\r
1755 Offset += 4;\r
1756\r
1757 Status = BarExisted (\r
1758 PciIoDevice,\r
1759 Offset,\r
1760 &Value,\r
1761 &OriginalValue\r
1762 );\r
1763\r
1764 if (EFI_ERROR (Status)) {\r
1765 //\r
1766 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
1767 //\r
1768 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1769 //\r
1770 // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
1771 //\r
1772 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1773 }\r
1774 return Offset + 4;\r
1775 }\r
1776\r
1777 //\r
1778 // Fix the length to support some spefic 64 bit BAR\r
1779 //\r
c0394e04 1780 Value |= ((UINT32)(-1) << HighBitSet32 (Value));\r
9060e3ec 1781\r
1782 //\r
1783 // Calculate the size of 64bit bar\r
1784 //\r
1785 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1786\r
1787 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1788 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1789 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1790 //\r
1791 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1792 //\r
1793 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1794 } else {\r
1795 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1796 }\r
1797\r
1798 break;\r
1799\r
1800 //\r
1801 // reserved\r
1802 //\r
1803 default:\r
1804 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1805 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1806 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1807 //\r
1808 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1809 //\r
1810 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1811 } else {\r
1812 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1813 }\r
1814 break;\r
1815 }\r
1816 }\r
1817\r
1818 //\r
1819 // Check the length again so as to keep compatible with some special bars\r
1820 //\r
1821 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1822 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1823 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1824 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1825 }\r
1826\r
1827 //\r
1828 // Increment number of bar\r
1829 //\r
1830 return Offset + 4;\r
1831}\r
1832\r
1833/**\r
1834 This routine is used to initialize the bar of a PCI device.\r
1835\r
1836 @param PciIoDevice Pci device instance.\r
1837\r
1838 @note It can be called typically when a device is going to be rejected.\r
1839\r
1840**/\r
1841VOID\r
1842InitializePciDevice (\r
1843 IN PCI_IO_DEVICE *PciIoDevice\r
1844 )\r
1845{\r
1846 EFI_PCI_IO_PROTOCOL *PciIo;\r
1847 UINT8 Offset;\r
1848\r
1849 PciIo = &(PciIoDevice->PciIo);\r
1850\r
1851 //\r
1852 // Put all the resource apertures\r
1853 // Resource base is set to all ones so as to indicate its resource\r
1854 // has not been alloacted\r
1855 //\r
1856 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1857 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1858 }\r
1859}\r
1860\r
1861/**\r
1862 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1863\r
1864 @param PciIoDevice PCI-PCI bridge device instance.\r
1865\r
1866**/\r
1867VOID\r
1868InitializePpb (\r
1869 IN PCI_IO_DEVICE *PciIoDevice\r
1870 )\r
1871{\r
1872 EFI_PCI_IO_PROTOCOL *PciIo;\r
1873\r
1874 PciIo = &(PciIoDevice->PciIo);\r
1875\r
1876 //\r
1877 // Put all the resource apertures including IO16\r
1878 // Io32, pMem32, pMem64 to quiescent state\r
1879 // Resource base all ones, Resource limit all zeros\r
1880 //\r
1881 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1882 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
1883\r
1884 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1885 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
1886\r
1887 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1888 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
1889\r
1890 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1891 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
1892\r
1893 //\r
1894 // Don't support use io32 as for now\r
1895 //\r
1896 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1897 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
1898\r
1899 //\r
1900 // Force Interrupt line to zero for cards that come up randomly\r
1901 //\r
1902 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1903}\r
1904\r
1905/**\r
1906 This routine is used to initialize the bar of a PCI Card Bridge device.\r
1907\r
1908 @param PciIoDevice PCI Card bridge device.\r
1909\r
1910**/\r
1911VOID\r
1912InitializeP2C (\r
1913 IN PCI_IO_DEVICE *PciIoDevice\r
1914 )\r
1915{\r
1916 EFI_PCI_IO_PROTOCOL *PciIo;\r
1917\r
1918 PciIo = &(PciIoDevice->PciIo);\r
1919\r
1920 //\r
1921 // Put all the resource apertures including IO16\r
1922 // Io32, pMem32, pMem64 to quiescent state(\r
1923 // Resource base all ones, Resource limit all zeros\r
1924 //\r
1925 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
1926 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
1927\r
1928 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
1929 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
1930\r
1931 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
1932 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
1933\r
1934 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
1935 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
1936\r
1937 //\r
1938 // Force Interrupt line to zero for cards that come up randomly\r
1939 //\r
1940 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1941}\r
1942\r
1943/**\r
1944 Create and initiliaze general PCI I/O device instance for\r
1945 PCI device/bridge device/hotplug bridge device.\r
1946\r
1947 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1948 @param Pci Input Pci information block.\r
1949 @param Bus Device Bus NO.\r
1950 @param Device Device device NO.\r
1951 @param Func Device func NO.\r
1952\r
1953 @return Instance of PCI device. NULL means no instance created.\r
1954\r
1955**/\r
1956PCI_IO_DEVICE *\r
1957CreatePciIoDevice (\r
d4048391 1958 IN PCI_IO_DEVICE *Bridge,\r
9060e3ec 1959 IN PCI_TYPE00 *Pci,\r
1960 IN UINT8 Bus,\r
1961 IN UINT8 Device,\r
1962 IN UINT8 Func\r
1963 )\r
1964{\r
d4048391 1965 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 1966 EFI_PCI_IO_PROTOCOL *PciIo;\r
1967 EFI_STATUS Status;\r
1968\r
1969 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
1970 if (PciIoDevice == NULL) {\r
1971 return NULL;\r
1972 }\r
1973\r
1974 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
1975 PciIoDevice->Handle = NULL;\r
d4048391 1976 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
9060e3ec 1977 PciIoDevice->DevicePath = NULL;\r
1978 PciIoDevice->BusNumber = Bus;\r
1979 PciIoDevice->DeviceNumber = Device;\r
1980 PciIoDevice->FunctionNumber = Func;\r
1981 PciIoDevice->Decodes = 0;\r
1982\r
1983 if (gFullEnumeration) {\r
1984 PciIoDevice->Allocated = FALSE;\r
1985 } else {\r
1986 PciIoDevice->Allocated = TRUE;\r
1987 }\r
1988\r
1989 PciIoDevice->Registered = FALSE;\r
1990 PciIoDevice->Attributes = 0;\r
1991 PciIoDevice->Supports = 0;\r
1992 PciIoDevice->BusOverride = FALSE;\r
1993 PciIoDevice->AllOpRomProcessed = FALSE;\r
1994\r
1995 PciIoDevice->IsPciExp = FALSE;\r
1996\r
1997 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
1998\r
1999 //\r
2000 // Initialize the PCI I/O instance structure\r
2001 //\r
2002 InitializePciIoInstance (PciIoDevice);\r
2003 InitializePciDriverOverrideInstance (PciIoDevice);\r
2004 InitializePciLoadFile2 (PciIoDevice);\r
2005 PciIo = &PciIoDevice->PciIo;\r
2006\r
b0bc24af
AW
2007 //\r
2008 // Create a device path for this PCI device and store it into its private data\r
2009 //\r
2010 CreatePciDevicePath (\r
2011 Bridge->DevicePath,\r
2012 PciIoDevice\r
2013 );\r
2014\r
9060e3ec 2015 //\r
2016 // Detect if PCI Express Device\r
2017 //\r
2018 PciIoDevice->PciExpressCapabilityOffset = 0;\r
2019 Status = LocateCapabilityRegBlock (\r
2020 PciIoDevice,\r
2021 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
2022 &PciIoDevice->PciExpressCapabilityOffset,\r
2023 NULL\r
2024 );\r
2025 if (!EFI_ERROR (Status)) {\r
2026 PciIoDevice->IsPciExp = TRUE;\r
2027 }\r
2028\r
d4048391 2029 if (PcdGetBool (PcdAriSupport)) {\r
2030 //\r
2031 // Check if the device is an ARI device.\r
2032 //\r
2033 Status = LocatePciExpressCapabilityRegBlock (\r
2034 PciIoDevice,\r
2035 EFI_PCIE_CAPABILITY_ID_ARI,\r
2036 &PciIoDevice->AriCapabilityOffset,\r
2037 NULL\r
2038 );\r
2039 if (!EFI_ERROR (Status)) {\r
2040 //\r
2041 // We need to enable ARI feature before calculate BusReservation,\r
2042 // because FirstVFOffset and VFStride may change after that.\r
2043 //\r
2044 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
2045 UINT32 Data32;\r
9060e3ec 2046\r
d4048391 2047 //\r
2048 // Check if its parent supports ARI forwarding.\r
2049 //\r
2050 ParentPciIo = &Bridge->PciIo;\r
2051 ParentPciIo->Pci.Read (\r
2052 ParentPciIo, \r
2053 EfiPciIoWidthUint32,\r
2054 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
2055 1,\r
2056 &Data32\r
2057 );\r
2058 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
2059 //\r
2060 // ARI forward support in bridge, so enable it.\r
2061 //\r
2062 ParentPciIo->Pci.Read (\r
2063 ParentPciIo,\r
2064 EfiPciIoWidthUint32,\r
2065 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2066 1,\r
2067 &Data32\r
2068 );\r
2069 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2070 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2071 ParentPciIo->Pci.Write (\r
2072 ParentPciIo,\r
2073 EfiPciIoWidthUint32,\r
2074 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2075 1,\r
2076 &Data32\r
2077 );\r
2078 DEBUG ((\r
2079 EFI_D_INFO,\r
8db6a82c
RN
2080 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",\r
2081 Bridge->BusNumber,\r
2082 Bridge->DeviceNumber,\r
2083 Bridge->FunctionNumber\r
d4048391 2084 ));\r
2085 }\r
2086 }\r
9060e3ec 2087\r
8db6a82c 2088 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));\r
d4048391 2089 }\r
9060e3ec 2090 }\r
2091\r
2092 //\r
d4048391 2093 // Initialization for SR-IOV\r
9060e3ec 2094 //\r
9060e3ec 2095\r
d4048391 2096 if (PcdGetBool (PcdSrIovSupport)) {\r
2097 Status = LocatePciExpressCapabilityRegBlock (\r
2098 PciIoDevice,\r
2099 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2100 &PciIoDevice->SrIovCapabilityOffset,\r
2101 NULL\r
2102 );\r
2103 if (!EFI_ERROR (Status)) {\r
8db6a82c 2104 UINT32 SupportedPageSize;\r
d4048391 2105 UINT16 VFStride;\r
2106 UINT16 FirstVFOffset;\r
2107 UINT16 Data16;\r
2108 UINT32 PFRid;\r
2109 UINT32 LastVF;\r
2110\r
2111 //\r
2112 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2113 //\r
2114 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {\r
2115 PciIo->Pci.Read (\r
2116 PciIo,\r
2117 EfiPciIoWidthUint16,\r
2118 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2119 1,\r
2120 &Data16\r
2121 );\r
2122 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2123 PciIo->Pci.Write (\r
2124 PciIo,\r
2125 EfiPciIoWidthUint16,\r
2126 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2127 1,\r
2128 &Data16\r
2129 );\r
2130 }\r
9060e3ec 2131\r
d4048391 2132 //\r
2133 // Calculate SystemPageSize\r
2134 //\r
9060e3ec 2135\r
d4048391 2136 PciIo->Pci.Read (\r
2137 PciIo,\r
2138 EfiPciIoWidthUint32,\r
2139 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2140 1,\r
8db6a82c 2141 &SupportedPageSize\r
d4048391 2142 );\r
8db6a82c 2143 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);\r
d4048391 2144 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2145\r
2146 PciIo->Pci.Write (\r
2147 PciIo,\r
2148 EfiPciIoWidthUint32,\r
2149 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2150 1,\r
2151 &PciIoDevice->SystemPageSize\r
2152 );\r
d4048391 2153 //\r
2154 // Adjust SystemPageSize for Alignment usage later\r
2155 //\r
2156 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2157\r
d4048391 2158 //\r
2159 // Calculate BusReservation for PCI IOV\r
2160 //\r
9060e3ec 2161\r
d4048391 2162 //\r
2163 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2164 //\r
2165 PciIo->Pci.Read (\r
2166 PciIo,\r
2167 EfiPciIoWidthUint16,\r
2168 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2169 1,\r
2170 &FirstVFOffset\r
2171 );\r
d4048391 2172 PciIo->Pci.Read (\r
2173 PciIo,\r
2174 EfiPciIoWidthUint16,\r
2175 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2176 1,\r
2177 &PciIoDevice->InitialVFs\r
2178 );\r
d4048391 2179 PciIo->Pci.Read (\r
2180 PciIo,\r
2181 EfiPciIoWidthUint16,\r
2182 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2183 1,\r
2184 &VFStride\r
2185 );\r
d4048391 2186 //\r
2187 // Calculate LastVF\r
2188 //\r
2189 PFRid = EFI_PCI_RID(Bus, Device, Func);\r
2190 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2191\r
d4048391 2192 //\r
2193 // Calculate ReservedBusNum for this PF\r
2194 //\r
2195 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
8db6a82c 2196\r
d4048391 2197 DEBUG ((\r
2198 EFI_D_INFO,\r
8db6a82c
RN
2199 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",\r
2200 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset\r
d4048391 2201 ));\r
d4048391 2202 DEBUG ((\r
2203 EFI_D_INFO,\r
8db6a82c
RN
2204 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",\r
2205 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset\r
d4048391 2206 ));\r
2207 }\r
9060e3ec 2208 }\r
2209\r
d4048391 2210 if (PcdGetBool (PcdMrIovSupport)) {\r
2211 Status = LocatePciExpressCapabilityRegBlock (\r
2212 PciIoDevice,\r
2213 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2214 &PciIoDevice->MrIovCapabilityOffset,\r
2215 NULL\r
2216 );\r
2217 if (!EFI_ERROR (Status)) {\r
8db6a82c 2218 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));\r
d4048391 2219 }\r
2220 }\r
9060e3ec 2221\r
2222 //\r
2223 // Initialize the reserved resource list\r
2224 //\r
2225 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2226\r
2227 //\r
2228 // Initialize the driver list\r
2229 //\r
2230 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2231\r
2232 //\r
2233 // Initialize the child list\r
2234 //\r
2235 InitializeListHead (&PciIoDevice->ChildList);\r
2236\r
2237 return PciIoDevice;\r
2238}\r
2239\r
2240/**\r
2241 This routine is used to enumerate entire pci bus system\r
2242 in a given platform.\r
2243\r
2244 It is only called on the second start on the same Root Bridge.\r
2245\r
2246 @param Controller Parent bridge handler.\r
2247\r
2248 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2249 @retval other Some error occurred when enumerating the pci bus system.\r
2250\r
2251**/\r
2252EFI_STATUS\r
2253PciEnumeratorLight (\r
2254 IN EFI_HANDLE Controller\r
2255 )\r
2256{\r
2257\r
2258 EFI_STATUS Status;\r
2259 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2260 PCI_IO_DEVICE *RootBridgeDev;\r
2261 UINT16 MinBus;\r
2262 UINT16 MaxBus;\r
2263 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
2264\r
2265 MinBus = 0;\r
2266 MaxBus = PCI_MAX_BUS;\r
2267 Descriptors = NULL;\r
2268\r
2269 //\r
2270 // If this root bridge has been already enumerated, then return successfully\r
2271 //\r
2272 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2273 return EFI_SUCCESS;\r
2274 }\r
2275\r
2276 //\r
2277 // Open pci root bridge io protocol\r
2278 //\r
2279 Status = gBS->OpenProtocol (\r
2280 Controller,\r
2281 &gEfiPciRootBridgeIoProtocolGuid,\r
2282 (VOID **) &PciRootBridgeIo,\r
2283 gPciBusDriverBinding.DriverBindingHandle,\r
2284 Controller,\r
2285 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2286 );\r
2287 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2288 return Status;\r
2289 }\r
2290\r
2291 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
2292\r
2293 if (EFI_ERROR (Status)) {\r
2294 return Status;\r
2295 }\r
2296\r
2297 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
2298\r
2299 //\r
2300 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2301 //\r
2302 RootBridgeDev = CreateRootBridge (Controller);\r
2303\r
2304 if (RootBridgeDev == NULL) {\r
2305 Descriptors++;\r
2306 continue;\r
2307 }\r
2308\r
2309 //\r
2310 // Record the root bridgeio protocol\r
2311 //\r
2312 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2313\r
2314 Status = PciPciDeviceInfoCollector (\r
2315 RootBridgeDev,\r
2316 (UINT8) MinBus\r
2317 );\r
2318\r
2319 if (!EFI_ERROR (Status)) {\r
2320\r
2321 //\r
2322 // Remove those PCI devices which are rejected when full enumeration\r
2323 //\r
2324 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2325\r
2326 //\r
2327 // Process option rom light\r
2328 //\r
2329 ProcessOptionRomLight (RootBridgeDev);\r
2330\r
2331 //\r
2332 // Determine attributes for all devices under this root bridge\r
2333 //\r
2334 DetermineDeviceAttribute (RootBridgeDev);\r
2335\r
2336 //\r
2337 // If successfully, insert the node into device pool\r
2338 //\r
2339 InsertRootBridge (RootBridgeDev);\r
2340 } else {\r
2341\r
2342 //\r
2343 // If unsuccessly, destroy the entire node\r
2344 //\r
2345 DestroyRootBridge (RootBridgeDev);\r
2346 }\r
2347\r
2348 Descriptors++;\r
2349 }\r
2350\r
2351 return EFI_SUCCESS;\r
2352}\r
2353\r
2354/**\r
2355 Get bus range from PCI resource descriptor list.\r
2356\r
2357 @param Descriptors A pointer to the address space descriptor.\r
2358 @param MinBus The min bus returned.\r
2359 @param MaxBus The max bus returned.\r
2360 @param BusRange The bus range returned.\r
2361\r
2362 @retval EFI_SUCCESS Successfully got bus range.\r
2363 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2364\r
2365**/\r
2366EFI_STATUS\r
2367PciGetBusRange (\r
2368 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2369 OUT UINT16 *MinBus,\r
2370 OUT UINT16 *MaxBus,\r
2371 OUT UINT16 *BusRange\r
2372 )\r
2373{\r
2374 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2375 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2376 if (MinBus != NULL) {\r
2377 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
2378 }\r
2379\r
2380 if (MaxBus != NULL) {\r
2381 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
2382 }\r
2383\r
2384 if (BusRange != NULL) {\r
2385 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
2386 }\r
2387\r
2388 return EFI_SUCCESS;\r
2389 }\r
2390\r
2391 (*Descriptors)++;\r
2392 }\r
2393\r
2394 return EFI_NOT_FOUND;\r
2395}\r
2396\r
2397/**\r
2398 This routine can be used to start the root bridge.\r
2399\r
2400 @param RootBridgeDev Pci device instance.\r
2401\r
2402 @retval EFI_SUCCESS This device started.\r
2403 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2404\r
2405**/\r
2406EFI_STATUS\r
2407StartManagingRootBridge (\r
2408 IN PCI_IO_DEVICE *RootBridgeDev\r
2409 )\r
2410{\r
2411 EFI_HANDLE RootBridgeHandle;\r
2412 EFI_STATUS Status;\r
2413 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2414\r
2415 //\r
2416 // Get the root bridge handle\r
2417 //\r
2418 RootBridgeHandle = RootBridgeDev->Handle;\r
2419 PciRootBridgeIo = NULL;\r
2420\r
2421 //\r
2422 // Get the pci root bridge io protocol\r
2423 //\r
2424 Status = gBS->OpenProtocol (\r
2425 RootBridgeHandle,\r
2426 &gEfiPciRootBridgeIoProtocolGuid,\r
2427 (VOID **) &PciRootBridgeIo,\r
2428 gPciBusDriverBinding.DriverBindingHandle,\r
2429 RootBridgeHandle,\r
2430 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2431 );\r
2432\r
2433 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2434 return Status;\r
2435 }\r
2436\r
2437 //\r
2438 // Store the PciRootBridgeIo protocol into root bridge private data\r
2439 //\r
2440 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2441\r
2442 return EFI_SUCCESS;\r
2443\r
2444}\r
2445\r
2446/**\r
2447 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2448\r
2449 @param PciIoDevice Pci device instance.\r
2450\r
2451 @retval TRUE This device should be rejected.\r
2452 @retval FALSE This device shouldn't be rejected.\r
2453\r
2454**/\r
2455BOOLEAN\r
2456IsPciDeviceRejected (\r
2457 IN PCI_IO_DEVICE *PciIoDevice\r
2458 )\r
2459{\r
2460 EFI_STATUS Status;\r
2461 UINT32 TestValue;\r
2462 UINT32 OldValue;\r
2463 UINT32 Mask;\r
2464 UINT8 BarOffset;\r
2465\r
2466 //\r
2467 // PPB should be skip!\r
2468 //\r
2469 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2470 return FALSE;\r
2471 }\r
2472\r
2473 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2474 //\r
2475 // Only test base registers for P2C\r
2476 //\r
2477 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
2478\r
2479 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2480 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2481 if (EFI_ERROR (Status)) {\r
2482 continue;\r
2483 }\r
2484\r
2485 TestValue = TestValue & Mask;\r
2486 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2487 //\r
2488 // The bar isn't programed, so it should be rejected\r
2489 //\r
2490 return TRUE;\r
2491 }\r
2492 }\r
2493\r
2494 return FALSE;\r
2495 }\r
2496\r
2497 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2498 //\r
2499 // Test PCI devices\r
2500 //\r
2501 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2502 if (EFI_ERROR (Status)) {\r
2503 continue;\r
2504 }\r
2505\r
2506 if ((TestValue & 0x01) != 0) {\r
2507\r
2508 //\r
2509 // IO Bar\r
2510 //\r
2511 Mask = 0xFFFFFFFC;\r
2512 TestValue = TestValue & Mask;\r
2513 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2514 return TRUE;\r
2515 }\r
2516\r
2517 } else {\r
2518\r
2519 //\r
2520 // Mem Bar\r
2521 //\r
2522 Mask = 0xFFFFFFF0;\r
2523 TestValue = TestValue & Mask;\r
2524\r
2525 if ((TestValue & 0x07) == 0x04) {\r
2526\r
2527 //\r
2528 // Mem64 or PMem64\r
2529 //\r
2530 BarOffset += sizeof (UINT32);\r
2531 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2532\r
2533 //\r
2534 // Test its high 32-Bit BAR\r
2535 //\r
2536 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2537 if (TestValue == OldValue) {\r
2538 return TRUE;\r
2539 }\r
2540 }\r
2541\r
2542 } else {\r
2543\r
2544 //\r
2545 // Mem32 or PMem32\r
2546 //\r
2547 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2548 return TRUE;\r
2549 }\r
2550 }\r
2551 }\r
2552 }\r
2553\r
2554 return FALSE;\r
2555}\r
2556\r
2557/**\r
2558 Reset all bus number from specific bridge.\r
2559\r
2560 @param Bridge Parent specific bridge.\r
2561 @param StartBusNumber Start bus number.\r
2562\r
2563**/\r
2564VOID\r
2565ResetAllPpbBusNumber (\r
2566 IN PCI_IO_DEVICE *Bridge,\r
2567 IN UINT8 StartBusNumber\r
2568 )\r
2569{\r
2570 EFI_STATUS Status;\r
2571 PCI_TYPE00 Pci;\r
2572 UINT8 Device;\r
2573 UINT32 Register;\r
2574 UINT8 Func;\r
2575 UINT64 Address;\r
2576 UINT8 SecondaryBus;\r
2577 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2578\r
2579 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2580\r
2581 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2582 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2583\r
2584 //\r
2585 // Check to see whether a pci device is present\r
2586 //\r
2587 Status = PciDevicePresent (\r
2588 PciRootBridgeIo,\r
2589 &Pci,\r
2590 StartBusNumber,\r
2591 Device,\r
2592 Func\r
2593 );\r
2594\r
2595 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
2596\r
2597 Register = 0;\r
2598 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2599 Status = PciRootBridgeIo->Pci.Read (\r
2600 PciRootBridgeIo,\r
2601 EfiPciWidthUint32,\r
2602 Address,\r
2603 1,\r
2604 &Register\r
2605 );\r
2606 SecondaryBus = (UINT8)(Register >> 8);\r
2607\r
2608 if (SecondaryBus != 0) {\r
2609 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2610 }\r
2611\r
2612 //\r
2613 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2614 //\r
2615 Register &= 0xFF000000;\r
2616 Status = PciRootBridgeIo->Pci.Write (\r
2617 PciRootBridgeIo,\r
2618 EfiPciWidthUint32,\r
2619 Address,\r
2620 1,\r
2621 &Register\r
2622 );\r
2623 }\r
2624\r
2625 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2626 //\r
2627 // Skip sub functions, this is not a multi function device\r
2628 //\r
2629 Func = PCI_MAX_FUNC;\r
2630 }\r
2631 }\r
2632 }\r
2633}\r
2634\r