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