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