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