]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
Update all the code to consume the ConvertDevicePathToText, ConvertDevicePathNodeToTe...
[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
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
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
980050bc
RN
983 Attributes |= (mReserveIsaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO : \\r
984 (UINT64) 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
980050bc
RN
1010 Attributes |= (mReserveVgaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO : \\r
1011 (UINT64) 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
9060e3ec 1476 EFI_STATUS Status;\r
1477\r
1478 //\r
1479 // Ensure it is called properly\r
1480 //\r
1481 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
1482 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
1483 return 0;\r
1484 }\r
1485\r
1486 OriginalValue = 0;\r
1487 Value = 0;\r
1488\r
1489 Status = VfBarExisted (\r
1490 PciIoDevice,\r
1491 Offset,\r
1492 &Value,\r
1493 &OriginalValue\r
1494 );\r
1495\r
1496 if (EFI_ERROR (Status)) {\r
1497 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1498 PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
1499 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1500\r
1501 //\r
1502 // Scan all the BARs anyway\r
1503 //\r
d4048391 1504 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
9060e3ec 1505 return Offset + 4;\r
1506 }\r
1507\r
d4048391 1508 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
aa75dfec 1509 if ((Value & 0x01) != 0) {\r
9060e3ec 1510 //\r
1511 // Device I/Os. Impossible\r
1512 //\r
1513 ASSERT (FALSE);\r
1514 return Offset + 4;\r
1515\r
1516 } else {\r
1517\r
1518 Mask = 0xfffffff0;\r
1519\r
1520 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1521\r
1522 switch (Value & 0x07) {\r
1523\r
1524 //\r
1525 //memory space; anywhere in 32 bit address space\r
1526 //\r
1527 case 0x00:\r
aa75dfec 1528 if ((Value & 0x08) != 0) {\r
9060e3ec 1529 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
1530 } else {\r
1531 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
1532 }\r
1533\r
1534 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1535 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1536\r
1537 //\r
1538 // Adjust Length\r
1539 //\r
1540 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1541 //\r
1542 // Adjust Alignment\r
1543 //\r
1544 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1545 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1546 }\r
1547\r
1548 break;\r
1549\r
1550 //\r
1551 // memory space; anywhere in 64 bit address space\r
1552 //\r
1553 case 0x04:\r
aa75dfec 1554 if ((Value & 0x08) != 0) {\r
9060e3ec 1555 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
1556 } else {\r
1557 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
1558 }\r
1559\r
1560 //\r
1561 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1562 // is regarded as an extension for the first bar. As a result\r
1563 // the sizing will be conducted on combined 64 bit value\r
1564 // Here just store the masked first 32bit value for future size\r
1565 // calculation\r
1566 //\r
1567 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
1568 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1569\r
1570 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1571 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1572 }\r
1573\r
1574 //\r
1575 // Increment the offset to point to next DWORD\r
1576 //\r
1577 Offset += 4;\r
1578\r
1579 Status = VfBarExisted (\r
1580 PciIoDevice,\r
1581 Offset,\r
1582 &Value,\r
1583 &OriginalValue\r
1584 );\r
1585\r
1586 if (EFI_ERROR (Status)) {\r
1587 return Offset + 4;\r
1588 }\r
1589\r
1590 //\r
1591 // Fix the length to support some spefic 64 bit BAR\r
1592 //\r
c0394e04 1593 Value |= ((UINT32) -1 << HighBitSet32 (Value));\r
9060e3ec 1594\r
1595 //\r
1596 // Calculate the size of 64bit bar\r
1597 //\r
1598 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1599\r
1600 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1601 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
1602 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1603\r
1604 //\r
1605 // Adjust Length\r
1606 //\r
1607 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1608 //\r
1609 // Adjust Alignment\r
1610 //\r
1611 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1612 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1613 }\r
1614\r
1615 break;\r
1616\r
1617 //\r
1618 // reserved\r
1619 //\r
1620 default:\r
1621 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1622 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1623 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1624\r
1625 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1626 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1627 }\r
1628\r
1629 break;\r
1630 }\r
1631 }\r
1632 \r
1633 //\r
1634 // Check the length again so as to keep compatible with some special bars\r
1635 //\r
1636 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
1637 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1638 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1639 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1640 }\r
1641 \r
1642 //\r
1643 // Increment number of bar\r
1644 //\r
1645 return Offset + 4;\r
1646}\r
1647\r
1648/**\r
1649 Parse PCI bar information and fill them into PCI device instance.\r
1650\r
1651 @param PciIoDevice Pci device instance.\r
1652 @param Offset Bar offset.\r
1653 @param BarIndex Bar index.\r
1654\r
1655 @return Next bar offset.\r
1656\r
1657**/\r
1658UINTN\r
1659PciParseBar (\r
1660 IN PCI_IO_DEVICE *PciIoDevice,\r
1661 IN UINTN Offset,\r
1662 IN UINTN BarIndex\r
1663 )\r
1664{\r
1665 UINT32 Value;\r
1666 UINT32 OriginalValue;\r
1667 UINT32 Mask;\r
9060e3ec 1668 EFI_STATUS Status;\r
1669\r
1670 OriginalValue = 0;\r
1671 Value = 0;\r
1672\r
1673 Status = BarExisted (\r
1674 PciIoDevice,\r
1675 Offset,\r
1676 &Value,\r
1677 &OriginalValue\r
1678 );\r
1679\r
1680 if (EFI_ERROR (Status)) {\r
1681 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1682 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1683 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1684\r
1685 //\r
1686 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1687 //\r
1688 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1689 return Offset + 4;\r
1690 }\r
1691\r
1692 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1693 if ((Value & 0x01) != 0) {\r
1694 //\r
1695 // Device I/Os\r
1696 //\r
1697 Mask = 0xfffffffc;\r
1698\r
1699 if ((Value & 0xFFFF0000) != 0) {\r
1700 //\r
1701 // It is a IO32 bar\r
1702 //\r
1703 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1704 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1705 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1706\r
1707 } else {\r
1708 //\r
1709 // It is a IO16 bar\r
1710 //\r
1711 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1712 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1713 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1714\r
1715 }\r
1716 //\r
1717 // Workaround. Some platforms inplement IO bar with 0 length\r
1718 // Need to treat it as no-bar\r
1719 //\r
1720 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1721 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1722 }\r
1723\r
1724 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
1725 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1726\r
1727 } else {\r
1728\r
1729 Mask = 0xfffffff0;\r
1730\r
1731 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1732\r
1733 switch (Value & 0x07) {\r
1734\r
1735 //\r
1736 //memory space; anywhere in 32 bit address space\r
1737 //\r
1738 case 0x00:\r
1739 if ((Value & 0x08) != 0) {\r
1740 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1741 } else {\r
1742 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1743 }\r
1744\r
1745 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1746 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1747 //\r
1748 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1749 //\r
1750 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1751 } else {\r
1752 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1753 }\r
1754 break;\r
1755\r
1756 //\r
1757 // memory space; anywhere in 64 bit address space\r
1758 //\r
1759 case 0x04:\r
1760 if ((Value & 0x08) != 0) {\r
1761 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1762 } else {\r
1763 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1764 }\r
1765\r
1766 //\r
1767 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1768 // is regarded as an extension for the first bar. As a result\r
1769 // the sizing will be conducted on combined 64 bit value\r
1770 // Here just store the masked first 32bit value for future size\r
1771 // calculation\r
1772 //\r
1773 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1774 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1775\r
1776 //\r
1777 // Increment the offset to point to next DWORD\r
1778 //\r
1779 Offset += 4;\r
1780\r
1781 Status = BarExisted (\r
1782 PciIoDevice,\r
1783 Offset,\r
1784 &Value,\r
1785 &OriginalValue\r
1786 );\r
1787\r
1788 if (EFI_ERROR (Status)) {\r
1789 //\r
1790 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
1791 //\r
1792 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1793 //\r
1794 // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
1795 //\r
1796 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1797 }\r
1798 return Offset + 4;\r
1799 }\r
1800\r
1801 //\r
1802 // Fix the length to support some spefic 64 bit BAR\r
1803 //\r
c0394e04 1804 Value |= ((UINT32)(-1) << HighBitSet32 (Value));\r
9060e3ec 1805\r
1806 //\r
1807 // Calculate the size of 64bit bar\r
1808 //\r
1809 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1810\r
1811 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1812 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1813 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1814 //\r
1815 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1816 //\r
1817 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1818 } else {\r
1819 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1820 }\r
1821\r
1822 break;\r
1823\r
1824 //\r
1825 // reserved\r
1826 //\r
1827 default:\r
1828 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1829 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1830 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1831 //\r
1832 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1833 //\r
1834 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1835 } else {\r
1836 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1837 }\r
1838 break;\r
1839 }\r
1840 }\r
1841\r
1842 //\r
1843 // Check the length again so as to keep compatible with some special bars\r
1844 //\r
1845 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1846 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1847 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1848 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1849 }\r
1850\r
1851 //\r
1852 // Increment number of bar\r
1853 //\r
1854 return Offset + 4;\r
1855}\r
1856\r
1857/**\r
1858 This routine is used to initialize the bar of a PCI device.\r
1859\r
1860 @param PciIoDevice Pci device instance.\r
1861\r
1862 @note It can be called typically when a device is going to be rejected.\r
1863\r
1864**/\r
1865VOID\r
1866InitializePciDevice (\r
1867 IN PCI_IO_DEVICE *PciIoDevice\r
1868 )\r
1869{\r
1870 EFI_PCI_IO_PROTOCOL *PciIo;\r
1871 UINT8 Offset;\r
1872\r
1873 PciIo = &(PciIoDevice->PciIo);\r
1874\r
1875 //\r
1876 // Put all the resource apertures\r
1877 // Resource base is set to all ones so as to indicate its resource\r
1878 // has not been alloacted\r
1879 //\r
1880 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1881 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1882 }\r
1883}\r
1884\r
1885/**\r
1886 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1887\r
1888 @param PciIoDevice PCI-PCI bridge device instance.\r
1889\r
1890**/\r
1891VOID\r
1892InitializePpb (\r
1893 IN PCI_IO_DEVICE *PciIoDevice\r
1894 )\r
1895{\r
1896 EFI_PCI_IO_PROTOCOL *PciIo;\r
1897\r
1898 PciIo = &(PciIoDevice->PciIo);\r
1899\r
1900 //\r
1901 // Put all the resource apertures including IO16\r
1902 // Io32, pMem32, pMem64 to quiescent state\r
1903 // Resource base all ones, Resource limit all zeros\r
1904 //\r
1905 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1906 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
1907\r
1908 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1909 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
1910\r
1911 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1912 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
1913\r
1914 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1915 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
1916\r
1917 //\r
1918 // Don't support use io32 as for now\r
1919 //\r
1920 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1921 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
1922\r
1923 //\r
1924 // Force Interrupt line to zero for cards that come up randomly\r
1925 //\r
1926 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1927}\r
1928\r
1929/**\r
1930 This routine is used to initialize the bar of a PCI Card Bridge device.\r
1931\r
1932 @param PciIoDevice PCI Card bridge device.\r
1933\r
1934**/\r
1935VOID\r
1936InitializeP2C (\r
1937 IN PCI_IO_DEVICE *PciIoDevice\r
1938 )\r
1939{\r
1940 EFI_PCI_IO_PROTOCOL *PciIo;\r
1941\r
1942 PciIo = &(PciIoDevice->PciIo);\r
1943\r
1944 //\r
1945 // Put all the resource apertures including IO16\r
1946 // Io32, pMem32, pMem64 to quiescent state(\r
1947 // Resource base all ones, Resource limit all zeros\r
1948 //\r
1949 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
1950 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
1951\r
1952 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
1953 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
1954\r
1955 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
1956 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
1957\r
1958 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
1959 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
1960\r
1961 //\r
1962 // Force Interrupt line to zero for cards that come up randomly\r
1963 //\r
1964 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1965}\r
1966\r
1967/**\r
1968 Create and initiliaze general PCI I/O device instance for\r
1969 PCI device/bridge device/hotplug bridge device.\r
1970\r
1971 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1972 @param Pci Input Pci information block.\r
1973 @param Bus Device Bus NO.\r
1974 @param Device Device device NO.\r
1975 @param Func Device func NO.\r
1976\r
1977 @return Instance of PCI device. NULL means no instance created.\r
1978\r
1979**/\r
1980PCI_IO_DEVICE *\r
1981CreatePciIoDevice (\r
d4048391 1982 IN PCI_IO_DEVICE *Bridge,\r
9060e3ec 1983 IN PCI_TYPE00 *Pci,\r
1984 IN UINT8 Bus,\r
1985 IN UINT8 Device,\r
1986 IN UINT8 Func\r
1987 )\r
1988{\r
d4048391 1989 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 1990 EFI_PCI_IO_PROTOCOL *PciIo;\r
1991 EFI_STATUS Status;\r
1992\r
1993 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
1994 if (PciIoDevice == NULL) {\r
1995 return NULL;\r
1996 }\r
1997\r
1998 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
1999 PciIoDevice->Handle = NULL;\r
d4048391 2000 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
9060e3ec 2001 PciIoDevice->DevicePath = NULL;\r
2002 PciIoDevice->BusNumber = Bus;\r
2003 PciIoDevice->DeviceNumber = Device;\r
2004 PciIoDevice->FunctionNumber = Func;\r
2005 PciIoDevice->Decodes = 0;\r
2006\r
2007 if (gFullEnumeration) {\r
2008 PciIoDevice->Allocated = FALSE;\r
2009 } else {\r
2010 PciIoDevice->Allocated = TRUE;\r
2011 }\r
2012\r
2013 PciIoDevice->Registered = FALSE;\r
2014 PciIoDevice->Attributes = 0;\r
2015 PciIoDevice->Supports = 0;\r
2016 PciIoDevice->BusOverride = FALSE;\r
2017 PciIoDevice->AllOpRomProcessed = FALSE;\r
2018\r
2019 PciIoDevice->IsPciExp = FALSE;\r
2020\r
2021 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
2022\r
2023 //\r
2024 // Initialize the PCI I/O instance structure\r
2025 //\r
2026 InitializePciIoInstance (PciIoDevice);\r
2027 InitializePciDriverOverrideInstance (PciIoDevice);\r
2028 InitializePciLoadFile2 (PciIoDevice);\r
2029 PciIo = &PciIoDevice->PciIo;\r
2030\r
2031 //\r
2032 // Detect if PCI Express Device\r
2033 //\r
2034 PciIoDevice->PciExpressCapabilityOffset = 0;\r
2035 Status = LocateCapabilityRegBlock (\r
2036 PciIoDevice,\r
2037 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
2038 &PciIoDevice->PciExpressCapabilityOffset,\r
2039 NULL\r
2040 );\r
2041 if (!EFI_ERROR (Status)) {\r
2042 PciIoDevice->IsPciExp = TRUE;\r
2043 }\r
2044\r
d4048391 2045 if (PcdGetBool (PcdAriSupport)) {\r
2046 //\r
2047 // Check if the device is an ARI device.\r
2048 //\r
2049 Status = LocatePciExpressCapabilityRegBlock (\r
2050 PciIoDevice,\r
2051 EFI_PCIE_CAPABILITY_ID_ARI,\r
2052 &PciIoDevice->AriCapabilityOffset,\r
2053 NULL\r
2054 );\r
2055 if (!EFI_ERROR (Status)) {\r
2056 //\r
2057 // We need to enable ARI feature before calculate BusReservation,\r
2058 // because FirstVFOffset and VFStride may change after that.\r
2059 //\r
2060 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
2061 UINT32 Data32;\r
9060e3ec 2062\r
d4048391 2063 //\r
2064 // Check if its parent supports ARI forwarding.\r
2065 //\r
2066 ParentPciIo = &Bridge->PciIo;\r
2067 ParentPciIo->Pci.Read (\r
2068 ParentPciIo, \r
2069 EfiPciIoWidthUint32,\r
2070 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
2071 1,\r
2072 &Data32\r
2073 );\r
2074 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
2075 //\r
2076 // ARI forward support in bridge, so enable it.\r
2077 //\r
2078 ParentPciIo->Pci.Read (\r
2079 ParentPciIo,\r
2080 EfiPciIoWidthUint32,\r
2081 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2082 1,\r
2083 &Data32\r
2084 );\r
2085 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2086 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2087 ParentPciIo->Pci.Write (\r
2088 ParentPciIo,\r
2089 EfiPciIoWidthUint32,\r
2090 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2091 1,\r
2092 &Data32\r
2093 );\r
2094 DEBUG ((\r
2095 EFI_D_INFO,\r
8db6a82c
RN
2096 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",\r
2097 Bridge->BusNumber,\r
2098 Bridge->DeviceNumber,\r
2099 Bridge->FunctionNumber\r
d4048391 2100 ));\r
2101 }\r
2102 }\r
9060e3ec 2103\r
8db6a82c 2104 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));\r
d4048391 2105 }\r
9060e3ec 2106 }\r
2107\r
2108 //\r
d4048391 2109 // Initialization for SR-IOV\r
9060e3ec 2110 //\r
9060e3ec 2111\r
d4048391 2112 if (PcdGetBool (PcdSrIovSupport)) {\r
2113 Status = LocatePciExpressCapabilityRegBlock (\r
2114 PciIoDevice,\r
2115 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2116 &PciIoDevice->SrIovCapabilityOffset,\r
2117 NULL\r
2118 );\r
2119 if (!EFI_ERROR (Status)) {\r
8db6a82c 2120 UINT32 SupportedPageSize;\r
d4048391 2121 UINT16 VFStride;\r
2122 UINT16 FirstVFOffset;\r
2123 UINT16 Data16;\r
2124 UINT32 PFRid;\r
2125 UINT32 LastVF;\r
2126\r
2127 //\r
2128 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2129 //\r
2130 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {\r
2131 PciIo->Pci.Read (\r
2132 PciIo,\r
2133 EfiPciIoWidthUint16,\r
2134 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2135 1,\r
2136 &Data16\r
2137 );\r
2138 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2139 PciIo->Pci.Write (\r
2140 PciIo,\r
2141 EfiPciIoWidthUint16,\r
2142 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2143 1,\r
2144 &Data16\r
2145 );\r
2146 }\r
9060e3ec 2147\r
d4048391 2148 //\r
2149 // Calculate SystemPageSize\r
2150 //\r
9060e3ec 2151\r
d4048391 2152 PciIo->Pci.Read (\r
2153 PciIo,\r
2154 EfiPciIoWidthUint32,\r
2155 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2156 1,\r
8db6a82c 2157 &SupportedPageSize\r
d4048391 2158 );\r
8db6a82c 2159 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);\r
d4048391 2160 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2161\r
2162 PciIo->Pci.Write (\r
2163 PciIo,\r
2164 EfiPciIoWidthUint32,\r
2165 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2166 1,\r
2167 &PciIoDevice->SystemPageSize\r
2168 );\r
d4048391 2169 //\r
2170 // Adjust SystemPageSize for Alignment usage later\r
2171 //\r
2172 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2173\r
d4048391 2174 //\r
2175 // Calculate BusReservation for PCI IOV\r
2176 //\r
9060e3ec 2177\r
d4048391 2178 //\r
2179 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2180 //\r
2181 PciIo->Pci.Read (\r
2182 PciIo,\r
2183 EfiPciIoWidthUint16,\r
2184 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2185 1,\r
2186 &FirstVFOffset\r
2187 );\r
d4048391 2188 PciIo->Pci.Read (\r
2189 PciIo,\r
2190 EfiPciIoWidthUint16,\r
2191 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2192 1,\r
2193 &PciIoDevice->InitialVFs\r
2194 );\r
d4048391 2195 PciIo->Pci.Read (\r
2196 PciIo,\r
2197 EfiPciIoWidthUint16,\r
2198 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2199 1,\r
2200 &VFStride\r
2201 );\r
d4048391 2202 //\r
2203 // Calculate LastVF\r
2204 //\r
2205 PFRid = EFI_PCI_RID(Bus, Device, Func);\r
2206 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2207\r
d4048391 2208 //\r
2209 // Calculate ReservedBusNum for this PF\r
2210 //\r
2211 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
8db6a82c 2212\r
d4048391 2213 DEBUG ((\r
2214 EFI_D_INFO,\r
8db6a82c
RN
2215 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",\r
2216 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset\r
d4048391 2217 ));\r
d4048391 2218 DEBUG ((\r
2219 EFI_D_INFO,\r
8db6a82c
RN
2220 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",\r
2221 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset\r
d4048391 2222 ));\r
2223 }\r
9060e3ec 2224 }\r
2225\r
d4048391 2226 if (PcdGetBool (PcdMrIovSupport)) {\r
2227 Status = LocatePciExpressCapabilityRegBlock (\r
2228 PciIoDevice,\r
2229 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2230 &PciIoDevice->MrIovCapabilityOffset,\r
2231 NULL\r
2232 );\r
2233 if (!EFI_ERROR (Status)) {\r
8db6a82c 2234 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));\r
d4048391 2235 }\r
2236 }\r
9060e3ec 2237\r
2238 //\r
2239 // Initialize the reserved resource list\r
2240 //\r
2241 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2242\r
2243 //\r
2244 // Initialize the driver list\r
2245 //\r
2246 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2247\r
2248 //\r
2249 // Initialize the child list\r
2250 //\r
2251 InitializeListHead (&PciIoDevice->ChildList);\r
2252\r
2253 return PciIoDevice;\r
2254}\r
2255\r
2256/**\r
2257 This routine is used to enumerate entire pci bus system\r
2258 in a given platform.\r
2259\r
2260 It is only called on the second start on the same Root Bridge.\r
2261\r
2262 @param Controller Parent bridge handler.\r
2263\r
2264 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2265 @retval other Some error occurred when enumerating the pci bus system.\r
2266\r
2267**/\r
2268EFI_STATUS\r
2269PciEnumeratorLight (\r
2270 IN EFI_HANDLE Controller\r
2271 )\r
2272{\r
2273\r
2274 EFI_STATUS Status;\r
2275 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2276 PCI_IO_DEVICE *RootBridgeDev;\r
2277 UINT16 MinBus;\r
2278 UINT16 MaxBus;\r
2279 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
2280\r
2281 MinBus = 0;\r
2282 MaxBus = PCI_MAX_BUS;\r
2283 Descriptors = NULL;\r
2284\r
2285 //\r
2286 // If this root bridge has been already enumerated, then return successfully\r
2287 //\r
2288 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2289 return EFI_SUCCESS;\r
2290 }\r
2291\r
2292 //\r
2293 // Open pci root bridge io protocol\r
2294 //\r
2295 Status = gBS->OpenProtocol (\r
2296 Controller,\r
2297 &gEfiPciRootBridgeIoProtocolGuid,\r
2298 (VOID **) &PciRootBridgeIo,\r
2299 gPciBusDriverBinding.DriverBindingHandle,\r
2300 Controller,\r
2301 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2302 );\r
2303 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2304 return Status;\r
2305 }\r
2306\r
2307 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
2308\r
2309 if (EFI_ERROR (Status)) {\r
2310 return Status;\r
2311 }\r
2312\r
2313 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
2314\r
2315 //\r
2316 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2317 //\r
2318 RootBridgeDev = CreateRootBridge (Controller);\r
2319\r
2320 if (RootBridgeDev == NULL) {\r
2321 Descriptors++;\r
2322 continue;\r
2323 }\r
2324\r
2325 //\r
2326 // Record the root bridgeio protocol\r
2327 //\r
2328 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2329\r
2330 Status = PciPciDeviceInfoCollector (\r
2331 RootBridgeDev,\r
2332 (UINT8) MinBus\r
2333 );\r
2334\r
2335 if (!EFI_ERROR (Status)) {\r
2336\r
2337 //\r
2338 // Remove those PCI devices which are rejected when full enumeration\r
2339 //\r
2340 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2341\r
2342 //\r
2343 // Process option rom light\r
2344 //\r
2345 ProcessOptionRomLight (RootBridgeDev);\r
2346\r
2347 //\r
2348 // Determine attributes for all devices under this root bridge\r
2349 //\r
2350 DetermineDeviceAttribute (RootBridgeDev);\r
2351\r
2352 //\r
2353 // If successfully, insert the node into device pool\r
2354 //\r
2355 InsertRootBridge (RootBridgeDev);\r
2356 } else {\r
2357\r
2358 //\r
2359 // If unsuccessly, destroy the entire node\r
2360 //\r
2361 DestroyRootBridge (RootBridgeDev);\r
2362 }\r
2363\r
2364 Descriptors++;\r
2365 }\r
2366\r
2367 return EFI_SUCCESS;\r
2368}\r
2369\r
2370/**\r
2371 Get bus range from PCI resource descriptor list.\r
2372\r
2373 @param Descriptors A pointer to the address space descriptor.\r
2374 @param MinBus The min bus returned.\r
2375 @param MaxBus The max bus returned.\r
2376 @param BusRange The bus range returned.\r
2377\r
2378 @retval EFI_SUCCESS Successfully got bus range.\r
2379 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2380\r
2381**/\r
2382EFI_STATUS\r
2383PciGetBusRange (\r
2384 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2385 OUT UINT16 *MinBus,\r
2386 OUT UINT16 *MaxBus,\r
2387 OUT UINT16 *BusRange\r
2388 )\r
2389{\r
2390 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2391 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2392 if (MinBus != NULL) {\r
2393 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
2394 }\r
2395\r
2396 if (MaxBus != NULL) {\r
2397 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
2398 }\r
2399\r
2400 if (BusRange != NULL) {\r
2401 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
2402 }\r
2403\r
2404 return EFI_SUCCESS;\r
2405 }\r
2406\r
2407 (*Descriptors)++;\r
2408 }\r
2409\r
2410 return EFI_NOT_FOUND;\r
2411}\r
2412\r
2413/**\r
2414 This routine can be used to start the root bridge.\r
2415\r
2416 @param RootBridgeDev Pci device instance.\r
2417\r
2418 @retval EFI_SUCCESS This device started.\r
2419 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2420\r
2421**/\r
2422EFI_STATUS\r
2423StartManagingRootBridge (\r
2424 IN PCI_IO_DEVICE *RootBridgeDev\r
2425 )\r
2426{\r
2427 EFI_HANDLE RootBridgeHandle;\r
2428 EFI_STATUS Status;\r
2429 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2430\r
2431 //\r
2432 // Get the root bridge handle\r
2433 //\r
2434 RootBridgeHandle = RootBridgeDev->Handle;\r
2435 PciRootBridgeIo = NULL;\r
2436\r
2437 //\r
2438 // Get the pci root bridge io protocol\r
2439 //\r
2440 Status = gBS->OpenProtocol (\r
2441 RootBridgeHandle,\r
2442 &gEfiPciRootBridgeIoProtocolGuid,\r
2443 (VOID **) &PciRootBridgeIo,\r
2444 gPciBusDriverBinding.DriverBindingHandle,\r
2445 RootBridgeHandle,\r
2446 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2447 );\r
2448\r
2449 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2450 return Status;\r
2451 }\r
2452\r
2453 //\r
2454 // Store the PciRootBridgeIo protocol into root bridge private data\r
2455 //\r
2456 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2457\r
2458 return EFI_SUCCESS;\r
2459\r
2460}\r
2461\r
2462/**\r
2463 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2464\r
2465 @param PciIoDevice Pci device instance.\r
2466\r
2467 @retval TRUE This device should be rejected.\r
2468 @retval FALSE This device shouldn't be rejected.\r
2469\r
2470**/\r
2471BOOLEAN\r
2472IsPciDeviceRejected (\r
2473 IN PCI_IO_DEVICE *PciIoDevice\r
2474 )\r
2475{\r
2476 EFI_STATUS Status;\r
2477 UINT32 TestValue;\r
2478 UINT32 OldValue;\r
2479 UINT32 Mask;\r
2480 UINT8 BarOffset;\r
2481\r
2482 //\r
2483 // PPB should be skip!\r
2484 //\r
2485 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2486 return FALSE;\r
2487 }\r
2488\r
2489 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2490 //\r
2491 // Only test base registers for P2C\r
2492 //\r
2493 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
2494\r
2495 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2496 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2497 if (EFI_ERROR (Status)) {\r
2498 continue;\r
2499 }\r
2500\r
2501 TestValue = TestValue & Mask;\r
2502 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2503 //\r
2504 // The bar isn't programed, so it should be rejected\r
2505 //\r
2506 return TRUE;\r
2507 }\r
2508 }\r
2509\r
2510 return FALSE;\r
2511 }\r
2512\r
2513 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2514 //\r
2515 // Test PCI devices\r
2516 //\r
2517 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2518 if (EFI_ERROR (Status)) {\r
2519 continue;\r
2520 }\r
2521\r
2522 if ((TestValue & 0x01) != 0) {\r
2523\r
2524 //\r
2525 // IO Bar\r
2526 //\r
2527 Mask = 0xFFFFFFFC;\r
2528 TestValue = TestValue & Mask;\r
2529 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2530 return TRUE;\r
2531 }\r
2532\r
2533 } else {\r
2534\r
2535 //\r
2536 // Mem Bar\r
2537 //\r
2538 Mask = 0xFFFFFFF0;\r
2539 TestValue = TestValue & Mask;\r
2540\r
2541 if ((TestValue & 0x07) == 0x04) {\r
2542\r
2543 //\r
2544 // Mem64 or PMem64\r
2545 //\r
2546 BarOffset += sizeof (UINT32);\r
2547 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2548\r
2549 //\r
2550 // Test its high 32-Bit BAR\r
2551 //\r
2552 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2553 if (TestValue == OldValue) {\r
2554 return TRUE;\r
2555 }\r
2556 }\r
2557\r
2558 } else {\r
2559\r
2560 //\r
2561 // Mem32 or PMem32\r
2562 //\r
2563 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2564 return TRUE;\r
2565 }\r
2566 }\r
2567 }\r
2568 }\r
2569\r
2570 return FALSE;\r
2571}\r
2572\r
2573/**\r
2574 Reset all bus number from specific bridge.\r
2575\r
2576 @param Bridge Parent specific bridge.\r
2577 @param StartBusNumber Start bus number.\r
2578\r
2579**/\r
2580VOID\r
2581ResetAllPpbBusNumber (\r
2582 IN PCI_IO_DEVICE *Bridge,\r
2583 IN UINT8 StartBusNumber\r
2584 )\r
2585{\r
2586 EFI_STATUS Status;\r
2587 PCI_TYPE00 Pci;\r
2588 UINT8 Device;\r
2589 UINT32 Register;\r
2590 UINT8 Func;\r
2591 UINT64 Address;\r
2592 UINT8 SecondaryBus;\r
2593 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2594\r
2595 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2596\r
2597 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2598 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2599\r
2600 //\r
2601 // Check to see whether a pci device is present\r
2602 //\r
2603 Status = PciDevicePresent (\r
2604 PciRootBridgeIo,\r
2605 &Pci,\r
2606 StartBusNumber,\r
2607 Device,\r
2608 Func\r
2609 );\r
2610\r
2611 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
2612\r
2613 Register = 0;\r
2614 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2615 Status = PciRootBridgeIo->Pci.Read (\r
2616 PciRootBridgeIo,\r
2617 EfiPciWidthUint32,\r
2618 Address,\r
2619 1,\r
2620 &Register\r
2621 );\r
2622 SecondaryBus = (UINT8)(Register >> 8);\r
2623\r
2624 if (SecondaryBus != 0) {\r
2625 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2626 }\r
2627\r
2628 //\r
2629 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2630 //\r
2631 Register &= 0xFF000000;\r
2632 Status = PciRootBridgeIo->Pci.Write (\r
2633 PciRootBridgeIo,\r
2634 EfiPciWidthUint32,\r
2635 Address,\r
2636 1,\r
2637 &Register\r
2638 );\r
2639 }\r
2640\r
2641 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2642 //\r
2643 // Skip sub functions, this is not a multi function device\r
2644 //\r
2645 Func = PCI_MAX_FUNC;\r
2646 }\r
2647 }\r
2648 }\r
2649}\r
2650\r