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