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