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