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