]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
MdeModulePkg/PciBus: Revert "disable all BME when entering RT"
[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
5db417ed 4Copyright (c) 2006 - 2017, 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
221c8fd5 285 PciIoDevice->PciIo.RomImage,\r
9060e3ec 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
221c8fd5 311 PciIoDevice->PciIo.RomImage,\r
9060e3ec 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
5db417ed
RN
714 //\r
715 // By default every bridge's IO and MMIO spaces are enabled.\r
716 // Bridge's Bus Master will be enabled when any device behind it requests\r
717 // to enable Bus Master.\r
718 //\r
719 Supports &= (UINT64) (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);\r
9060e3ec 720 PciIoDevice->PciIo.Attributes (\r
721 &(PciIoDevice->PciIo),\r
722 EfiPciIoAttributeOperationEnable,\r
723 Supports,\r
724 NULL\r
725 );\r
726\r
727 return Status;\r
728 } else {\r
729\r
730 //\r
731 // Currently, the PCI bus driver only support PCI-PCI bridge\r
732 //\r
733 return EFI_UNSUPPORTED;\r
734 }\r
735\r
736 } else {\r
737\r
738 //\r
739 // If remaining device path is NULL,\r
740 // try to enable all the pci devices under this bridge\r
741 //\r
742 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {\r
743 Status = RegisterPciDevice (\r
744 Controller,\r
745 PciIoDevice,\r
746 NULL\r
747 );\r
748\r
749 }\r
750\r
751 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
752 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
753 (*NumberOfChildren)++;\r
754 }\r
755\r
13fd0d50 756 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 757 Status = StartPciDevicesOnBridge (\r
758 Controller,\r
759 PciIoDevice,\r
760 RemainingDevicePath,\r
761 NumberOfChildren,\r
762 ChildHandleBuffer\r
763 );\r
764\r
765 PciIoDevice->PciIo.Attributes (\r
766 &(PciIoDevice->PciIo),\r
767 EfiPciIoAttributeOperationSupported,\r
768 0,\r
769 &Supports\r
770 );\r
5db417ed
RN
771 //\r
772 // By default every bridge's IO and MMIO spaces are enabled.\r
773 // Bridge's Bus Master will be enabled when any device behind it requests\r
774 // to enable Bus Master.\r
775 //\r
776 Supports &= (UINT64) (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);\r
9060e3ec 777 PciIoDevice->PciIo.Attributes (\r
778 &(PciIoDevice->PciIo),\r
779 EfiPciIoAttributeOperationEnable,\r
780 Supports,\r
781 NULL\r
782 );\r
783\r
784 }\r
785\r
786 CurrentLink = CurrentLink->ForwardLink;\r
787 }\r
788 }\r
789\r
790 if (PciIoDevice == NULL) {\r
791 return EFI_NOT_FOUND;\r
792 } else {\r
793 return EFI_SUCCESS;\r
794 }\r
795}\r
796\r
797/**\r
798 Start to manage all the PCI devices it found previously under\r
799 the entire host bridge.\r
800\r
801 @param Controller The root bridge handle.\r
802\r
803 @retval EFI_NOT_READY Device is not allocated.\r
804 @retval EFI_SUCCESS Success to start Pci device on host bridge.\r
805\r
806**/\r
807EFI_STATUS\r
808StartPciDevices (\r
809 IN EFI_HANDLE Controller\r
810 )\r
811{\r
812 PCI_IO_DEVICE *RootBridge;\r
813 EFI_HANDLE ThisHostBridge;\r
814 LIST_ENTRY *CurrentLink;\r
815\r
816 RootBridge = GetRootBridgeByHandle (Controller);\r
817 ASSERT (RootBridge != NULL);\r
818 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
819\r
820 CurrentLink = mPciDevicePool.ForwardLink;\r
821\r
822 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
823\r
824 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
825 //\r
826 // Locate the right root bridge to start\r
827 //\r
828 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
829 StartPciDevicesOnBridge (\r
830 RootBridge->Handle,\r
831 RootBridge,\r
832 NULL,\r
833 NULL,\r
834 NULL\r
835 );\r
836 }\r
837\r
838 CurrentLink = CurrentLink->ForwardLink;\r
839 }\r
840\r
841 return EFI_SUCCESS;\r
842}\r
843\r
844/**\r
845 Create root bridge device.\r
846\r
847 @param RootBridgeHandle Specified root bridge hanle.\r
848\r
849 @return The crated root bridge device instance, NULL means no\r
850 root bridge device instance created.\r
851\r
852**/\r
853PCI_IO_DEVICE *\r
854CreateRootBridge (\r
855 IN EFI_HANDLE RootBridgeHandle\r
856 )\r
857{\r
858 EFI_STATUS Status;\r
859 PCI_IO_DEVICE *Dev;\r
860 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
861 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
862\r
863 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
864 if (Dev == NULL) {\r
865 return NULL;\r
866 }\r
867\r
868 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
869 Dev->Handle = RootBridgeHandle;\r
870 InitializeListHead (&Dev->ChildList);\r
871\r
872 Status = gBS->OpenProtocol (\r
873 RootBridgeHandle,\r
874 &gEfiDevicePathProtocolGuid,\r
875 (VOID **) &ParentDevicePath,\r
876 gPciBusDriverBinding.DriverBindingHandle,\r
877 RootBridgeHandle,\r
878 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
879 );\r
880\r
881 if (EFI_ERROR (Status)) {\r
882 FreePool (Dev);\r
883 return NULL;\r
884 }\r
885\r
886 //\r
887 // Record the root bridge parent device path\r
888 //\r
889 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
890\r
891 //\r
892 // Get the pci root bridge io protocol\r
893 //\r
894 Status = gBS->OpenProtocol (\r
895 RootBridgeHandle,\r
896 &gEfiPciRootBridgeIoProtocolGuid,\r
897 (VOID **) &PciRootBridgeIo,\r
898 gPciBusDriverBinding.DriverBindingHandle,\r
899 RootBridgeHandle,\r
900 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
901 );\r
902\r
903 if (EFI_ERROR (Status)) {\r
904 FreePciDevice (Dev);\r
905 return NULL;\r
906 }\r
907\r
908 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
909\r
910 //\r
911 // Initialize the PCI I/O instance structure\r
912 //\r
913 InitializePciIoInstance (Dev);\r
914 InitializePciDriverOverrideInstance (Dev);\r
915 InitializePciLoadFile2 (Dev);\r
916\r
917 //\r
918 // Initialize reserved resource list and\r
919 // option rom driver list\r
920 //\r
921 InitializeListHead (&Dev->ReservedResourceList);\r
922 InitializeListHead (&Dev->OptionRomDriverList);\r
923\r
924 return Dev;\r
925}\r
926\r
927/**\r
928 Get root bridge device instance by specific root bridge handle.\r
929\r
930 @param RootBridgeHandle Given root bridge handle.\r
931\r
932 @return The root bridge device instance, NULL means no root bridge\r
933 device instance found.\r
934\r
935**/\r
936PCI_IO_DEVICE *\r
937GetRootBridgeByHandle (\r
938 EFI_HANDLE RootBridgeHandle\r
939 )\r
940{\r
941 PCI_IO_DEVICE *RootBridgeDev;\r
942 LIST_ENTRY *CurrentLink;\r
943\r
944 CurrentLink = mPciDevicePool.ForwardLink;\r
945\r
946 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
947\r
948 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
949 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
950 return RootBridgeDev;\r
951 }\r
952\r
953 CurrentLink = CurrentLink->ForwardLink;\r
954 }\r
955\r
956 return NULL;\r
957}\r
958\r
959/**\r
960 Judege whether Pci device existed.\r
961\r
962 @param Bridge Parent bridege instance.\r
963 @param PciIoDevice Device instance.\r
964\r
965 @retval TRUE Pci device existed.\r
966 @retval FALSE Pci device did not exist.\r
967\r
968**/\r
969BOOLEAN\r
970PciDeviceExisted (\r
971 IN PCI_IO_DEVICE *Bridge,\r
972 IN PCI_IO_DEVICE *PciIoDevice\r
973 )\r
974{\r
975\r
976 PCI_IO_DEVICE *Temp;\r
977 LIST_ENTRY *CurrentLink;\r
978\r
979 CurrentLink = Bridge->ChildList.ForwardLink;\r
980\r
981 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
982\r
983 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
984\r
985 if (Temp == PciIoDevice) {\r
986 return TRUE;\r
987 }\r
988\r
989 if (!IsListEmpty (&Temp->ChildList)) {\r
990 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
991 return TRUE;\r
992 }\r
993 }\r
994\r
995 CurrentLink = CurrentLink->ForwardLink;\r
996 }\r
997\r
998 return FALSE;\r
999}\r
1000\r
1001/**\r
1002 Get the active VGA device on the same segment.\r
1003\r
1004 @param VgaDevice PCI IO instance for the VGA device.\r
1005\r
1006 @return The active VGA device on the same segment.\r
1007\r
1008**/\r
1009PCI_IO_DEVICE *\r
1010ActiveVGADeviceOnTheSameSegment (\r
1011 IN PCI_IO_DEVICE *VgaDevice\r
1012 )\r
1013{\r
1014 LIST_ENTRY *CurrentLink;\r
1015 PCI_IO_DEVICE *Temp;\r
1016\r
1017 CurrentLink = mPciDevicePool.ForwardLink;\r
1018\r
1019 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
1020\r
1021 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1022\r
1023 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
1024\r
1025 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1026\r
1027 if (Temp != NULL) {\r
1028 return Temp;\r
1029 }\r
1030 }\r
1031\r
1032 CurrentLink = CurrentLink->ForwardLink;\r
1033 }\r
1034\r
1035 return NULL;\r
1036}\r
1037\r
1038/**\r
1039 Get the active VGA device on the root bridge.\r
1040\r
1041 @param RootBridge PCI IO instance for the root bridge.\r
1042\r
1043 @return The active VGA device.\r
1044\r
1045**/\r
1046PCI_IO_DEVICE *\r
1047ActiveVGADeviceOnTheRootBridge (\r
1048 IN PCI_IO_DEVICE *RootBridge\r
1049 )\r
1050{\r
1051 LIST_ENTRY *CurrentLink;\r
1052 PCI_IO_DEVICE *Temp;\r
1053\r
1054 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1055\r
1056 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
1057\r
1058 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1059\r
1060 if (IS_PCI_VGA(&Temp->Pci) &&\r
1061 (Temp->Attributes &\r
1062 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1063 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
1064 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {\r
1065 return Temp;\r
1066 }\r
1067\r
1068 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1069\r
1070 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1071\r
1072 if (Temp != NULL) {\r
1073 return Temp;\r
1074 }\r
1075 }\r
1076\r
1077 CurrentLink = CurrentLink->ForwardLink;\r
1078 }\r
1079\r
1080 return NULL;\r
1081}\r
1082\r
1083\r
1084/**\r
1085 Get HPC PCI address according to its device path.\r
1086\r
1087 @param RootBridge Root bridege Io instance.\r
1088 @param RemainingDevicePath Given searching device path.\r
1089 @param PciAddress Buffer holding searched result.\r
1090\r
1091 @retval EFI_SUCCESS PCI address was stored in PciAddress\r
1092 @retval EFI_NOT_FOUND Can not find the specific device path.\r
1093\r
1094**/\r
1095EFI_STATUS\r
1096GetHpcPciAddressFromRootBridge (\r
1097 IN PCI_IO_DEVICE *RootBridge,\r
1098 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1099 OUT UINT64 *PciAddress\r
1100 )\r
1101{\r
1102 EFI_DEV_PATH_PTR Node;\r
1103 PCI_IO_DEVICE *Temp;\r
1104 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1105 LIST_ENTRY *CurrentLink;\r
1106 BOOLEAN MisMatch;\r
1107\r
1108 MisMatch = FALSE;\r
1109\r
1110 CurrentDevicePath = RemainingDevicePath;\r
1111 Node.DevPath = CurrentDevicePath;\r
1112 Temp = NULL;\r
1113\r
1114 while (!IsDevicePathEnd (CurrentDevicePath)) {\r
1115\r
1116 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1117 Node.DevPath = CurrentDevicePath;\r
1118\r
1119 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
1120 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1121\r
1122 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1123 Node.Pci->Function == Temp->FunctionNumber) {\r
1124 RootBridge = Temp;\r
1125 break;\r
1126 }\r
1127\r
1128 CurrentLink = CurrentLink->ForwardLink;\r
1129 }\r
1130\r
1131 //\r
1132 // Check if we find the bridge\r
1133 //\r
1134 if (CurrentLink == &RootBridge->ChildList) {\r
1135\r
1136 MisMatch = TRUE;\r
1137 break;\r
1138\r
1139 }\r
1140\r
1141 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
1142 }\r
1143\r
1144 if (MisMatch) {\r
1145\r
1146 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
1147\r
1148 if (IsDevicePathEnd (CurrentDevicePath)) {\r
1149 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1150 return EFI_SUCCESS;\r
1151 }\r
1152\r
1153 return EFI_NOT_FOUND;\r
1154 }\r
1155\r
1156 if (Temp != NULL) {\r
1157 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1158 } else {\r
1159 return EFI_NOT_FOUND;\r
1160 }\r
1161\r
1162 return EFI_SUCCESS;\r
1163\r
1164}\r
1165\r