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