]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
Update FrameworkSpecConformance.txt after adding new datahub definitions for SMBIOS...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciDeviceSupport.c
CommitLineData
9060e3ec 1/** @file\r
2 Supporting functions implementaion for PCI devices management.\r
3\r
d4048391 4Copyright (c) 2006 - 2010, 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
17//\r
18// This device structure is serviced as a header.\r
19// Its next field points to the first root bridge device node.\r
20//\r
21LIST_ENTRY mPciDevicePool;\r
22\r
23/**\r
24 Initialize the PCI devices pool.\r
25\r
26**/\r
27VOID\r
28InitializePciDevicePool (\r
29 VOID\r
30 )\r
31{\r
32 InitializeListHead (&mPciDevicePool);\r
33}\r
34\r
35/**\r
36 Insert a root bridge into PCI device pool.\r
37\r
38 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
39\r
40**/\r
41VOID\r
42InsertRootBridge (\r
43 IN PCI_IO_DEVICE *RootBridge\r
44 )\r
45{\r
46 InsertTailList (&mPciDevicePool, &(RootBridge->Link));\r
47}\r
48\r
49/**\r
50 This function is used to insert a PCI device node under\r
51 a bridge.\r
52\r
53 @param Bridge The PCI bridge.\r
54 @param PciDeviceNode The PCI device needs inserting.\r
55\r
56**/\r
57VOID\r
58InsertPciDevice (\r
59 IN PCI_IO_DEVICE *Bridge,\r
60 IN PCI_IO_DEVICE *PciDeviceNode\r
61 )\r
62{\r
63 InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));\r
64 PciDeviceNode->Parent = Bridge;\r
65}\r
66\r
67/**\r
68 Destroy root bridge and remove it from deivce tree.\r
69\r
70 @param RootBridge The bridge want to be removed.\r
71\r
72**/\r
73VOID\r
74DestroyRootBridge (\r
75 IN PCI_IO_DEVICE *RootBridge\r
76 )\r
77{\r
78 DestroyPciDeviceTree (RootBridge);\r
79\r
80 FreePciDevice (RootBridge);\r
81}\r
82\r
83/**\r
84 Destroy a pci device node.\r
85\r
86 All direct or indirect allocated resource for this node will be freed.\r
87\r
88 @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried.\r
89\r
90**/\r
91VOID\r
92FreePciDevice (\r
93 IN PCI_IO_DEVICE *PciIoDevice\r
94 )\r
95{\r
96 ASSERT (PciIoDevice != NULL);\r
97 //\r
98 // Assume all children have been removed underneath this device\r
99 //\r
100 if (PciIoDevice->ResourcePaddingDescriptors != NULL) {\r
101 FreePool (PciIoDevice->ResourcePaddingDescriptors);\r
102 }\r
103\r
104 if (PciIoDevice->DevicePath != NULL) {\r
105 FreePool (PciIoDevice->DevicePath);\r
106 }\r
107\r
108 FreePool (PciIoDevice);\r
109}\r
110\r
111/**\r
112 Destroy all the pci device node under the bridge.\r
113 Bridge itself is not included.\r
114\r
115 @param Bridge A pointer to the PCI_IO_DEVICE.\r
116\r
117**/\r
118VOID\r
119DestroyPciDeviceTree (\r
120 IN PCI_IO_DEVICE *Bridge\r
121 )\r
122{\r
123 LIST_ENTRY *CurrentLink;\r
124 PCI_IO_DEVICE *Temp;\r
125\r
126 while (!IsListEmpty (&Bridge->ChildList)) {\r
127\r
128 CurrentLink = Bridge->ChildList.ForwardLink;\r
129\r
130 //\r
131 // Remove this node from the linked list\r
132 //\r
133 RemoveEntryList (CurrentLink);\r
134\r
135 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
136\r
137 if (!IsListEmpty (&Temp->ChildList)) {\r
138 DestroyPciDeviceTree (Temp);\r
139 }\r
140\r
141 FreePciDevice (Temp);\r
142 }\r
143}\r
144\r
145/**\r
146 Destroy all device nodes under the root bridge\r
147 specified by Controller.\r
148\r
149 The root bridge itself is also included.\r
150\r
151 @param Controller Root bridge handle.\r
152\r
153 @retval EFI_SUCCESS Destory all devcie nodes successfully.\r
154 @retval EFI_NOT_FOUND Cannot find any PCI device under specified\r
155 root bridge.\r
156\r
157**/\r
158EFI_STATUS\r
159DestroyRootBridgeByHandle (\r
160 IN EFI_HANDLE Controller\r
161 )\r
162{\r
163\r
164 LIST_ENTRY *CurrentLink;\r
165 PCI_IO_DEVICE *Temp;\r
166\r
167 CurrentLink = mPciDevicePool.ForwardLink;\r
168\r
169 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
170 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
171\r
172 if (Temp->Handle == Controller) {\r
173\r
174 RemoveEntryList (CurrentLink);\r
175\r
176 DestroyPciDeviceTree (Temp);\r
177\r
178 FreePciDevice (Temp);\r
179\r
180 return EFI_SUCCESS;\r
181 }\r
182\r
183 CurrentLink = CurrentLink->ForwardLink;\r
184 }\r
185\r
186 return EFI_NOT_FOUND;\r
187}\r
188\r
189/**\r
190 This function registers the PCI IO device.\r
191\r
192 It creates a handle for this PCI IO device (if the handle does not exist), attaches\r
193 appropriate protocols onto the handle, does necessary initialization, and sets up\r
194 parent/child relationship with its bus controller.\r
195\r
196 @param Controller An EFI handle for the PCI bus controller.\r
197 @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.\r
198 @param Handle A pointer to hold the returned EFI handle for the PCI IO device.\r
199\r
200 @retval EFI_SUCCESS The PCI device is successfully registered.\r
201 @retval other An error occurred when registering the PCI device.\r
202\r
203**/\r
204EFI_STATUS\r
205RegisterPciDevice (\r
206 IN EFI_HANDLE Controller,\r
207 IN PCI_IO_DEVICE *PciIoDevice,\r
208 OUT EFI_HANDLE *Handle OPTIONAL\r
209 )\r
210{\r
211 EFI_STATUS Status;\r
212 VOID *PlatformOpRomBuffer;\r
213 UINTN PlatformOpRomSize;\r
214 UINT8 PciExpressCapRegOffset;\r
215 EFI_PCI_IO_PROTOCOL *PciIo;\r
216 UINT8 Data8;\r
217 BOOLEAN HasEfiImage;\r
9060e3ec 218\r
219 //\r
220 // Install the pciio protocol, device path protocol\r
221 //\r
222 Status = gBS->InstallMultipleProtocolInterfaces (\r
223 &PciIoDevice->Handle,\r
224 &gEfiDevicePathProtocolGuid,\r
225 PciIoDevice->DevicePath,\r
226 &gEfiPciIoProtocolGuid,\r
227 &PciIoDevice->PciIo,\r
228 NULL\r
229 );\r
230 if (EFI_ERROR (Status)) {\r
231 return Status;\r
232 }\r
233\r
234 //\r
235 // Detect if PCI Express Device\r
236 //\r
237 PciExpressCapRegOffset = 0;\r
238 Status = LocateCapabilityRegBlock (\r
239 PciIoDevice,\r
240 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
241 &PciExpressCapRegOffset,\r
242 NULL\r
243 );\r
244 if (!EFI_ERROR (Status)) {\r
245 PciIoDevice->IsPciExp = TRUE;\r
246 }\r
247\r
248 //\r
249 // Force Interrupt line to "Unknown" or "No Connection"\r
250 //\r
251 PciIo = &(PciIoDevice->PciIo);\r
252 Data8 = PCI_INT_LINE_UNKNOWN;\r
253 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
d4048391 254 \r
9060e3ec 255 //\r
256 // Process OpRom\r
257 //\r
258 if (!PciIoDevice->AllOpRomProcessed) {\r
259\r
260 //\r
261 // Get the OpRom provided by platform\r
262 //\r
263 if (gPciPlatformProtocol != NULL) {\r
264 Status = gPciPlatformProtocol->GetPciRom (\r
265 gPciPlatformProtocol,\r
266 PciIoDevice->Handle,\r
267 &PlatformOpRomBuffer,\r
268 &PlatformOpRomSize\r
269 );\r
270 if (!EFI_ERROR (Status)) {\r
271 PciIoDevice->RomSize = PlatformOpRomSize;\r
272 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
273 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
274 //\r
275 // For OpROM read from gPciPlatformProtocol:\r
276 // Add the Rom Image to internal database for later PCI light enumeration\r
277 //\r
278 PciRomAddImageMapping (\r
279 NULL,\r
280 PciIoDevice->PciRootBridgeIo->SegmentNumber,\r
281 PciIoDevice->BusNumber,\r
282 PciIoDevice->DeviceNumber,\r
283 PciIoDevice->FunctionNumber,\r
284 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,\r
285 PciIoDevice->PciIo.RomSize\r
286 );\r
287 }\r
288 } else if (gPciOverrideProtocol != NULL) {\r
289 Status = gPciOverrideProtocol->GetPciRom (\r
290 gPciOverrideProtocol,\r
291 PciIoDevice->Handle,\r
292 &PlatformOpRomBuffer,\r
293 &PlatformOpRomSize\r
294 );\r
295 if (!EFI_ERROR (Status)) {\r
296 PciIoDevice->RomSize = PlatformOpRomSize;\r
297 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
298 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
299 //\r
300 // For OpROM read from gPciOverrideProtocol:\r
301 // Add the Rom Image to internal database for later PCI light enumeration\r
302 //\r
303 PciRomAddImageMapping (\r
304 NULL,\r
305 PciIoDevice->PciRootBridgeIo->SegmentNumber,\r
306 PciIoDevice->BusNumber,\r
307 PciIoDevice->DeviceNumber,\r
308 PciIoDevice->FunctionNumber,\r
309 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,\r
310 PciIoDevice->PciIo.RomSize\r
311 );\r
312 } \r
313 }\r
314 }\r
315\r
316 //\r
317 // Determine if there are EFI images in the option rom\r
318 //\r
319 HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);\r
320\r
321 if (HasEfiImage) {\r
322 Status = gBS->InstallMultipleProtocolInterfaces (\r
323 &PciIoDevice->Handle,\r
324 &gEfiLoadFile2ProtocolGuid,\r
325 &PciIoDevice->LoadFile2,\r
326 NULL\r
327 );\r
328 if (EFI_ERROR (Status)) {\r
329 gBS->UninstallMultipleProtocolInterfaces (\r
330 &PciIoDevice->Handle,\r
331 &gEfiDevicePathProtocolGuid,\r
332 PciIoDevice->DevicePath,\r
333 &gEfiPciIoProtocolGuid,\r
334 &PciIoDevice->PciIo,\r
335 NULL\r
336 );\r
337 return Status;\r
338 }\r
339 }\r
340\r
341\r
342 if (!PciIoDevice->AllOpRomProcessed) {\r
343\r
344 PciIoDevice->AllOpRomProcessed = TRUE;\r
345\r
346 //\r
347 // Dispatch the EFI OpRom for the PCI device.\r
348 // The OpRom is got from platform in the above code\r
349 // or loaded from device in the previous round of bus enumeration\r
350 //\r
351 if (HasEfiImage) {\r
352 ProcessOpRomImage (PciIoDevice);\r
353 }\r
354 }\r
355\r
356 if (PciIoDevice->BusOverride) {\r
357 //\r
358 // Install Bus Specific Driver Override Protocol\r
359 //\r
360 Status = gBS->InstallMultipleProtocolInterfaces (\r
361 &PciIoDevice->Handle,\r
362 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
363 &PciIoDevice->PciDriverOverride,\r
364 NULL\r
365 );\r
366 if (EFI_ERROR (Status)) {\r
367 gBS->UninstallMultipleProtocolInterfaces (\r
368 &PciIoDevice->Handle,\r
369 &gEfiDevicePathProtocolGuid,\r
370 PciIoDevice->DevicePath,\r
371 &gEfiPciIoProtocolGuid,\r
372 &PciIoDevice->PciIo,\r
373 NULL\r
374 );\r
375 if (HasEfiImage) {\r
376 gBS->UninstallMultipleProtocolInterfaces (\r
377 &PciIoDevice->Handle,\r
378 &gEfiLoadFile2ProtocolGuid,\r
379 &PciIoDevice->LoadFile2,\r
380 NULL\r
381 );\r
382 }\r
383\r
384 return Status;\r
385 }\r
386 }\r
387\r
388 Status = gBS->OpenProtocol (\r
389 Controller,\r
390 &gEfiPciRootBridgeIoProtocolGuid,\r
391 (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
392 gPciBusDriverBinding.DriverBindingHandle,\r
393 PciIoDevice->Handle,\r
394 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
395 );\r
396 if (EFI_ERROR (Status)) {\r
397 return Status;\r
398 }\r
399\r
400 if (Handle != NULL) {\r
401 *Handle = PciIoDevice->Handle;\r
402 }\r
403\r
404 //\r
405 // Indicate the pci device is registered\r
406 //\r
407 PciIoDevice->Registered = TRUE;\r
408\r
409 return EFI_SUCCESS;\r
410}\r
411\r
412/**\r
413 This function is used to remove the whole PCI devices on the specified bridge from\r
414 the root bridge.\r
415\r
416 @param RootBridgeHandle The root bridge device handle.\r
417 @param Bridge The bridge device to be removed.\r
418\r
419**/\r
420VOID\r
421RemoveAllPciDeviceOnBridge (\r
422 EFI_HANDLE RootBridgeHandle,\r
423 PCI_IO_DEVICE *Bridge\r
424 )\r
425{\r
426 LIST_ENTRY *CurrentLink;\r
427 PCI_IO_DEVICE *Temp;\r
428\r
429 while (!IsListEmpty (&Bridge->ChildList)) {\r
430\r
431 CurrentLink = Bridge->ChildList.ForwardLink;\r
432 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
433\r
434 //\r
435 // Check if the current node has been deregistered before\r
436 // If it is not, then deregister it\r
437 //\r
438 if (Temp->Registered) {\r
439 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
440 }\r
441\r
442 //\r
443 // Remove this node from the linked list\r
444 //\r
445 RemoveEntryList (CurrentLink);\r
446\r
447 if (!IsListEmpty (&Temp->ChildList)) {\r
448 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
449 }\r
450\r
451 FreePciDevice (Temp);\r
452 }\r
453}\r
454\r
455/**\r
456 This function is used to de-register the PCI IO device.\r
457\r
458 That includes un-installing PciIo protocol from the specified PCI\r
459 device handle.\r
460\r
461 @param Controller An EFI handle for the PCI bus controller.\r
462 @param Handle PCI device handle.\r
463\r
464 @retval EFI_SUCCESS The PCI device is successfully de-registered.\r
465 @retval other An error occurred when de-registering the PCI device.\r
466\r
467**/\r
468EFI_STATUS\r
469DeRegisterPciDevice (\r
470 IN EFI_HANDLE Controller,\r
471 IN EFI_HANDLE Handle\r
472 )\r
473\r
474{\r
475 EFI_PCI_IO_PROTOCOL *PciIo;\r
476 EFI_STATUS Status;\r
477 PCI_IO_DEVICE *PciIoDevice;\r
478 PCI_IO_DEVICE *Node;\r
479 LIST_ENTRY *CurrentLink;\r
480 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
481\r
482 Status = gBS->OpenProtocol (\r
483 Handle,\r
484 &gEfiPciIoProtocolGuid,\r
485 (VOID **) &PciIo,\r
486 gPciBusDriverBinding.DriverBindingHandle,\r
487 Controller,\r
488 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
489 );\r
490 if (!EFI_ERROR (Status)) {\r
491 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
492\r
493 //\r
494 // If it is already de-registered\r
495 //\r
496 if (!PciIoDevice->Registered) {\r
497 return EFI_SUCCESS;\r
498 }\r
499\r
500 //\r
501 // If it is PPB, first de-register its children\r
502 //\r
503\r
504 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
505\r
506 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
507\r
508 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
509 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
510 Status = DeRegisterPciDevice (Controller, Node->Handle);\r
511\r
512 if (EFI_ERROR (Status)) {\r
513 return Status;\r
514 }\r
515\r
516 CurrentLink = CurrentLink->ForwardLink;\r
517 }\r
518 }\r
519\r
520 //\r
521 // Close the child handle\r
522 //\r
523 Status = gBS->CloseProtocol (\r
524 Controller,\r
525 &gEfiPciRootBridgeIoProtocolGuid,\r
526 gPciBusDriverBinding.DriverBindingHandle,\r
527 Handle\r
528 );\r
529\r
530 //\r
531 // Un-install the Device Path protocol and PCI I/O protocol\r
532 // and Bus Specific Driver Override protocol if needed.\r
533 //\r
534 if (PciIoDevice->BusOverride) {\r
535 Status = gBS->UninstallMultipleProtocolInterfaces (\r
536 Handle,\r
537 &gEfiDevicePathProtocolGuid,\r
538 PciIoDevice->DevicePath,\r
539 &gEfiPciIoProtocolGuid,\r
540 &PciIoDevice->PciIo,\r
541 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
542 &PciIoDevice->PciDriverOverride,\r
543 NULL\r
544 );\r
545 } else {\r
546 Status = gBS->UninstallMultipleProtocolInterfaces (\r
547 Handle,\r
548 &gEfiDevicePathProtocolGuid,\r
549 PciIoDevice->DevicePath,\r
550 &gEfiPciIoProtocolGuid,\r
551 &PciIoDevice->PciIo,\r
552 NULL\r
553 );\r
554 }\r
555\r
556 if (!EFI_ERROR (Status)) {\r
557 //\r
558 // Try to uninstall LoadFile2 protocol if exists\r
559 //\r
560 Status = gBS->OpenProtocol (\r
561 Handle,\r
562 &gEfiLoadFile2ProtocolGuid,\r
563 NULL,\r
564 gPciBusDriverBinding.DriverBindingHandle,\r
565 Controller,\r
566 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
567 );\r
568 if (!EFI_ERROR (Status)) {\r
569 Status = gBS->UninstallMultipleProtocolInterfaces (\r
570 Handle,\r
571 &gEfiLoadFile2ProtocolGuid,\r
572 &PciIoDevice->LoadFile2,\r
573 NULL\r
574 );\r
575 }\r
576 //\r
577 // Restore Status\r
578 //\r
579 Status = EFI_SUCCESS;\r
580 }\r
581\r
582\r
583 if (EFI_ERROR (Status)) {\r
584 gBS->OpenProtocol (\r
585 Controller,\r
586 &gEfiPciRootBridgeIoProtocolGuid,\r
587 (VOID **) &PciRootBridgeIo,\r
588 gPciBusDriverBinding.DriverBindingHandle,\r
589 Handle,\r
590 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
591 );\r
592 return Status;\r
593 }\r
594\r
595 //\r
596 // The Device Driver should disable this device after disconnect\r
597 // so the Pci Bus driver will not touch this device any more.\r
598 // Restore the register field to the original value\r
599 //\r
600 PciIoDevice->Registered = FALSE;\r
601 PciIoDevice->Handle = NULL;\r
602 } else {\r
603\r
604 //\r
605 // Handle may be closed before\r
606 //\r
607 return EFI_SUCCESS;\r
608 }\r
609\r
610 return EFI_SUCCESS;\r
611}\r
612\r
613/**\r
614 Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.\r
615\r
616 @param Controller The root bridge handle.\r
617 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
618 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
619 @param NumberOfChildren Children number.\r
620 @param ChildHandleBuffer A pointer to the child handle buffer.\r
621\r
622 @retval EFI_NOT_READY Device is not allocated.\r
623 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.\r
624 @retval EFI_NOT_FOUND Can not find the specific device.\r
625 @retval EFI_SUCCESS Success to start Pci devices on bridge.\r
626\r
627**/\r
628EFI_STATUS\r
629StartPciDevicesOnBridge (\r
630 IN EFI_HANDLE Controller,\r
631 IN PCI_IO_DEVICE *RootBridge,\r
632 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
633 IN OUT UINT8 *NumberOfChildren,\r
634 IN OUT EFI_HANDLE *ChildHandleBuffer\r
635 )\r
636\r
637{\r
638 PCI_IO_DEVICE *PciIoDevice;\r
639 EFI_DEV_PATH_PTR Node;\r
640 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
641 EFI_STATUS Status;\r
642 LIST_ENTRY *CurrentLink;\r
643 UINT64 Supports;\r
644\r
645 PciIoDevice = NULL;\r
646 CurrentLink = RootBridge->ChildList.ForwardLink;\r
647\r
648 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
649\r
650 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
651 if (RemainingDevicePath != NULL) {\r
652\r
653 Node.DevPath = RemainingDevicePath;\r
654\r
655 if (Node.Pci->Device != PciIoDevice->DeviceNumber ||\r
656 Node.Pci->Function != PciIoDevice->FunctionNumber) {\r
657 CurrentLink = CurrentLink->ForwardLink;\r
658 continue;\r
659 }\r
660\r
661 //\r
662 // Check if the device has been assigned with required resource\r
663 //\r
664 if (!PciIoDevice->Allocated) {\r
665 return EFI_NOT_READY;\r
666 }\r
667\r
668 //\r
669 // Check if the current node has been registered before\r
670 // If it is not, register it\r
671 //\r
672 if (!PciIoDevice->Registered) {\r
673 Status = RegisterPciDevice (\r
674 Controller,\r
675 PciIoDevice,\r
676 NULL\r
677 );\r
678\r
679 }\r
680\r
681 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
682 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
683 (*NumberOfChildren)++;\r
684 }\r
685\r
686 //\r
687 // Get the next device path\r
688 //\r
689 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);\r
690 if (IsDevicePathEnd (CurrentDevicePath)) {\r
691 return EFI_SUCCESS;\r
692 }\r
693\r
694 //\r
695 // If it is a PPB\r
696 //\r
13fd0d50 697 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 698 Status = StartPciDevicesOnBridge (\r
699 Controller,\r
700 PciIoDevice,\r
701 CurrentDevicePath,\r
702 NumberOfChildren,\r
703 ChildHandleBuffer\r
704 );\r
705\r
706 PciIoDevice->PciIo.Attributes (\r
707 &(PciIoDevice->PciIo),\r
708 EfiPciIoAttributeOperationSupported,\r
709 0,\r
710 &Supports\r
711 );\r
712 Supports &= EFI_PCI_DEVICE_ENABLE;\r
713 PciIoDevice->PciIo.Attributes (\r
714 &(PciIoDevice->PciIo),\r
715 EfiPciIoAttributeOperationEnable,\r
716 Supports,\r
717 NULL\r
718 );\r
719\r
720 return Status;\r
721 } else {\r
722\r
723 //\r
724 // Currently, the PCI bus driver only support PCI-PCI bridge\r
725 //\r
726 return EFI_UNSUPPORTED;\r
727 }\r
728\r
729 } else {\r
730\r
731 //\r
732 // If remaining device path is NULL,\r
733 // try to enable all the pci devices under this bridge\r
734 //\r
735 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {\r
736 Status = RegisterPciDevice (\r
737 Controller,\r
738 PciIoDevice,\r
739 NULL\r
740 );\r
741\r
742 }\r
743\r
744 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
745 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
746 (*NumberOfChildren)++;\r
747 }\r
748\r
13fd0d50 749 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 750 Status = StartPciDevicesOnBridge (\r
751 Controller,\r
752 PciIoDevice,\r
753 RemainingDevicePath,\r
754 NumberOfChildren,\r
755 ChildHandleBuffer\r
756 );\r
757\r
758 PciIoDevice->PciIo.Attributes (\r
759 &(PciIoDevice->PciIo),\r
760 EfiPciIoAttributeOperationSupported,\r
761 0,\r
762 &Supports\r
763 );\r
764 Supports &= EFI_PCI_DEVICE_ENABLE;\r
765 PciIoDevice->PciIo.Attributes (\r
766 &(PciIoDevice->PciIo),\r
767 EfiPciIoAttributeOperationEnable,\r
768 Supports,\r
769 NULL\r
770 );\r
771\r
772 }\r
773\r
774 CurrentLink = CurrentLink->ForwardLink;\r
775 }\r
776 }\r
777\r
778 if (PciIoDevice == NULL) {\r
779 return EFI_NOT_FOUND;\r
780 } else {\r
781 return EFI_SUCCESS;\r
782 }\r
783}\r
784\r
785/**\r
786 Start to manage all the PCI devices it found previously under\r
787 the entire host bridge.\r
788\r
789 @param Controller The root bridge handle.\r
790\r
791 @retval EFI_NOT_READY Device is not allocated.\r
792 @retval EFI_SUCCESS Success to start Pci device on host bridge.\r
793\r
794**/\r
795EFI_STATUS\r
796StartPciDevices (\r
797 IN EFI_HANDLE Controller\r
798 )\r
799{\r
800 PCI_IO_DEVICE *RootBridge;\r
801 EFI_HANDLE ThisHostBridge;\r
802 LIST_ENTRY *CurrentLink;\r
803\r
804 RootBridge = GetRootBridgeByHandle (Controller);\r
805 ASSERT (RootBridge != NULL);\r
806 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
807\r
808 CurrentLink = mPciDevicePool.ForwardLink;\r
809\r
810 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
811\r
812 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
813 //\r
814 // Locate the right root bridge to start\r
815 //\r
816 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
817 StartPciDevicesOnBridge (\r
818 RootBridge->Handle,\r
819 RootBridge,\r
820 NULL,\r
821 NULL,\r
822 NULL\r
823 );\r
824 }\r
825\r
826 CurrentLink = CurrentLink->ForwardLink;\r
827 }\r
828\r
829 return EFI_SUCCESS;\r
830}\r
831\r
832/**\r
833 Create root bridge device.\r
834\r
835 @param RootBridgeHandle Specified root bridge hanle.\r
836\r
837 @return The crated root bridge device instance, NULL means no\r
838 root bridge device instance created.\r
839\r
840**/\r
841PCI_IO_DEVICE *\r
842CreateRootBridge (\r
843 IN EFI_HANDLE RootBridgeHandle\r
844 )\r
845{\r
846 EFI_STATUS Status;\r
847 PCI_IO_DEVICE *Dev;\r
848 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
849 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
850\r
851 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
852 if (Dev == NULL) {\r
853 return NULL;\r
854 }\r
855\r
856 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
857 Dev->Handle = RootBridgeHandle;\r
858 InitializeListHead (&Dev->ChildList);\r
859\r
860 Status = gBS->OpenProtocol (\r
861 RootBridgeHandle,\r
862 &gEfiDevicePathProtocolGuid,\r
863 (VOID **) &ParentDevicePath,\r
864 gPciBusDriverBinding.DriverBindingHandle,\r
865 RootBridgeHandle,\r
866 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
867 );\r
868\r
869 if (EFI_ERROR (Status)) {\r
870 FreePool (Dev);\r
871 return NULL;\r
872 }\r
873\r
874 //\r
875 // Record the root bridge parent device path\r
876 //\r
877 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
878\r
879 //\r
880 // Get the pci root bridge io protocol\r
881 //\r
882 Status = gBS->OpenProtocol (\r
883 RootBridgeHandle,\r
884 &gEfiPciRootBridgeIoProtocolGuid,\r
885 (VOID **) &PciRootBridgeIo,\r
886 gPciBusDriverBinding.DriverBindingHandle,\r
887 RootBridgeHandle,\r
888 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
889 );\r
890\r
891 if (EFI_ERROR (Status)) {\r
892 FreePciDevice (Dev);\r
893 return NULL;\r
894 }\r
895\r
896 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
897\r
898 //\r
899 // Initialize the PCI I/O instance structure\r
900 //\r
901 InitializePciIoInstance (Dev);\r
902 InitializePciDriverOverrideInstance (Dev);\r
903 InitializePciLoadFile2 (Dev);\r
904\r
905 //\r
906 // Initialize reserved resource list and\r
907 // option rom driver list\r
908 //\r
909 InitializeListHead (&Dev->ReservedResourceList);\r
910 InitializeListHead (&Dev->OptionRomDriverList);\r
911\r
912 return Dev;\r
913}\r
914\r
915/**\r
916 Get root bridge device instance by specific root bridge handle.\r
917\r
918 @param RootBridgeHandle Given root bridge handle.\r
919\r
920 @return The root bridge device instance, NULL means no root bridge\r
921 device instance found.\r
922\r
923**/\r
924PCI_IO_DEVICE *\r
925GetRootBridgeByHandle (\r
926 EFI_HANDLE RootBridgeHandle\r
927 )\r
928{\r
929 PCI_IO_DEVICE *RootBridgeDev;\r
930 LIST_ENTRY *CurrentLink;\r
931\r
932 CurrentLink = mPciDevicePool.ForwardLink;\r
933\r
934 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
935\r
936 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
937 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
938 return RootBridgeDev;\r
939 }\r
940\r
941 CurrentLink = CurrentLink->ForwardLink;\r
942 }\r
943\r
944 return NULL;\r
945}\r
946\r
947/**\r
948 Judege whether Pci device existed.\r
949\r
950 @param Bridge Parent bridege instance.\r
951 @param PciIoDevice Device instance.\r
952\r
953 @retval TRUE Pci device existed.\r
954 @retval FALSE Pci device did not exist.\r
955\r
956**/\r
957BOOLEAN\r
958PciDeviceExisted (\r
959 IN PCI_IO_DEVICE *Bridge,\r
960 IN PCI_IO_DEVICE *PciIoDevice\r
961 )\r
962{\r
963\r
964 PCI_IO_DEVICE *Temp;\r
965 LIST_ENTRY *CurrentLink;\r
966\r
967 CurrentLink = Bridge->ChildList.ForwardLink;\r
968\r
969 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
970\r
971 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
972\r
973 if (Temp == PciIoDevice) {\r
974 return TRUE;\r
975 }\r
976\r
977 if (!IsListEmpty (&Temp->ChildList)) {\r
978 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
979 return TRUE;\r
980 }\r
981 }\r
982\r
983 CurrentLink = CurrentLink->ForwardLink;\r
984 }\r
985\r
986 return FALSE;\r
987}\r
988\r
989/**\r
990 Get the active VGA device on the same segment.\r
991\r
992 @param VgaDevice PCI IO instance for the VGA device.\r
993\r
994 @return The active VGA device on the same segment.\r
995\r
996**/\r
997PCI_IO_DEVICE *\r
998ActiveVGADeviceOnTheSameSegment (\r
999 IN PCI_IO_DEVICE *VgaDevice\r
1000 )\r
1001{\r
1002 LIST_ENTRY *CurrentLink;\r
1003 PCI_IO_DEVICE *Temp;\r
1004\r
1005 CurrentLink = mPciDevicePool.ForwardLink;\r
1006\r
1007 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
1008\r
1009 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1010\r
1011 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
1012\r
1013 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1014\r
1015 if (Temp != NULL) {\r
1016 return Temp;\r
1017 }\r
1018 }\r
1019\r
1020 CurrentLink = CurrentLink->ForwardLink;\r
1021 }\r
1022\r
1023 return NULL;\r
1024}\r
1025\r
1026/**\r
1027 Get the active VGA device on the root bridge.\r
1028\r
1029 @param RootBridge PCI IO instance for the root bridge.\r
1030\r
1031 @return The active VGA device.\r
1032\r
1033**/\r
1034PCI_IO_DEVICE *\r
1035ActiveVGADeviceOnTheRootBridge (\r
1036 IN PCI_IO_DEVICE *RootBridge\r
1037 )\r
1038{\r
1039 LIST_ENTRY *CurrentLink;\r
1040 PCI_IO_DEVICE *Temp;\r
1041\r
1042 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1043\r
1044 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
1045\r
1046 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1047\r
1048 if (IS_PCI_VGA(&Temp->Pci) &&\r
1049 (Temp->Attributes &\r
1050 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1051 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
1052 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {\r
1053 return Temp;\r
1054 }\r
1055\r
1056 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1057\r
1058 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1059\r
1060 if (Temp != NULL) {\r
1061 return Temp;\r
1062 }\r
1063 }\r
1064\r
1065 CurrentLink = CurrentLink->ForwardLink;\r
1066 }\r
1067\r
1068 return NULL;\r
1069}\r
1070\r
1071\r
1072/**\r
1073 Get HPC PCI address according to its device path.\r
1074\r
1075 @param RootBridge Root bridege Io instance.\r
1076 @param RemainingDevicePath Given searching device path.\r
1077 @param PciAddress Buffer holding searched result.\r
1078\r
1079 @retval EFI_SUCCESS PCI address was stored in PciAddress\r
1080 @retval EFI_NOT_FOUND Can not find the specific device path.\r
1081\r
1082**/\r
1083EFI_STATUS\r
1084GetHpcPciAddressFromRootBridge (\r
1085 IN PCI_IO_DEVICE *RootBridge,\r
1086 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1087 OUT UINT64 *PciAddress\r
1088 )\r
1089{\r
1090 EFI_DEV_PATH_PTR Node;\r
1091 PCI_IO_DEVICE *Temp;\r
1092 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1093 LIST_ENTRY *CurrentLink;\r
1094 BOOLEAN MisMatch;\r
1095\r
1096 MisMatch = FALSE;\r
1097\r
1098 CurrentDevicePath = RemainingDevicePath;\r
1099 Node.DevPath = CurrentDevicePath;\r
1100 Temp = NULL;\r
1101\r
1102 while (!IsDevicePathEnd (CurrentDevicePath)) {\r
1103\r
1104 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1105 Node.DevPath = CurrentDevicePath;\r
1106\r
1107 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
1108 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1109\r
1110 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1111 Node.Pci->Function == Temp->FunctionNumber) {\r
1112 RootBridge = Temp;\r
1113 break;\r
1114 }\r
1115\r
1116 CurrentLink = CurrentLink->ForwardLink;\r
1117 }\r
1118\r
1119 //\r
1120 // Check if we find the bridge\r
1121 //\r
1122 if (CurrentLink == &RootBridge->ChildList) {\r
1123\r
1124 MisMatch = TRUE;\r
1125 break;\r
1126\r
1127 }\r
1128\r
1129 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
1130 }\r
1131\r
1132 if (MisMatch) {\r
1133\r
1134 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
1135\r
1136 if (IsDevicePathEnd (CurrentDevicePath)) {\r
1137 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1138 return EFI_SUCCESS;\r
1139 }\r
1140\r
1141 return EFI_NOT_FOUND;\r
1142 }\r
1143\r
1144 if (Temp != NULL) {\r
1145 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1146 } else {\r
1147 return EFI_NOT_FOUND;\r
1148 }\r
1149\r
1150 return EFI_SUCCESS;\r
1151\r
1152}\r
1153\r