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