1 /** @file
2   Driver Binding functions for PCI Bus module.
3 
4   Single PCI bus driver instance will manager all PCI Root Bridges in one EFI based firmware,
5   since all PCI Root Bridges' resources need to be managed together.
6   Supported() function will try to get PCI Root Bridge IO Protocol.
7   Start() function will get PCI Host Bridge Resource Allocation Protocol to manage all
8   PCI Root Bridges. So it means platform needs install PCI Root Bridge IO protocol for each
9   PCI Root Bus and install PCI Host Bridge Resource Allocation Protocol.
10 
11 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
12 This program and the accompanying materials
13 are licensed and made available under the terms and conditions of the BSD License
14 which accompanies this distribution.  The full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
16 
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 **/
21 
22 #include "PciBus.h"
23 
24 //
25 // PCI Bus Driver Global Variables
26 //
27 EFI_DRIVER_BINDING_PROTOCOL                   gPciBusDriverBinding = {
28   PciBusDriverBindingSupported,
29   PciBusDriverBindingStart,
30   PciBusDriverBindingStop,
31   0xa,
32   NULL,
33   NULL
34 };
35 
36 EFI_HANDLE                                    gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM];
37 EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL  *gEfiIncompatiblePciDeviceSupport = NULL;
38 UINTN                                         gPciHostBridgeNumber = 0;
39 BOOLEAN                                       gFullEnumeration     = TRUE;
40 UINT64                                        gAllOne              = 0xFFFFFFFFFFFFFFFFULL;
41 UINT64                                        gAllZero             = 0;
42 
43 EFI_PCI_PLATFORM_PROTOCOL                     *gPciPlatformProtocol;
44 EFI_PCI_OVERRIDE_PROTOCOL                     *gPciOverrideProtocol;
45 
46 
47 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL mPciHotPlugRequest = {
48   PciHotPlugRequestNotify
49 };
50 
51 /**
52   The Entry Point for PCI Bus module. The user code starts with this function.
53 
54   Installs driver module protocols and. Creates virtual device handles for ConIn,
55   ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,
56   Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.
57   Installs Graphics Output protocol and/or UGA Draw protocol if needed.
58 
59   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
60   @param[in] SystemTable    A pointer to the EFI System Table.
61 
62   @retval EFI_SUCCESS       The entry point is executed successfully.
63   @retval other             Some error occurred when executing this entry point.
64 
65 **/
66 EFI_STATUS
67 EFIAPI
PciBusEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)68 PciBusEntryPoint (
69   IN EFI_HANDLE         ImageHandle,
70   IN EFI_SYSTEM_TABLE   *SystemTable
71   )
72 {
73   EFI_STATUS  Status;
74   EFI_HANDLE  Handle;
75 
76   //
77   // Initializes PCI devices pool
78   //
79   InitializePciDevicePool ();
80 
81   //
82   // Install driver model protocol(s).
83   //
84   Status = EfiLibInstallDriverBindingComponentName2 (
85              ImageHandle,
86              SystemTable,
87              &gPciBusDriverBinding,
88              ImageHandle,
89              &gPciBusComponentName,
90              &gPciBusComponentName2
91              );
92   ASSERT_EFI_ERROR (Status);
93 
94   if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
95     //
96     // If Hot Plug is supported, install EFI PCI Hot Plug Request protocol.
97     //
98     Handle = NULL;
99     Status = gBS->InstallProtocolInterface (
100                     &Handle,
101                     &gEfiPciHotPlugRequestProtocolGuid,
102                     EFI_NATIVE_INTERFACE,
103                     &mPciHotPlugRequest
104                     );
105   }
106 
107   return Status;
108 }
109 
110 /**
111   Test to see if this driver supports ControllerHandle. Any ControllerHandle
112   than contains a gEfiPciRootBridgeIoProtocolGuid protocol can be supported.
113 
114   @param  This                Protocol instance pointer.
115   @param  Controller          Handle of device to test.
116   @param  RemainingDevicePath Optional parameter use to pick a specific child.
117                               device to start.
118 
119   @retval EFI_SUCCESS         This driver supports this device.
120   @retval EFI_ALREADY_STARTED This driver is already running on this device.
121   @retval other               This driver does not support this device.
122 
123 **/
124 EFI_STATUS
125 EFIAPI
PciBusDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)126 PciBusDriverBindingSupported (
127   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
128   IN EFI_HANDLE                     Controller,
129   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
130   )
131 {
132   EFI_STATUS                      Status;
133   EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
134   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
135   EFI_DEV_PATH_PTR                Node;
136 
137   //
138   // Check RemainingDevicePath validation
139   //
140   if (RemainingDevicePath != NULL) {
141     //
142     // Check if RemainingDevicePath is the End of Device Path Node,
143     // if yes, go on checking other conditions
144     //
145     if (!IsDevicePathEnd (RemainingDevicePath)) {
146       //
147       // If RemainingDevicePath isn't the End of Device Path Node,
148       // check its validation
149       //
150       Node.DevPath = RemainingDevicePath;
151       if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
152           Node.DevPath->SubType != HW_PCI_DP         ||
153           DevicePathNodeLength(Node.DevPath) != sizeof(PCI_DEVICE_PATH)) {
154         return EFI_UNSUPPORTED;
155       }
156     }
157   }
158 
159   //
160   // Check if Pci Root Bridge IO protocol is installed by platform
161   //
162   Status = gBS->OpenProtocol (
163                   Controller,
164                   &gEfiPciRootBridgeIoProtocolGuid,
165                   (VOID **) &PciRootBridgeIo,
166                   This->DriverBindingHandle,
167                   Controller,
168                   EFI_OPEN_PROTOCOL_BY_DRIVER
169                   );
170   if (Status == EFI_ALREADY_STARTED) {
171     return EFI_SUCCESS;
172   }
173 
174   if (EFI_ERROR (Status)) {
175     return Status;
176   }
177 
178   //
179   // Close the I/O Abstraction(s) used to perform the supported test
180   //
181   gBS->CloseProtocol (
182         Controller,
183         &gEfiPciRootBridgeIoProtocolGuid,
184         This->DriverBindingHandle,
185         Controller
186         );
187 
188   //
189   // Open the EFI Device Path protocol needed to perform the supported test
190   //
191   Status = gBS->OpenProtocol (
192                   Controller,
193                   &gEfiDevicePathProtocolGuid,
194                   (VOID **) &ParentDevicePath,
195                   This->DriverBindingHandle,
196                   Controller,
197                   EFI_OPEN_PROTOCOL_BY_DRIVER
198                   );
199   if (Status == EFI_ALREADY_STARTED) {
200     return EFI_SUCCESS;
201   }
202 
203   if (EFI_ERROR (Status)) {
204     return Status;
205   }
206 
207   //
208   // Close protocol, don't use device path protocol in the Support() function
209   //
210   gBS->CloseProtocol (
211         Controller,
212         &gEfiDevicePathProtocolGuid,
213         This->DriverBindingHandle,
214         Controller
215         );
216 
217   return EFI_SUCCESS;
218 }
219 
220 /**
221   Start this driver on ControllerHandle and enumerate Pci bus and start
222   all device under PCI bus.
223 
224   @param  This                 Protocol instance pointer.
225   @param  Controller           Handle of device to bind driver to.
226   @param  RemainingDevicePath  Optional parameter use to pick a specific child.
227                                device to start.
228 
229   @retval EFI_SUCCESS          This driver is added to ControllerHandle.
230   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle.
231   @retval other                This driver does not support this device.
232 
233 **/
234 EFI_STATUS
235 EFIAPI
PciBusDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)236 PciBusDriverBindingStart (
237   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
238   IN EFI_HANDLE                   Controller,
239   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
240   )
241 {
242   EFI_STATUS                Status;
243   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
244 
245   //
246   // Check RemainingDevicePath validation
247   //
248   if (RemainingDevicePath != NULL) {
249     //
250     // Check if RemainingDevicePath is the End of Device Path Node,
251     // if yes, return EFI_SUCCESS
252     //
253     if (IsDevicePathEnd (RemainingDevicePath)) {
254       return EFI_SUCCESS;
255     }
256   }
257 
258   Status = gBS->LocateProtocol (
259                   &gEfiIncompatiblePciDeviceSupportProtocolGuid,
260                   NULL,
261                   (VOID **) &gEfiIncompatiblePciDeviceSupport
262                   );
263 
264   //
265   // If PCI Platform protocol is available, get it now.
266   // If the platform implements this, it must be installed before BDS phase
267   //
268   gPciPlatformProtocol = NULL;
269   gBS->LocateProtocol (
270         &gEfiPciPlatformProtocolGuid,
271         NULL,
272         (VOID **) &gPciPlatformProtocol
273         );
274 
275   //
276   // If PCI Platform protocol doesn't exist, try to Pci Override Protocol.
277   //
278   if (gPciPlatformProtocol == NULL) {
279     gPciOverrideProtocol = NULL;
280     gBS->LocateProtocol (
281           &gEfiPciOverrideProtocolGuid,
282           NULL,
283           (VOID **) &gPciOverrideProtocol
284           );
285   }
286 
287   if (PcdGetBool (PcdPciDisableBusEnumeration)) {
288     gFullEnumeration = FALSE;
289   } else {
290     gFullEnumeration = (BOOLEAN) ((SearchHostBridgeHandle (Controller) ? FALSE : TRUE));
291   }
292 
293   //
294   // Open Device Path Protocol for PCI root bridge
295   //
296   Status = gBS->OpenProtocol (
297                   Controller,
298                   &gEfiDevicePathProtocolGuid,
299                   (VOID **) &ParentDevicePath,
300                   This->DriverBindingHandle,
301                   Controller,
302                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
303                   );
304   ASSERT_EFI_ERROR (Status);
305 
306   //
307   // Report Status Code to indicate PCI bus starts
308   //
309   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
310     EFI_PROGRESS_CODE,
311     (EFI_IO_BUS_PCI | EFI_IOB_PC_INIT),
312     ParentDevicePath
313     );
314 
315   //
316   // Enumerate the entire host bridge
317   // After enumeration, a database that records all the device information will be created
318   //
319   //
320   Status = PciEnumerator (Controller);
321 
322   if (EFI_ERROR (Status)) {
323     return Status;
324   }
325 
326   //
327   // Start all the devices under the entire host bridge.
328   //
329   StartPciDevices (Controller);
330 
331   return EFI_SUCCESS;
332 }
333 
334 /**
335   Stop this driver on ControllerHandle. Support stoping any child handles
336   created by this driver.
337 
338   @param  This              Protocol instance pointer.
339   @param  Controller        Handle of device to stop driver on.
340   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
341                             children is zero stop the entire bus driver.
342   @param  ChildHandleBuffer List of Child Handles to Stop.
343 
344   @retval EFI_SUCCESS       This driver is removed ControllerHandle.
345   @retval other             This driver was not removed from this device.
346 
347 **/
348 EFI_STATUS
349 EFIAPI
PciBusDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)350 PciBusDriverBindingStop (
351   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
352   IN  EFI_HANDLE                    Controller,
353   IN  UINTN                         NumberOfChildren,
354   IN  EFI_HANDLE                    *ChildHandleBuffer
355   )
356 {
357   EFI_STATUS  Status;
358   UINTN       Index;
359   BOOLEAN     AllChildrenStopped;
360 
361   if (NumberOfChildren == 0) {
362     //
363     // Close the bus driver
364     //
365     gBS->CloseProtocol (
366           Controller,
367           &gEfiDevicePathProtocolGuid,
368           This->DriverBindingHandle,
369           Controller
370           );
371     gBS->CloseProtocol (
372           Controller,
373           &gEfiPciRootBridgeIoProtocolGuid,
374           This->DriverBindingHandle,
375           Controller
376           );
377 
378     DestroyRootBridgeByHandle (
379       Controller
380       );
381 
382     return EFI_SUCCESS;
383   }
384 
385   //
386   // Stop all the children
387   //
388 
389   AllChildrenStopped = TRUE;
390 
391   for (Index = 0; Index < NumberOfChildren; Index++) {
392 
393     //
394     // De register all the pci device
395     //
396     Status = DeRegisterPciDevice (Controller, ChildHandleBuffer[Index]);
397 
398     if (EFI_ERROR (Status)) {
399       AllChildrenStopped = FALSE;
400     }
401   }
402 
403   if (!AllChildrenStopped) {
404     return EFI_DEVICE_ERROR;
405   }
406 
407   return EFI_SUCCESS;
408 }
409 
410