]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c
• BaseMemoryLib:
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / PciBus / Dxe / PciDeviceSupport.c
CommitLineData
878ddf1f 1/*++\r
2\r
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
11\r
12Module Name:\r
13\r
14 PciDeviceSupport.c\r
15 \r
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
122 \r
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
150 Also all direct or indirect allocated resource for this node will be freed. \r
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
235 specified by Controller. \r
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
286 This function is used to register the PCI device to the EFI,\r
287 create a handle for this PCI device,then attach apporpriate protocols\r
288 onto the handle.\r
289\r
290Arguments:\r
291\r
292 Controller - An efi handle.\r
293 PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
294 Handle - A pointer to a efi handle.\r
295\r
296Returns:\r
297\r
298 None\r
299\r
300--*/\r
301// TODO: EFI_SUCCESS - add return value to function comment\r
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
308\r
309 //\r
310 // Install the pciio protocol, device path protocol\r
311 //\r
312 Status = gBS->InstallMultipleProtocolInterfaces (\r
313 &PciIoDevice->Handle,\r
314 &gEfiDevicePathProtocolGuid,\r
315 PciIoDevice->DevicePath,\r
316 &gEfiPciIoProtocolGuid,\r
317 &PciIoDevice->PciIo,\r
318 NULL\r
319 );\r
320 if (EFI_ERROR (Status)) {\r
321 return Status;\r
322 }\r
323\r
324 //\r
325 // Detect if PCI Express Device\r
326 //\r
327 PciExpressCapRegOffset = 0;\r
328 Status = LocateCapabilityRegBlock (\r
329 PciIoDevice,\r
330 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
331 &PciExpressCapRegOffset,\r
332 NULL\r
333 );\r
334 if (!EFI_ERROR (Status)) {\r
335 PciIoDevice->IsPciExp = TRUE;\r
336 }\r
337 \r
338 //\r
339 // Force Interrupt line to zero for cards that come up randomly\r
340 //\r
341 PciIo = &(PciIoDevice->PciIo);\r
342 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
343 //\r
344 // Process Platform OpRom\r
345 //\r
346 if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) {\r
347 PciIoDevice->AllOpRomProcessed = TRUE;\r
348\r
349 Status = gPciPlatformProtocol->GetPciRom (\r
350 gPciPlatformProtocol,\r
351 PciIoDevice->Handle,\r
352 &PlatformOpRomBuffer,\r
353 &PlatformOpRomSize\r
354 );\r
355\r
356 if (!EFI_ERROR (Status)) {\r
357\r
358 //\r
359 // Have Platform OpRom\r
360 //\r
361 PciIoDevice->RomSize = PlatformOpRomSize;\r
362 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
363 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
364\r
365 //\r
366 // Process Image\r
367 //\r
368 ProcessOpRomImage (PciIoDevice);\r
369 }\r
370 }\r
371\r
372 if (PciIoDevice->BusOverride) {\r
373 //\r
374 // Install BusSpecificDriverOverride Protocol\r
375 //\r
376 Status = gBS->InstallMultipleProtocolInterfaces (\r
377 &PciIoDevice->Handle,\r
378 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
379 &PciIoDevice->PciDriverOverride,\r
380 NULL\r
381 );\r
382 if (EFI_ERROR (Status)) {\r
383 gBS->UninstallMultipleProtocolInterfaces (\r
384 &PciIoDevice->Handle,\r
385 &gEfiDevicePathProtocolGuid,\r
386 PciIoDevice->DevicePath,\r
387 &gEfiPciIoProtocolGuid,\r
388 &PciIoDevice->PciIo,\r
389 NULL\r
390 );\r
391\r
392 return Status;\r
393 }\r
394 }\r
395\r
396 Status = gBS->OpenProtocol (\r
397 Controller,\r
398 &gEfiPciRootBridgeIoProtocolGuid,\r
399 (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
400 gPciBusDriverBinding.DriverBindingHandle,\r
401 PciIoDevice->Handle,\r
402 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
403 );\r
404 if (EFI_ERROR (Status)) {\r
405 return Status;\r
406 }\r
407\r
408 //\r
409 // Install Pccard Hotplug GUID for Pccard device so that\r
410 // to notify CardBus driver to stop the device when de-register happens\r
411 //\r
412 InstallPciHotplugGuid (PciIoDevice);\r
413\r
414 if (Handle != NULL) {\r
415 *Handle = PciIoDevice->Handle;\r
416 }\r
417\r
418 //\r
419 // Indicate the pci device is registered\r
420 //\r
421 PciIoDevice->Registered = TRUE;\r
422\r
423 return EFI_SUCCESS;\r
424}\r
425\r
426EFI_STATUS\r
427RemoveAllPciDeviceOnBridge (\r
428 EFI_HANDLE RootBridgeHandle,\r
429 PCI_IO_DEVICE *Bridge\r
430 )\r
431/*++\r
432\r
433Routine Description:\r
434\r
435 This function is used to remove the whole PCI devices from the bridge.\r
436 \r
437Arguments:\r
438\r
439 RootBridgeHandle - An efi handle.\r
440 Bridge - A pointer to the PCI_IO_DEVICE.\r
441\r
442Returns:\r
443\r
444 None\r
445\r
446--*/\r
447// TODO: EFI_SUCCESS - add return value to function comment\r
448{\r
449\r
450 LIST_ENTRY *CurrentLink;\r
451 PCI_IO_DEVICE *Temp;\r
452\r
453 while (!IsListEmpty (&Bridge->ChildList)) {\r
454\r
455 CurrentLink = Bridge->ChildList.ForwardLink;\r
456 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
457\r
458 //\r
459 // Check if the current node has been deregistered before\r
460 // If it is not, then deregister it\r
461 //\r
462 if (Temp->Registered) {\r
463 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
464 }\r
465 \r
466 //\r
467 // Remove this node from the linked list\r
468 //\r
469 RemoveEntryList (CurrentLink);\r
470\r
471 if (!IsListEmpty (&Temp->ChildList)) {\r
472 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
473 }\r
474\r
475 FreePciDevice (Temp);\r
476 }\r
477\r
478 return EFI_SUCCESS;\r
479}\r
480\r
481EFI_STATUS\r
482DeRegisterPciDevice (\r
483 IN EFI_HANDLE Controller,\r
484 IN EFI_HANDLE Handle\r
485 )\r
486/*++\r
487\r
488Routine Description:\r
489\r
490 This function is used to de-register the PCI device from the EFI,\r
491 That includes un-installing PciIo protocol from the specified PCI \r
492 device handle.\r
493\r
494Arguments:\r
495\r
496 Controller - An efi handle.\r
497 Handle - An efi handle.\r
498\r
499Returns:\r
500\r
501 None\r
502\r
503--*/\r
504// TODO: EFI_SUCCESS - add return value to function comment\r
505// TODO: EFI_SUCCESS - add return value to function comment\r
506// TODO: EFI_SUCCESS - add return value to function comment\r
507{\r
508 EFI_PCI_IO_PROTOCOL *PciIo;\r
509 EFI_STATUS Status;\r
510 PCI_IO_DEVICE *PciIoDevice;\r
511 PCI_IO_DEVICE *Node;\r
512 LIST_ENTRY *CurrentLink;\r
513 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
514\r
515 Status = gBS->OpenProtocol (\r
516 Handle,\r
517 &gEfiPciIoProtocolGuid,\r
518 (VOID **) &PciIo,\r
519 gPciBusDriverBinding.DriverBindingHandle,\r
520 Controller,\r
521 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
522 );\r
523 if (!EFI_ERROR (Status)) {\r
524 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
525\r
526 //\r
527 // If it is already de-registered\r
528 //\r
529 if (!PciIoDevice->Registered) {\r
530 return EFI_SUCCESS;\r
531 }\r
532\r
533 //\r
534 // If it is PPB, first de-register its children\r
535 //\r
536\r
537 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
538\r
539 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
540\r
541 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
542 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
543 Status = DeRegisterPciDevice (Controller, Node->Handle);\r
544\r
545 if (EFI_ERROR (Status)) {\r
546 return Status;\r
547 }\r
548\r
549 CurrentLink = CurrentLink->ForwardLink;\r
550 }\r
551 }\r
552 //\r
553 // Uninstall Pccard Hotplug GUID for Pccard device\r
554 //\r
555 UninstallPciHotplugGuid (PciIoDevice);\r
556\r
557 //\r
558 // Close the child handle\r
559 //\r
560 Status = gBS->CloseProtocol (\r
561 Controller,\r
562 &gEfiPciRootBridgeIoProtocolGuid,\r
563 gPciBusDriverBinding.DriverBindingHandle,\r
564 Handle\r
565 );\r
566\r
567 //\r
568 // Un-install the device path protocol and pci io protocol\r
569 //\r
570 if (PciIoDevice->BusOverride) {\r
571 Status = gBS->UninstallMultipleProtocolInterfaces (\r
572 Handle,\r
573 &gEfiDevicePathProtocolGuid,\r
574 PciIoDevice->DevicePath,\r
575 &gEfiPciIoProtocolGuid,\r
576 &PciIoDevice->PciIo,\r
577 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
578 &PciIoDevice->PciDriverOverride,\r
579 NULL\r
580 );\r
581 } else {\r
582 Status = gBS->UninstallMultipleProtocolInterfaces (\r
583 Handle,\r
584 &gEfiDevicePathProtocolGuid,\r
585 PciIoDevice->DevicePath,\r
586 &gEfiPciIoProtocolGuid,\r
587 &PciIoDevice->PciIo,\r
588 NULL\r
589 );\r
590 }\r
591\r
592 if (EFI_ERROR (Status)) {\r
593 gBS->OpenProtocol (\r
594 Controller,\r
595 &gEfiPciRootBridgeIoProtocolGuid,\r
596 (VOID **) &PciRootBridgeIo,\r
597 gPciBusDriverBinding.DriverBindingHandle,\r
598 Handle,\r
599 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
600 );\r
601 return Status;\r
602 }\r
603 \r
604 //\r
605 // The Device Driver should disable this device after disconnect\r
606 // so the Pci Bus driver will not touch this device any more.\r
607 // Restore the register field to the original value\r
608 //\r
609 PciIoDevice->Registered = FALSE;\r
610 PciIoDevice->Handle = NULL;\r
611 } else {\r
612\r
613 //\r
614 // Handle may be closed before\r
615 //\r
616 return EFI_SUCCESS;\r
617 }\r
618\r
619 return EFI_SUCCESS;\r
620}\r
621\r
622EFI_STATUS\r
623StartPciDevicesOnBridge (\r
624 IN EFI_HANDLE Controller,\r
625 IN PCI_IO_DEVICE *RootBridge,\r
626 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
627 IN OUT UINT8 *NumberOfChildren,\r
628 IN OUT EFI_HANDLE *ChildHandleBuffer\r
629 )\r
630/*++\r
631\r
632Routine Description:\r
633\r
634 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
635\r
636Arguments:\r
637\r
638 Controller - An efi handle.\r
639 RootBridge - A pointer to the PCI_IO_DEVICE.\r
640 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
641 NumberOfChildren - Children number.\r
642 ChildHandleBuffer - A pointer to the child handle buffer.\r
643\r
644Returns:\r
645\r
646 None\r
647\r
648--*/\r
649// TODO: EFI_NOT_READY - add return value to function comment\r
650// TODO: EFI_SUCCESS - add return value to function comment\r
651// TODO: EFI_UNSUPPORTED - add return value to function comment\r
652// TODO: EFI_NOT_FOUND - add return value to function comment\r
653{\r
654 PCI_IO_DEVICE *Temp;\r
655 PCI_IO_DEVICE *PciIoDevice;\r
656 EFI_DEV_PATH_PTR Node;\r
657 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
658 EFI_STATUS Status;\r
659 LIST_ENTRY *CurrentLink;\r
660 UINT64 Supports;\r
661\r
662 CurrentLink = RootBridge->ChildList.ForwardLink;\r
663\r
664 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
665\r
666 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
667 if (RemainingDevicePath != NULL) {\r
668\r
669 Node.DevPath = RemainingDevicePath;\r
670\r
671 if (Node.Pci->Device != Temp->DeviceNumber || \r
672 Node.Pci->Function != Temp->FunctionNumber) {\r
673 CurrentLink = CurrentLink->ForwardLink;\r
674 continue;\r
675 }\r
676\r
677 //\r
678 // Check if the device has been assigned with required resource\r
679 //\r
680 if (!Temp->Allocated) {\r
681 return EFI_NOT_READY;\r
682 }\r
683 \r
684 //\r
685 // Check if the current node has been registered before\r
686 // If it is not, register it\r
687 //\r
688 if (!Temp->Registered) {\r
689 PciIoDevice = Temp;\r
690\r
691 Status = RegisterPciDevice (\r
692 Controller,\r
693 PciIoDevice,\r
694 NULL\r
695 );\r
696\r
697 }\r
698\r
699 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
700 ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
701 (*NumberOfChildren)++;\r
702 }\r
703 \r
704 //\r
705 // Get the next device path\r
706 //\r
707 CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);\r
708 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
709 return EFI_SUCCESS;\r
710 }\r
711 \r
712 //\r
713 // If it is a PPB\r
714 //\r
715 if (!IsListEmpty (&Temp->ChildList)) {\r
716 Status = StartPciDevicesOnBridge (\r
717 Controller,\r
718 Temp,\r
719 CurrentDevicePath,\r
720 NumberOfChildren,\r
721 ChildHandleBuffer\r
722 );\r
723\r
724 Temp->PciIo.Attributes (\r
725 &(Temp->PciIo),\r
726 EfiPciIoAttributeOperationSupported,\r
727 0,\r
728 &Supports\r
729 );\r
730 Supports &= EFI_PCI_DEVICE_ENABLE;\r
731 Temp->PciIo.Attributes (\r
732 &(Temp->PciIo),\r
733 EfiPciIoAttributeOperationEnable,\r
734 Supports,\r
735 NULL\r
736 );\r
737\r
738 return Status;\r
739 } else {\r
740\r
741 //\r
742 // Currently, the PCI bus driver only support PCI-PCI bridge\r
743 //\r
744 return EFI_UNSUPPORTED;\r
745 }\r
746\r
747 } else {\r
748\r
749 //\r
750 // If remaining device path is NULL,\r
751 // try to enable all the pci devices under this bridge\r
752 //\r
753\r
754 if (!Temp->Registered && Temp->Allocated) {\r
755\r
756 PciIoDevice = Temp;\r
757\r
758 Status = RegisterPciDevice (\r
759 Controller,\r
760 PciIoDevice,\r
761 NULL\r
762 );\r
763\r
764 }\r
765\r
766 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
767 ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
768 (*NumberOfChildren)++;\r
769 }\r
770\r
771 if (!IsListEmpty (&Temp->ChildList)) {\r
772 Status = StartPciDevicesOnBridge (\r
773 Controller,\r
774 Temp,\r
775 RemainingDevicePath,\r
776 NumberOfChildren,\r
777 ChildHandleBuffer\r
778 );\r
779\r
780 Temp->PciIo.Attributes (\r
781 &(Temp->PciIo),\r
782 EfiPciIoAttributeOperationSupported,\r
783 0,\r
784 &Supports\r
785 );\r
786 Supports &= EFI_PCI_DEVICE_ENABLE;\r
787 Temp->PciIo.Attributes (\r
788 &(Temp->PciIo),\r
789 EfiPciIoAttributeOperationEnable,\r
790 Supports,\r
791 NULL\r
792 );\r
793\r
794 }\r
795\r
796 CurrentLink = CurrentLink->ForwardLink;\r
797 continue;\r
798 }\r
799 }\r
800\r
801 return EFI_NOT_FOUND;\r
802}\r
803\r
804EFI_STATUS\r
805StartPciDevices (\r
806 IN EFI_HANDLE Controller,\r
807 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
808 )\r
809/*++\r
810\r
811Routine Description:\r
812\r
813 Start to manage the PCI device according to RemainingDevicePath\r
814 If RemainingDevicePath == NULL, the PCI bus driver will start \r
815 to manage all the PCI devices it found previously\r
816\r
817Arguments:\r
818 Controller - An efi handle.\r
819 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
820\r
821Returns:\r
822\r
823 None\r
824\r
825--*/\r
826// TODO: EFI_UNSUPPORTED - add return value to function comment\r
827// TODO: EFI_SUCCESS - add return value to function comment\r
828{\r
829 EFI_DEV_PATH_PTR Node;\r
830 PCI_IO_DEVICE *RootBridge;\r
831 LIST_ENTRY *CurrentLink;\r
832\r
833 if (RemainingDevicePath != NULL) {\r
834\r
835 //\r
836 // Check if the RemainingDevicePath is valid\r
837 //\r
838 Node.DevPath = RemainingDevicePath;\r
839 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
840 ((Node.DevPath->SubType != HW_PCI_DP) &&\r
841 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))\r
842 ) {\r
843 return EFI_UNSUPPORTED;\r
844 }\r
845 }\r
846\r
847 CurrentLink = gPciDevicePool.ForwardLink;\r
848\r
849 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
850\r
851 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
852 //\r
853 // Locate the right root bridge to start\r
854 //\r
855 if (RootBridge->Handle == Controller) {\r
856 StartPciDevicesOnBridge (\r
857 Controller,\r
858 RootBridge,\r
859 RemainingDevicePath,\r
860 NULL,\r
861 NULL\r
862 );\r
863 }\r
864\r
865 CurrentLink = CurrentLink->ForwardLink;\r
866 }\r
867\r
868 return EFI_SUCCESS;\r
869}\r
870\r
871PCI_IO_DEVICE *\r
872CreateRootBridge (\r
873 IN EFI_HANDLE RootBridgeHandle\r
874 )\r
875/*++\r
876\r
877Routine Description:\r
878\r
879\r
880Arguments:\r
881 RootBridgeHandle - An efi handle.\r
882\r
883Returns:\r
884\r
885 None\r
886\r
887--*/\r
888{\r
889\r
890 EFI_STATUS Status;\r
891 PCI_IO_DEVICE *Dev;\r
892 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
893 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
894\r
895 Dev = NULL;\r
896 Status = gBS->AllocatePool (\r
897 EfiBootServicesData,\r
898 sizeof (PCI_IO_DEVICE),\r
899 (VOID **) &Dev\r
900 );\r
901\r
902 if (EFI_ERROR (Status)) {\r
903 return NULL;\r
904 }\r
905\r
906 ZeroMem (Dev, sizeof (PCI_IO_DEVICE));\r
907 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
908 Dev->Handle = RootBridgeHandle;\r
909 InitializeListHead (&Dev->ChildList);\r
910\r
911 Status = gBS->OpenProtocol (\r
912 RootBridgeHandle,\r
913 &gEfiDevicePathProtocolGuid,\r
914 (VOID **) &ParentDevicePath,\r
915 gPciBusDriverBinding.DriverBindingHandle,\r
916 RootBridgeHandle,\r
917 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
918 );\r
919\r
920 if (EFI_ERROR (Status)) {\r
921 gBS->FreePool (Dev);\r
922 return NULL;\r
923 }\r
924\r
925 //\r
926 // Record the root bridge parent device path\r
927 //\r
928 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
929\r
930 //\r
931 // Get the pci root bridge io protocol\r
932 //\r
933 Status = gBS->OpenProtocol (\r
934 RootBridgeHandle,\r
935 &gEfiPciRootBridgeIoProtocolGuid,\r
936 (VOID **) &PciRootBridgeIo,\r
937 gPciBusDriverBinding.DriverBindingHandle,\r
938 RootBridgeHandle,\r
939 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
940 );\r
941\r
942 if (EFI_ERROR (Status)) {\r
943 FreePciDevice (Dev);\r
944 return NULL;\r
945 }\r
946\r
947 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
948\r
949 //\r
950 // Initialize the PCI I/O instance structure\r
951 //\r
952 Status = InitializePciIoInstance (Dev);\r
953 Status = InitializePciDriverOverrideInstance (Dev);\r
954\r
955 //\r
956 // Initialize reserved resource list and\r
957 // option rom driver list\r
958 //\r
959 InitializeListHead (&Dev->ReservedResourceList);\r
960 InitializeListHead (&Dev->OptionRomDriverList);\r
961\r
962 return Dev;\r
963}\r
964\r
965PCI_IO_DEVICE *\r
966GetRootBridgeByHandle (\r
967 EFI_HANDLE RootBridgeHandle\r
968 )\r
969/*++\r
970\r
971Routine Description:\r
972\r
973\r
974Arguments:\r
975\r
976 RootBridgeHandle - An efi handle.\r
977\r
978Returns:\r
979\r
980 None\r
981\r
982--*/\r
983{\r
984 PCI_IO_DEVICE *RootBridgeDev;\r
985 LIST_ENTRY *CurrentLink;\r
986\r
987 CurrentLink = gPciDevicePool.ForwardLink;\r
988\r
989 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
990\r
991 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
992 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
993 return RootBridgeDev;\r
994 }\r
995\r
996 CurrentLink = CurrentLink->ForwardLink;\r
997 }\r
998\r
999 return NULL;\r
1000}\r
1001\r
1002BOOLEAN\r
1003RootBridgeExisted (\r
1004 IN EFI_HANDLE RootBridgeHandle\r
1005 )\r
1006/*++\r
1007\r
1008Routine Description:\r
1009\r
1010 This function searches if RootBridgeHandle has already existed\r
1011 in current device pool.\r
1012\r
1013 If so, it means the given root bridge has been already enumerated.\r
1014\r
1015Arguments:\r
1016\r
1017 RootBridgeHandle - An efi handle.\r
1018\r
1019Returns:\r
1020\r
1021 None\r
1022\r
1023--*/\r
1024{\r
1025 PCI_IO_DEVICE *Bridge;\r
1026\r
1027 Bridge = GetRootBridgeByHandle (RootBridgeHandle);\r
1028\r
1029 if (Bridge != NULL) {\r
1030 return TRUE;\r
1031 }\r
1032\r
1033 return FALSE;\r
1034}\r
1035\r
1036BOOLEAN\r
1037PciDeviceExisted (\r
1038 IN PCI_IO_DEVICE *Bridge,\r
1039 IN PCI_IO_DEVICE *PciIoDevice\r
1040 )\r
1041/*++\r
1042\r
1043Routine Description:\r
1044 \r
1045Arguments:\r
1046\r
1047 Bridge - A pointer to the PCI_IO_DEVICE.\r
1048 PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
1049\r
1050Returns:\r
1051\r
1052 None\r
1053\r
1054--*/\r
1055{\r
1056\r
1057 PCI_IO_DEVICE *Temp;\r
1058 LIST_ENTRY *CurrentLink;\r
1059\r
1060 CurrentLink = Bridge->ChildList.ForwardLink;\r
1061\r
1062 while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
1063\r
1064 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1065\r
1066 if (Temp == PciIoDevice) {\r
1067 return TRUE;\r
1068 }\r
1069\r
1070 if (!IsListEmpty (&Temp->ChildList)) {\r
1071 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
1072 return TRUE;\r
1073 }\r
1074 }\r
1075\r
1076 CurrentLink = CurrentLink->ForwardLink;\r
1077 }\r
1078\r
1079 return FALSE;\r
1080}\r
1081\r
1082PCI_IO_DEVICE *\r
1083ActiveVGADeviceOnTheSameSegment (\r
1084 IN PCI_IO_DEVICE *VgaDevice\r
1085 )\r
1086/*++\r
1087\r
1088Routine Description:\r
1089\r
1090Arguments:\r
1091\r
1092 VgaDevice - A pointer to the PCI_IO_DEVICE.\r
1093 \r
1094Returns:\r
1095\r
1096 None\r
1097\r
1098--*/\r
1099{\r
1100 LIST_ENTRY *CurrentLink;\r
1101 PCI_IO_DEVICE *Temp;\r
1102\r
1103 CurrentLink = gPciDevicePool.ForwardLink;\r
1104\r
1105 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
1106\r
1107 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1108\r
1109 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
1110\r
1111 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1112\r
1113 if (Temp != NULL) {\r
1114 return Temp;\r
1115 }\r
1116 }\r
1117\r
1118 CurrentLink = CurrentLink->ForwardLink;\r
1119 }\r
1120\r
1121 return NULL;\r
1122}\r
1123\r
1124PCI_IO_DEVICE *\r
1125ActiveVGADeviceOnTheRootBridge (\r
1126 IN PCI_IO_DEVICE *RootBridge\r
1127 )\r
1128/*++\r
1129\r
1130Routine Description:\r
1131\r
1132Arguments:\r
1133\r
1134 RootBridge - A pointer to the PCI_IO_DEVICE.\r
1135\r
1136Returns:\r
1137\r
1138 None\r
1139\r
1140--*/\r
1141{\r
1142 LIST_ENTRY *CurrentLink;\r
1143 PCI_IO_DEVICE *Temp;\r
1144\r
1145 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1146\r
1147 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
1148\r
1149 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1150\r
1151 if (IS_PCI_VGA(&Temp->Pci) && \r
1152 (Temp->Attributes & (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_IO))) {\r
1153 return Temp;\r
1154 }\r
1155\r
1156 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1157\r
1158 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1159\r
1160 if (Temp != NULL) {\r
1161 return Temp;\r
1162 }\r
1163 }\r
1164\r
1165 CurrentLink = CurrentLink->ForwardLink;\r
1166 }\r
1167\r
1168 return NULL;\r
1169}\r
1170\r
1171EFI_STATUS\r
1172GetHpcPciAddress (\r
1173 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
1174 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
1175 OUT UINT64 *PciAddress\r
1176 )\r
1177/*++\r
1178\r
1179Routine Description:\r
1180\r
1181Arguments:\r
1182\r
1183 PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1184 HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
1185 PciAddress - A pointer to the pci address.\r
1186 \r
1187Returns:\r
1188\r
1189 None\r
1190\r
1191--*/\r
1192// TODO: EFI_NOT_FOUND - add return value to function comment\r
1193// TODO: EFI_NOT_FOUND - add return value to function comment\r
1194// TODO: EFI_SUCCESS - add return value to function comment\r
1195// TODO: EFI_NOT_FOUND - add return value to function comment\r
1196{\r
1197 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1198 EFI_DEV_PATH_PTR Node;\r
1199 LIST_ENTRY *CurrentLink;\r
1200 PCI_IO_DEVICE *RootBridge;\r
1201 EFI_STATUS Status;\r
1202\r
1203 CurrentDevicePath = HpcDevicePath;\r
1204\r
1205 //\r
1206 // Get the remaining device path for this PCI device, if it is a PCI device\r
1207 //\r
1208 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1209\r
1210 Node.DevPath = CurrentDevicePath;\r
1211\r
1212 //\r
1213 // Check if it is PCI device Path?\r
1214 //\r
1215 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
1216 ((Node.DevPath->SubType != HW_PCI_DP) &&\r
1217 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {\r
1218 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1219 continue;\r
1220 }\r
1221\r
1222 break;\r
1223 }\r
1224\r
1225 //\r
1226 // Check if it is not PCI device path\r
1227 //\r
1228 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1229 return EFI_NOT_FOUND;\r
1230 }\r
1231\r
1232 CurrentLink = gPciDevicePool.ForwardLink;\r
1233\r
1234 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
1235\r
1236 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1237 //\r
1238 // Locate the right root bridge to start\r
1239 //\r
1240 if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {\r
1241 Status = GetHpcPciAddressFromRootBridge (\r
1242 RootBridge,\r
1243 CurrentDevicePath,\r
1244 PciAddress\r
1245 );\r
1246 if (EFI_ERROR (Status)) {\r
1247 return EFI_NOT_FOUND;\r
1248 }\r
1249\r
1250 return EFI_SUCCESS;\r
1251\r
1252 }\r
1253\r
1254 CurrentLink = CurrentLink->ForwardLink;\r
1255 }\r
1256\r
1257 return EFI_NOT_FOUND;\r
1258}\r
1259\r
1260EFI_STATUS\r
1261GetHpcPciAddressFromRootBridge (\r
1262 IN PCI_IO_DEVICE *RootBridge,\r
1263 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1264 OUT UINT64 *PciAddress\r
1265 )\r
1266/*++\r
1267\r
1268Routine Description:\r
1269\r
1270Arguments:\r
1271\r
1272 PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1273 HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
1274 PciAddress - A pointer to the pci address.\r
1275\r
1276Returns:\r
1277\r
1278 None\r
1279\r
1280--*/\r
1281// TODO: RootBridge - add argument and description to function comment\r
1282// TODO: RemainingDevicePath - add argument and description to function comment\r
1283// TODO: EFI_SUCCESS - add return value to function comment\r
1284// TODO: EFI_NOT_FOUND - add return value to function comment\r
1285// TODO: EFI_SUCCESS - add return value to function comment\r
1286{\r
1287 EFI_DEV_PATH_PTR Node;\r
1288 PCI_IO_DEVICE *Temp;\r
1289 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1290 LIST_ENTRY *CurrentLink;\r
1291 BOOLEAN MisMatch;\r
1292\r
1293 MisMatch = FALSE;\r
1294\r
1295 CurrentDevicePath = RemainingDevicePath;\r
1296 Node.DevPath = CurrentDevicePath;\r
1297 Temp = NULL;\r
1298\r
1299 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1300\r
1301 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1302 Node.DevPath = CurrentDevicePath;\r
1303\r
1304 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
1305 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1306\r
1307 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1308 Node.Pci->Function == Temp->FunctionNumber) {\r
1309 RootBridge = Temp;\r
1310 break;\r
1311 }\r
1312\r
1313 CurrentLink = CurrentLink->ForwardLink;\r
1314 }\r
1315\r
1316 //\r
1317 // Check if we find the bridge\r
1318 //\r
1319 if (CurrentLink == &RootBridge->ChildList) {\r
1320\r
1321 MisMatch = TRUE;\r
1322 break;\r
1323\r
1324 }\r
1325\r
1326 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1327 }\r
1328\r
1329 if (MisMatch) {\r
1330\r
1331 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1332\r
1333 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1334 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1335 return EFI_SUCCESS;\r
1336 }\r
1337\r
1338 return EFI_NOT_FOUND;\r
1339 }\r
1340\r
1341 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1342\r
1343 return EFI_SUCCESS;\r
1344\r
1345}\r