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