]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c
Clean up MSA file of the checked in modules which include:
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / PciBus / Dxe / PciDeviceSupport.c
CommitLineData
878ddf1f 1/*++\r
2\r
6c31fdb8 3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
878ddf1f 11\r
12Module Name:\r
13\r
14 PciDeviceSupport.c\r
6c31fdb8 15\r
878ddf1f 16Abstract:\r
17\r
18 This file provides routine to support Pci device node manipulation\r
19\r
20Revision History\r
21\r
22--*/\r
23\r
f0ec738d 24#include "pcibus.h"\r
878ddf1f 25#include "PciDeviceSupport.h"\r
26\r
27//\r
28// This device structure is serviced as a header.\r
29// Its Next field points to the first root bridge device node\r
30//\r
31LIST_ENTRY gPciDevicePool;\r
32\r
33EFI_STATUS\r
34InitializePciDevicePool (\r
35 VOID\r
36 )\r
37/*++\r
38\r
39Routine Description:\r
40\r
41 Initialize the gPciDevicePool\r
42\r
43Arguments:\r
44\r
45Returns:\r
46\r
47 None\r
48\r
49--*/\r
50// TODO: EFI_SUCCESS - add return value to function comment\r
51{\r
52 InitializeListHead (&gPciDevicePool);\r
53\r
54 return EFI_SUCCESS;\r
55}\r
56\r
57EFI_STATUS\r
58InsertRootBridge (\r
59 PCI_IO_DEVICE *RootBridge\r
60 )\r
61/*++\r
62\r
63Routine Description:\r
64\r
65 Insert a root bridge into PCI device pool\r
66\r
67Arguments:\r
68\r
69 RootBridge - A pointer to the PCI_IO_DEVICE.\r
70\r
71Returns:\r
72\r
73 None\r
74\r
75--*/\r
76// TODO: EFI_SUCCESS - add return value to function comment\r
77{\r
78\r
79 InsertTailList (&gPciDevicePool, &(RootBridge->Link));\r
80\r
81 return EFI_SUCCESS;\r
82}\r
83\r
84EFI_STATUS\r
85InsertPciDevice (\r
86 PCI_IO_DEVICE *Bridge,\r
87 PCI_IO_DEVICE *PciDeviceNode\r
88 )\r
89/*++\r
90\r
91Routine Description:\r
92\r
93 This function is used to insert a PCI device node under\r
94 a bridge\r
95\r
96Arguments:\r
97 Bridge - A pointer to the PCI_IO_DEVICE.\r
98 PciDeviceNode - A pointer to the PCI_IO_DEVICE.\r
99\r
100Returns:\r
101\r
102 None\r
103\r
104--*/\r
105// TODO: EFI_SUCCESS - add return value to function comment\r
106{\r
107\r
108 InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));\r
109 PciDeviceNode->Parent = Bridge;\r
110\r
111 return EFI_SUCCESS;\r
112}\r
113\r
114EFI_STATUS\r
115DestroyRootBridge (\r
116 IN PCI_IO_DEVICE *RootBridge\r
117 )\r
118/*++\r
119\r
120Routine Description:\r
121\r
6c31fdb8 122\r
878ddf1f 123Arguments:\r
124\r
125 RootBridge - A pointer to the PCI_IO_DEVICE.\r
126\r
127Returns:\r
128\r
129 None\r
130\r
131--*/\r
132// TODO: EFI_SUCCESS - add return value to function comment\r
133{\r
134 DestroyPciDeviceTree (RootBridge);\r
135\r
136 FreePciDevice (RootBridge);\r
137\r
138 return EFI_SUCCESS;\r
139}\r
140\r
141EFI_STATUS\r
142FreePciDevice (\r
143 IN PCI_IO_DEVICE *PciIoDevice\r
144 )\r
145/*++\r
146\r
147Routine Description:\r
148\r
149 Destroy a pci device node.\r
6c31fdb8 150 Also all direct or indirect allocated resource for this node will be freed.\r
878ddf1f 151\r
152Arguments:\r
153\r
154 PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
155\r
156Returns:\r
157\r
158 None\r
159\r
160--*/\r
161// TODO: EFI_SUCCESS - add return value to function comment\r
162{\r
163\r
164 //\r
165 // Assume all children have been removed underneath this device\r
166 //\r
167 if (PciIoDevice->ResourcePaddingDescriptors != NULL) {\r
168 gBS->FreePool (PciIoDevice->ResourcePaddingDescriptors);\r
169 }\r
170\r
171 if (PciIoDevice->DevicePath != NULL) {\r
172 gBS->FreePool (PciIoDevice->DevicePath);\r
173 }\r
174\r
175 gBS->FreePool (PciIoDevice);\r
176\r
177 return EFI_SUCCESS;\r
178}\r
179\r
180EFI_STATUS\r
181DestroyPciDeviceTree (\r
182 IN PCI_IO_DEVICE *Bridge\r
183 )\r
184/*++\r
185\r
186Routine Description:\r
187\r
188 Destroy all the pci device node under the bridge.\r
189 Bridge itself is not included.\r
190\r
191Arguments:\r
192\r
193 Bridge - A pointer to the PCI_IO_DEVICE.\r
194\r
195Returns:\r
196\r
197 None\r
198\r
199--*/\r
200// TODO: EFI_SUCCESS - add return value to function comment\r
201{\r
202 LIST_ENTRY *CurrentLink;\r
203 PCI_IO_DEVICE *Temp;\r
204\r
205 while (!IsListEmpty (&Bridge->ChildList)) {\r
206\r
207 CurrentLink = Bridge->ChildList.ForwardLink;\r
208\r
209 //\r
210 // Remove this node from the linked list\r
211 //\r
212 RemoveEntryList (CurrentLink);\r
213\r
214 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
215\r
216 if (!IsListEmpty (&Temp->ChildList)) {\r
217 DestroyPciDeviceTree (Temp);\r
218 }\r
219\r
220 FreePciDevice (Temp);\r
221 }\r
222\r
223 return EFI_SUCCESS;\r
224}\r
225\r
226EFI_STATUS\r
227DestroyRootBridgeByHandle (\r
228 EFI_HANDLE Controller\r
229 )\r
230/*++\r
231\r
232Routine Description:\r
233\r
234 Destroy all device nodes under the root bridge\r
6c31fdb8 235 specified by Controller.\r
878ddf1f 236 The root bridge itself is also included.\r
237\r
238Arguments:\r
239\r
240 Controller - An efi handle.\r
241\r
242Returns:\r
243\r
244 None\r
245\r
246--*/\r
247// TODO: EFI_SUCCESS - add return value to function comment\r
248// TODO: EFI_NOT_FOUND - add return value to function comment\r
249{\r
250\r
251 LIST_ENTRY *CurrentLink;\r
252 PCI_IO_DEVICE *Temp;\r
253\r
254 CurrentLink = gPciDevicePool.ForwardLink;\r
255\r
256 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
257 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
258\r
259 if (Temp->Handle == Controller) {\r
260\r
261 RemoveEntryList (CurrentLink);\r
262\r
263 DestroyPciDeviceTree (Temp);\r
264\r
265 FreePciDevice (Temp);\r
266\r
267 return EFI_SUCCESS;\r
268 }\r
269\r
270 CurrentLink = CurrentLink->ForwardLink;\r
271 }\r
272\r
273 return EFI_NOT_FOUND;\r
274}\r
275\r
276EFI_STATUS\r
277RegisterPciDevice (\r
278 IN EFI_HANDLE Controller,\r
279 IN PCI_IO_DEVICE *PciIoDevice,\r
280 OUT EFI_HANDLE *Handle OPTIONAL\r
281 )\r
282/*++\r
283\r
284Routine Description:\r
285\r
6c31fdb8 286 This function registers the PCI IO device. It creates a handle for this PCI IO device\r
e53a7e1b 287 (if the handle does not exist), attaches appropriate protocols onto the handle, does\r
288 necessary initialization, and sets up parent/child relationship with its bus controller.\r
878ddf1f 289\r
290Arguments:\r
291\r
e53a7e1b 292 Controller - An EFI handle for the PCI bus controller.\r
293 PciIoDevice - A PCI_IO_DEVICE pointer to the PCI IO device to be registered.\r
294 Handle - A pointer to hold the EFI handle for the PCI IO device.\r
878ddf1f 295\r
296Returns:\r
297\r
e53a7e1b 298 EFI_SUCCESS - The PCI device is successfully registered.\r
299 Others - An error occurred when registering the PCI device.\r
878ddf1f 300\r
301--*/\r
878ddf1f 302{\r
303 EFI_STATUS Status;\r
304 VOID *PlatformOpRomBuffer;\r
305 UINTN PlatformOpRomSize;\r
306 UINT8 PciExpressCapRegOffset;\r
307 EFI_PCI_IO_PROTOCOL *PciIo;\r
e53a7e1b 308 UINT8 Data8;\r
878ddf1f 309\r
310 //\r
311 // Install the pciio protocol, device path protocol\r
312 //\r
313 Status = gBS->InstallMultipleProtocolInterfaces (\r
314 &PciIoDevice->Handle,\r
315 &gEfiDevicePathProtocolGuid,\r
316 PciIoDevice->DevicePath,\r
317 &gEfiPciIoProtocolGuid,\r
318 &PciIoDevice->PciIo,\r
319 NULL\r
320 );\r
321 if (EFI_ERROR (Status)) {\r
322 return Status;\r
323 }\r
324\r
325 //\r
326 // Detect if PCI Express Device\r
327 //\r
328 PciExpressCapRegOffset = 0;\r
329 Status = LocateCapabilityRegBlock (\r
e53a7e1b 330 PciIoDevice,\r
331 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
332 &PciExpressCapRegOffset,\r
333 NULL\r
334 );\r
878ddf1f 335 if (!EFI_ERROR (Status)) {\r
336 PciIoDevice->IsPciExp = TRUE;\r
337 }\r
6c31fdb8 338\r
878ddf1f 339 //\r
e53a7e1b 340 // Force Interrupt line to "Unknown" or "No Connection"\r
6c31fdb8 341 // based on the PCI spec, the Interrupt line for x86 should be set as 0xFF for unknown.\r
878ddf1f 342 //\r
343 PciIo = &(PciIoDevice->PciIo);\r
6c31fdb8 344#ifndef MDE_CPU_IPF\r
e53a7e1b 345 Data8 = PCI_INT_LINE_UNKNOWN;\r
6c31fdb8 346#else\r
347 Data8 = 0;\r
348#endif\r
e53a7e1b 349 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
350\r
878ddf1f 351 //\r
352 // Process Platform OpRom\r
353 //\r
354 if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) {\r
355 PciIoDevice->AllOpRomProcessed = TRUE;\r
356\r
357 Status = gPciPlatformProtocol->GetPciRom (\r
e53a7e1b 358 gPciPlatformProtocol,\r
359 PciIoDevice->Handle,\r
360 &PlatformOpRomBuffer,\r
361 &PlatformOpRomSize\r
362 );\r
878ddf1f 363\r
364 if (!EFI_ERROR (Status)) {\r
365\r
366 //\r
367 // Have Platform OpRom\r
368 //\r
369 PciIoDevice->RomSize = PlatformOpRomSize;\r
370 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
371 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
372\r
373 //\r
374 // Process Image\r
375 //\r
376 ProcessOpRomImage (PciIoDevice);\r
377 }\r
378 }\r
379\r
380 if (PciIoDevice->BusOverride) {\r
381 //\r
382 // Install BusSpecificDriverOverride Protocol\r
383 //\r
384 Status = gBS->InstallMultipleProtocolInterfaces (\r
385 &PciIoDevice->Handle,\r
386 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
387 &PciIoDevice->PciDriverOverride,\r
388 NULL\r
389 );\r
390 if (EFI_ERROR (Status)) {\r
391 gBS->UninstallMultipleProtocolInterfaces (\r
e53a7e1b 392 &PciIoDevice->Handle,\r
393 &gEfiDevicePathProtocolGuid,\r
394 PciIoDevice->DevicePath,\r
395 &gEfiPciIoProtocolGuid,\r
396 &PciIoDevice->PciIo,\r
397 NULL\r
398 );\r
878ddf1f 399\r
400 return Status;\r
401 }\r
402 }\r
403\r
404 Status = gBS->OpenProtocol (\r
405 Controller,\r
406 &gEfiPciRootBridgeIoProtocolGuid,\r
407 (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
408 gPciBusDriverBinding.DriverBindingHandle,\r
409 PciIoDevice->Handle,\r
410 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
411 );\r
412 if (EFI_ERROR (Status)) {\r
413 return Status;\r
414 }\r
415\r
416 //\r
417 // Install Pccard Hotplug GUID for Pccard device so that\r
418 // to notify CardBus driver to stop the device when de-register happens\r
419 //\r
420 InstallPciHotplugGuid (PciIoDevice);\r
421\r
422 if (Handle != NULL) {\r
423 *Handle = PciIoDevice->Handle;\r
424 }\r
425\r
426 //\r
427 // Indicate the pci device is registered\r
428 //\r
429 PciIoDevice->Registered = TRUE;\r
430\r
431 return EFI_SUCCESS;\r
432}\r
433\r
434EFI_STATUS\r
435RemoveAllPciDeviceOnBridge (\r
436 EFI_HANDLE RootBridgeHandle,\r
437 PCI_IO_DEVICE *Bridge\r
438 )\r
439/*++\r
440\r
441Routine Description:\r
442\r
443 This function is used to remove the whole PCI devices from the bridge.\r
6c31fdb8 444\r
878ddf1f 445Arguments:\r
446\r
447 RootBridgeHandle - An efi handle.\r
448 Bridge - A pointer to the PCI_IO_DEVICE.\r
449\r
450Returns:\r
451\r
452 None\r
453\r
454--*/\r
455// TODO: EFI_SUCCESS - add return value to function comment\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
6c31fdb8 473\r
878ddf1f 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 return EFI_SUCCESS;\r
487}\r
488\r
489EFI_STATUS\r
490DeRegisterPciDevice (\r
491 IN EFI_HANDLE Controller,\r
492 IN EFI_HANDLE Handle\r
493 )\r
494/*++\r
495\r
496Routine Description:\r
497\r
498 This function is used to de-register the PCI device from the EFI,\r
6c31fdb8 499 That includes un-installing PciIo protocol from the specified PCI\r
878ddf1f 500 device handle.\r
501\r
502Arguments:\r
503\r
504 Controller - An efi handle.\r
505 Handle - An efi handle.\r
506\r
507Returns:\r
508\r
509 None\r
510\r
511--*/\r
512// TODO: EFI_SUCCESS - add return value to function comment\r
513// TODO: EFI_SUCCESS - add return value to function comment\r
514// TODO: EFI_SUCCESS - add return value to function comment\r
515{\r
516 EFI_PCI_IO_PROTOCOL *PciIo;\r
517 EFI_STATUS Status;\r
518 PCI_IO_DEVICE *PciIoDevice;\r
519 PCI_IO_DEVICE *Node;\r
520 LIST_ENTRY *CurrentLink;\r
521 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
522\r
523 Status = gBS->OpenProtocol (\r
524 Handle,\r
525 &gEfiPciIoProtocolGuid,\r
526 (VOID **) &PciIo,\r
527 gPciBusDriverBinding.DriverBindingHandle,\r
528 Controller,\r
529 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
530 );\r
531 if (!EFI_ERROR (Status)) {\r
532 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
533\r
534 //\r
535 // If it is already de-registered\r
536 //\r
537 if (!PciIoDevice->Registered) {\r
538 return EFI_SUCCESS;\r
539 }\r
540\r
541 //\r
542 // If it is PPB, first de-register its children\r
543 //\r
544\r
545 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
546\r
547 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
548\r
549 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
550 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
551 Status = DeRegisterPciDevice (Controller, Node->Handle);\r
552\r
553 if (EFI_ERROR (Status)) {\r
554 return Status;\r
555 }\r
556\r
557 CurrentLink = CurrentLink->ForwardLink;\r
558 }\r
559 }\r
560 //\r
561 // Uninstall Pccard Hotplug GUID for Pccard device\r
562 //\r
563 UninstallPciHotplugGuid (PciIoDevice);\r
564\r
565 //\r
566 // Close the child handle\r
567 //\r
568 Status = gBS->CloseProtocol (\r
569 Controller,\r
570 &gEfiPciRootBridgeIoProtocolGuid,\r
571 gPciBusDriverBinding.DriverBindingHandle,\r
572 Handle\r
573 );\r
574\r
575 //\r
576 // Un-install the device path protocol and pci io protocol\r
577 //\r
578 if (PciIoDevice->BusOverride) {\r
579 Status = gBS->UninstallMultipleProtocolInterfaces (\r
580 Handle,\r
581 &gEfiDevicePathProtocolGuid,\r
582 PciIoDevice->DevicePath,\r
583 &gEfiPciIoProtocolGuid,\r
584 &PciIoDevice->PciIo,\r
585 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
586 &PciIoDevice->PciDriverOverride,\r
587 NULL\r
588 );\r
589 } else {\r
590 Status = gBS->UninstallMultipleProtocolInterfaces (\r
591 Handle,\r
592 &gEfiDevicePathProtocolGuid,\r
593 PciIoDevice->DevicePath,\r
594 &gEfiPciIoProtocolGuid,\r
595 &PciIoDevice->PciIo,\r
596 NULL\r
597 );\r
598 }\r
599\r
600 if (EFI_ERROR (Status)) {\r
601 gBS->OpenProtocol (\r
602 Controller,\r
603 &gEfiPciRootBridgeIoProtocolGuid,\r
604 (VOID **) &PciRootBridgeIo,\r
605 gPciBusDriverBinding.DriverBindingHandle,\r
606 Handle,\r
607 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
608 );\r
609 return Status;\r
610 }\r
6c31fdb8 611\r
878ddf1f 612 //\r
613 // The Device Driver should disable this device after disconnect\r
614 // so the Pci Bus driver will not touch this device any more.\r
615 // Restore the register field to the original value\r
616 //\r
617 PciIoDevice->Registered = FALSE;\r
618 PciIoDevice->Handle = NULL;\r
619 } else {\r
620\r
621 //\r
622 // Handle may be closed before\r
623 //\r
624 return EFI_SUCCESS;\r
625 }\r
626\r
627 return EFI_SUCCESS;\r
628}\r
629\r
630EFI_STATUS\r
631StartPciDevicesOnBridge (\r
632 IN EFI_HANDLE Controller,\r
633 IN PCI_IO_DEVICE *RootBridge,\r
634 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
635 IN OUT UINT8 *NumberOfChildren,\r
636 IN OUT EFI_HANDLE *ChildHandleBuffer\r
637 )\r
638/*++\r
639\r
640Routine Description:\r
641\r
642 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
643\r
644Arguments:\r
645\r
646 Controller - An efi handle.\r
647 RootBridge - A pointer to the PCI_IO_DEVICE.\r
648 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
649 NumberOfChildren - Children number.\r
650 ChildHandleBuffer - A pointer to the child handle buffer.\r
651\r
652Returns:\r
653\r
654 None\r
655\r
656--*/\r
657// TODO: EFI_NOT_READY - add return value to function comment\r
658// TODO: EFI_SUCCESS - add return value to function comment\r
659// TODO: EFI_UNSUPPORTED - add return value to function comment\r
660// TODO: EFI_NOT_FOUND - add return value to function comment\r
661{\r
662 PCI_IO_DEVICE *Temp;\r
663 PCI_IO_DEVICE *PciIoDevice;\r
664 EFI_DEV_PATH_PTR Node;\r
665 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
666 EFI_STATUS Status;\r
667 LIST_ENTRY *CurrentLink;\r
668 UINT64 Supports;\r
669\r
670 CurrentLink = RootBridge->ChildList.ForwardLink;\r
671\r
672 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
673\r
674 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
675 if (RemainingDevicePath != NULL) {\r
676\r
677 Node.DevPath = RemainingDevicePath;\r
678\r
6c31fdb8 679 if (Node.Pci->Device != Temp->DeviceNumber ||\r
878ddf1f 680 Node.Pci->Function != Temp->FunctionNumber) {\r
681 CurrentLink = CurrentLink->ForwardLink;\r
682 continue;\r
683 }\r
684\r
685 //\r
686 // Check if the device has been assigned with required resource\r
687 //\r
688 if (!Temp->Allocated) {\r
689 return EFI_NOT_READY;\r
690 }\r
6c31fdb8 691\r
878ddf1f 692 //\r
693 // Check if the current node has been registered before\r
694 // If it is not, register it\r
695 //\r
696 if (!Temp->Registered) {\r
697 PciIoDevice = Temp;\r
698\r
699 Status = RegisterPciDevice (\r
700 Controller,\r
701 PciIoDevice,\r
702 NULL\r
703 );\r
704\r
705 }\r
706\r
707 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
708 ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
709 (*NumberOfChildren)++;\r
710 }\r
6c31fdb8 711\r
878ddf1f 712 //\r
713 // Get the next device path\r
714 //\r
715 CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);\r
716 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
717 return EFI_SUCCESS;\r
718 }\r
6c31fdb8 719\r
878ddf1f 720 //\r
721 // If it is a PPB\r
722 //\r
723 if (!IsListEmpty (&Temp->ChildList)) {\r
724 Status = StartPciDevicesOnBridge (\r
725 Controller,\r
726 Temp,\r
727 CurrentDevicePath,\r
728 NumberOfChildren,\r
729 ChildHandleBuffer\r
730 );\r
731\r
732 Temp->PciIo.Attributes (\r
733 &(Temp->PciIo),\r
734 EfiPciIoAttributeOperationSupported,\r
735 0,\r
736 &Supports\r
737 );\r
738 Supports &= EFI_PCI_DEVICE_ENABLE;\r
739 Temp->PciIo.Attributes (\r
740 &(Temp->PciIo),\r
741 EfiPciIoAttributeOperationEnable,\r
742 Supports,\r
743 NULL\r
744 );\r
745\r
746 return Status;\r
747 } else {\r
748\r
749 //\r
750 // Currently, the PCI bus driver only support PCI-PCI bridge\r
751 //\r
752 return EFI_UNSUPPORTED;\r
753 }\r
754\r
755 } else {\r
756\r
757 //\r
758 // If remaining device path is NULL,\r
759 // try to enable all the pci devices under this bridge\r
760 //\r
761\r
762 if (!Temp->Registered && Temp->Allocated) {\r
763\r
764 PciIoDevice = Temp;\r
765\r
766 Status = RegisterPciDevice (\r
767 Controller,\r
768 PciIoDevice,\r
769 NULL\r
770 );\r
771\r
772 }\r
773\r
774 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
775 ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
776 (*NumberOfChildren)++;\r
777 }\r
778\r
779 if (!IsListEmpty (&Temp->ChildList)) {\r
780 Status = StartPciDevicesOnBridge (\r
781 Controller,\r
782 Temp,\r
783 RemainingDevicePath,\r
784 NumberOfChildren,\r
785 ChildHandleBuffer\r
786 );\r
787\r
788 Temp->PciIo.Attributes (\r
789 &(Temp->PciIo),\r
790 EfiPciIoAttributeOperationSupported,\r
791 0,\r
792 &Supports\r
793 );\r
794 Supports &= EFI_PCI_DEVICE_ENABLE;\r
795 Temp->PciIo.Attributes (\r
796 &(Temp->PciIo),\r
797 EfiPciIoAttributeOperationEnable,\r
798 Supports,\r
799 NULL\r
800 );\r
801\r
802 }\r
803\r
804 CurrentLink = CurrentLink->ForwardLink;\r
805 continue;\r
806 }\r
807 }\r
808\r
809 return EFI_NOT_FOUND;\r
810}\r
811\r
812EFI_STATUS\r
813StartPciDevices (\r
814 IN EFI_HANDLE Controller,\r
815 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
816 )\r
817/*++\r
818\r
819Routine Description:\r
820\r
821 Start to manage the PCI device according to RemainingDevicePath\r
6c31fdb8 822 If RemainingDevicePath == NULL, the PCI bus driver will start\r
878ddf1f 823 to manage all the PCI devices it found previously\r
824\r
825Arguments:\r
826 Controller - An efi handle.\r
827 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
828\r
829Returns:\r
830\r
831 None\r
832\r
833--*/\r
834// TODO: EFI_UNSUPPORTED - add return value to function comment\r
835// TODO: EFI_SUCCESS - add return value to function comment\r
836{\r
837 EFI_DEV_PATH_PTR Node;\r
838 PCI_IO_DEVICE *RootBridge;\r
839 LIST_ENTRY *CurrentLink;\r
840\r
841 if (RemainingDevicePath != NULL) {\r
842\r
843 //\r
844 // Check if the RemainingDevicePath is valid\r
845 //\r
846 Node.DevPath = RemainingDevicePath;\r
847 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
848 ((Node.DevPath->SubType != HW_PCI_DP) &&\r
849 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))\r
850 ) {\r
851 return EFI_UNSUPPORTED;\r
852 }\r
853 }\r
854\r
855 CurrentLink = gPciDevicePool.ForwardLink;\r
856\r
857 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
858\r
859 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
860 //\r
861 // Locate the right root bridge to start\r
862 //\r
863 if (RootBridge->Handle == Controller) {\r
864 StartPciDevicesOnBridge (\r
865 Controller,\r
866 RootBridge,\r
867 RemainingDevicePath,\r
868 NULL,\r
869 NULL\r
870 );\r
871 }\r
872\r
873 CurrentLink = CurrentLink->ForwardLink;\r
874 }\r
875\r
876 return EFI_SUCCESS;\r
877}\r
878\r
879PCI_IO_DEVICE *\r
880CreateRootBridge (\r
881 IN EFI_HANDLE RootBridgeHandle\r
882 )\r
883/*++\r
884\r
885Routine Description:\r
886\r
887\r
888Arguments:\r
889 RootBridgeHandle - An efi handle.\r
890\r
891Returns:\r
892\r
893 None\r
894\r
895--*/\r
896{\r
897\r
898 EFI_STATUS Status;\r
899 PCI_IO_DEVICE *Dev;\r
900 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
901 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
902\r
903 Dev = NULL;\r
904 Status = gBS->AllocatePool (\r
905 EfiBootServicesData,\r
906 sizeof (PCI_IO_DEVICE),\r
907 (VOID **) &Dev\r
908 );\r
909\r
910 if (EFI_ERROR (Status)) {\r
911 return NULL;\r
912 }\r
913\r
914 ZeroMem (Dev, sizeof (PCI_IO_DEVICE));\r
915 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
916 Dev->Handle = RootBridgeHandle;\r
917 InitializeListHead (&Dev->ChildList);\r
918\r
919 Status = gBS->OpenProtocol (\r
920 RootBridgeHandle,\r
921 &gEfiDevicePathProtocolGuid,\r
922 (VOID **) &ParentDevicePath,\r
923 gPciBusDriverBinding.DriverBindingHandle,\r
924 RootBridgeHandle,\r
925 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
926 );\r
927\r
928 if (EFI_ERROR (Status)) {\r
929 gBS->FreePool (Dev);\r
930 return NULL;\r
931 }\r
932\r
933 //\r
934 // Record the root bridge parent device path\r
935 //\r
936 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
937\r
938 //\r
939 // Get the pci root bridge io protocol\r
940 //\r
941 Status = gBS->OpenProtocol (\r
942 RootBridgeHandle,\r
943 &gEfiPciRootBridgeIoProtocolGuid,\r
944 (VOID **) &PciRootBridgeIo,\r
945 gPciBusDriverBinding.DriverBindingHandle,\r
946 RootBridgeHandle,\r
947 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
948 );\r
949\r
950 if (EFI_ERROR (Status)) {\r
951 FreePciDevice (Dev);\r
952 return NULL;\r
953 }\r
954\r
955 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
956\r
957 //\r
958 // Initialize the PCI I/O instance structure\r
959 //\r
960 Status = InitializePciIoInstance (Dev);\r
961 Status = InitializePciDriverOverrideInstance (Dev);\r
962\r
963 //\r
964 // Initialize reserved resource list and\r
965 // option rom driver list\r
966 //\r
967 InitializeListHead (&Dev->ReservedResourceList);\r
968 InitializeListHead (&Dev->OptionRomDriverList);\r
969\r
970 return Dev;\r
971}\r
972\r
973PCI_IO_DEVICE *\r
974GetRootBridgeByHandle (\r
975 EFI_HANDLE RootBridgeHandle\r
976 )\r
977/*++\r
978\r
979Routine Description:\r
980\r
981\r
982Arguments:\r
983\r
984 RootBridgeHandle - An efi handle.\r
985\r
986Returns:\r
987\r
988 None\r
989\r
990--*/\r
991{\r
992 PCI_IO_DEVICE *RootBridgeDev;\r
993 LIST_ENTRY *CurrentLink;\r
994\r
995 CurrentLink = gPciDevicePool.ForwardLink;\r
996\r
997 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
998\r
999 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1000 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
1001 return RootBridgeDev;\r
1002 }\r
1003\r
1004 CurrentLink = CurrentLink->ForwardLink;\r
1005 }\r
1006\r
1007 return NULL;\r
1008}\r
1009\r
1010BOOLEAN\r
1011RootBridgeExisted (\r
1012 IN EFI_HANDLE RootBridgeHandle\r
1013 )\r
1014/*++\r
1015\r
1016Routine Description:\r
1017\r
1018 This function searches if RootBridgeHandle has already existed\r
1019 in current device pool.\r
1020\r
1021 If so, it means the given root bridge has been already enumerated.\r
1022\r
1023Arguments:\r
1024\r
1025 RootBridgeHandle - An efi handle.\r
1026\r
1027Returns:\r
1028\r
1029 None\r
1030\r
1031--*/\r
1032{\r
1033 PCI_IO_DEVICE *Bridge;\r
1034\r
1035 Bridge = GetRootBridgeByHandle (RootBridgeHandle);\r
1036\r
1037 if (Bridge != NULL) {\r
1038 return TRUE;\r
1039 }\r
1040\r
1041 return FALSE;\r
1042}\r
1043\r
1044BOOLEAN\r
1045PciDeviceExisted (\r
1046 IN PCI_IO_DEVICE *Bridge,\r
1047 IN PCI_IO_DEVICE *PciIoDevice\r
1048 )\r
1049/*++\r
1050\r
1051Routine Description:\r
6c31fdb8 1052\r
878ddf1f 1053Arguments:\r
1054\r
1055 Bridge - A pointer to the PCI_IO_DEVICE.\r
1056 PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
1057\r
1058Returns:\r
1059\r
1060 None\r
1061\r
1062--*/\r
1063{\r
1064\r
1065 PCI_IO_DEVICE *Temp;\r
1066 LIST_ENTRY *CurrentLink;\r
1067\r
1068 CurrentLink = Bridge->ChildList.ForwardLink;\r
1069\r
1070 while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
1071\r
1072 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1073\r
1074 if (Temp == PciIoDevice) {\r
1075 return TRUE;\r
1076 }\r
1077\r
1078 if (!IsListEmpty (&Temp->ChildList)) {\r
1079 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
1080 return TRUE;\r
1081 }\r
1082 }\r
1083\r
1084 CurrentLink = CurrentLink->ForwardLink;\r
1085 }\r
1086\r
1087 return FALSE;\r
1088}\r
1089\r
1090PCI_IO_DEVICE *\r
1091ActiveVGADeviceOnTheSameSegment (\r
1092 IN PCI_IO_DEVICE *VgaDevice\r
1093 )\r
1094/*++\r
1095\r
1096Routine Description:\r
1097\r
1098Arguments:\r
1099\r
1100 VgaDevice - A pointer to the PCI_IO_DEVICE.\r
6c31fdb8 1101\r
878ddf1f 1102Returns:\r
1103\r
1104 None\r
1105\r
1106--*/\r
1107{\r
1108 LIST_ENTRY *CurrentLink;\r
1109 PCI_IO_DEVICE *Temp;\r
1110\r
1111 CurrentLink = gPciDevicePool.ForwardLink;\r
1112\r
1113 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
1114\r
1115 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1116\r
1117 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
1118\r
1119 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1120\r
1121 if (Temp != NULL) {\r
1122 return Temp;\r
1123 }\r
1124 }\r
1125\r
1126 CurrentLink = CurrentLink->ForwardLink;\r
1127 }\r
1128\r
1129 return NULL;\r
1130}\r
1131\r
1132PCI_IO_DEVICE *\r
1133ActiveVGADeviceOnTheRootBridge (\r
1134 IN PCI_IO_DEVICE *RootBridge\r
1135 )\r
1136/*++\r
1137\r
1138Routine Description:\r
1139\r
1140Arguments:\r
1141\r
1142 RootBridge - A pointer to the PCI_IO_DEVICE.\r
1143\r
1144Returns:\r
1145\r
1146 None\r
1147\r
1148--*/\r
1149{\r
1150 LIST_ENTRY *CurrentLink;\r
1151 PCI_IO_DEVICE *Temp;\r
1152\r
1153 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1154\r
1155 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
1156\r
1157 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1158\r
6c31fdb8 1159 if (IS_PCI_VGA(&Temp->Pci) &&\r
c51cec25 1160 (Temp->Attributes &\r
1161 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1162 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
1163 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {\r
878ddf1f 1164 return Temp;\r
1165 }\r
1166\r
1167 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1168\r
1169 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1170\r
1171 if (Temp != NULL) {\r
1172 return Temp;\r
1173 }\r
1174 }\r
1175\r
1176 CurrentLink = CurrentLink->ForwardLink;\r
1177 }\r
1178\r
1179 return NULL;\r
1180}\r
1181\r
1182EFI_STATUS\r
1183GetHpcPciAddress (\r
1184 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
1185 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
1186 OUT UINT64 *PciAddress\r
1187 )\r
1188/*++\r
1189\r
1190Routine Description:\r
1191\r
1192Arguments:\r
1193\r
1194 PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1195 HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
1196 PciAddress - A pointer to the pci address.\r
6c31fdb8 1197\r
878ddf1f 1198Returns:\r
1199\r
1200 None\r
1201\r
1202--*/\r
1203// TODO: EFI_NOT_FOUND - add return value to function comment\r
1204// TODO: EFI_NOT_FOUND - add return value to function comment\r
1205// TODO: EFI_SUCCESS - add return value to function comment\r
1206// TODO: EFI_NOT_FOUND - add return value to function comment\r
1207{\r
1208 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1209 EFI_DEV_PATH_PTR Node;\r
1210 LIST_ENTRY *CurrentLink;\r
1211 PCI_IO_DEVICE *RootBridge;\r
1212 EFI_STATUS Status;\r
1213\r
1214 CurrentDevicePath = HpcDevicePath;\r
1215\r
1216 //\r
1217 // Get the remaining device path for this PCI device, if it is a PCI device\r
1218 //\r
1219 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1220\r
1221 Node.DevPath = CurrentDevicePath;\r
1222\r
1223 //\r
1224 // Check if it is PCI device Path?\r
1225 //\r
1226 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
1227 ((Node.DevPath->SubType != HW_PCI_DP) &&\r
1228 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {\r
1229 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1230 continue;\r
1231 }\r
1232\r
1233 break;\r
1234 }\r
1235\r
1236 //\r
1237 // Check if it is not PCI device path\r
1238 //\r
1239 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1240 return EFI_NOT_FOUND;\r
1241 }\r
1242\r
1243 CurrentLink = gPciDevicePool.ForwardLink;\r
1244\r
1245 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
1246\r
1247 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1248 //\r
1249 // Locate the right root bridge to start\r
1250 //\r
1251 if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {\r
1252 Status = GetHpcPciAddressFromRootBridge (\r
1253 RootBridge,\r
1254 CurrentDevicePath,\r
1255 PciAddress\r
1256 );\r
1257 if (EFI_ERROR (Status)) {\r
1258 return EFI_NOT_FOUND;\r
1259 }\r
1260\r
1261 return EFI_SUCCESS;\r
1262\r
1263 }\r
1264\r
1265 CurrentLink = CurrentLink->ForwardLink;\r
1266 }\r
1267\r
1268 return EFI_NOT_FOUND;\r
1269}\r
1270\r
1271EFI_STATUS\r
1272GetHpcPciAddressFromRootBridge (\r
1273 IN PCI_IO_DEVICE *RootBridge,\r
1274 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1275 OUT UINT64 *PciAddress\r
1276 )\r
1277/*++\r
1278\r
1279Routine Description:\r
1280\r
1281Arguments:\r
1282\r
1283 PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1284 HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
1285 PciAddress - A pointer to the pci address.\r
1286\r
1287Returns:\r
1288\r
1289 None\r
1290\r
1291--*/\r
1292// TODO: RootBridge - add argument and description to function comment\r
1293// TODO: RemainingDevicePath - add argument and description to function comment\r
1294// TODO: EFI_SUCCESS - add return value to function comment\r
1295// TODO: EFI_NOT_FOUND - add return value to function comment\r
1296// TODO: EFI_SUCCESS - add return value to function comment\r
1297{\r
1298 EFI_DEV_PATH_PTR Node;\r
1299 PCI_IO_DEVICE *Temp;\r
1300 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1301 LIST_ENTRY *CurrentLink;\r
1302 BOOLEAN MisMatch;\r
1303\r
1304 MisMatch = FALSE;\r
1305\r
1306 CurrentDevicePath = RemainingDevicePath;\r
1307 Node.DevPath = CurrentDevicePath;\r
1308 Temp = NULL;\r
1309\r
1310 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1311\r
1312 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1313 Node.DevPath = CurrentDevicePath;\r
1314\r
1315 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
1316 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1317\r
1318 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1319 Node.Pci->Function == Temp->FunctionNumber) {\r
1320 RootBridge = Temp;\r
1321 break;\r
1322 }\r
1323\r
1324 CurrentLink = CurrentLink->ForwardLink;\r
1325 }\r
1326\r
1327 //\r
1328 // Check if we find the bridge\r
1329 //\r
1330 if (CurrentLink == &RootBridge->ChildList) {\r
1331\r
1332 MisMatch = TRUE;\r
1333 break;\r
1334\r
1335 }\r
1336\r
1337 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1338 }\r
1339\r
1340 if (MisMatch) {\r
1341\r
1342 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1343\r
1344 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1345 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1346 return EFI_SUCCESS;\r
1347 }\r
1348\r
1349 return EFI_NOT_FOUND;\r
1350 }\r
1351\r
1352 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1353\r
1354 return EFI_SUCCESS;\r
1355\r
1356}\r