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