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