MdeModulePkg/NonDiscoverablePciDeviceDxe: expose unique B/D/F identifiers
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NonDiscoverablePciDeviceDxe / NonDiscoverablePciDeviceDxe.c
1 /** @file
2
3 Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
4
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
11 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "NonDiscoverablePciDeviceIo.h"
16
17 #include <Protocol/DriverBinding.h>
18
19 #define MAX_NON_DISCOVERABLE_PCI_DEVICE_ID (32 * 256)
20
21 STATIC UINTN mUniqueIdCounter = 0;
22 EFI_CPU_ARCH_PROTOCOL *mCpu;
23
24 //
25 // We only support the following device types
26 //
27 STATIC
28 CONST EFI_GUID * CONST
29 SupportedNonDiscoverableDevices[] = {
30 &gEdkiiNonDiscoverableAhciDeviceGuid,
31 &gEdkiiNonDiscoverableEhciDeviceGuid,
32 &gEdkiiNonDiscoverableNvmeDeviceGuid,
33 &gEdkiiNonDiscoverableOhciDeviceGuid,
34 &gEdkiiNonDiscoverableSdhciDeviceGuid,
35 &gEdkiiNonDiscoverableUfsDeviceGuid,
36 &gEdkiiNonDiscoverableUhciDeviceGuid,
37 &gEdkiiNonDiscoverableXhciDeviceGuid,
38 };
39
40 //
41 // Probe, start and stop functions of this driver, called by the DXE core for
42 // specific devices.
43 //
44 // The following specifications document these interfaces:
45 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
46 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
47 //
48 // The implementation follows:
49 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
50 // - 5.1.3.4 OpenProtocol() and CloseProtocol()
51 // - UEFI Spec 2.3.1 + Errata C
52 // - 6.3 Protocol Handler Services
53 //
54
55 /**
56 Supported function of Driver Binding protocol for this driver.
57 Test to see if this driver supports ControllerHandle.
58
59 @param This Protocol instance pointer.
60 @param DeviceHandle Handle of device to test.
61 @param RemainingDevicePath A pointer to the device path.
62 it should be ignored by device driver.
63
64 @retval EFI_SUCCESS This driver supports this device.
65 @retval other This driver does not support this device.
66
67 **/
68 STATIC
69 EFI_STATUS
70 EFIAPI
71 NonDiscoverablePciDeviceSupported (
72 IN EFI_DRIVER_BINDING_PROTOCOL *This,
73 IN EFI_HANDLE DeviceHandle,
74 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
75 )
76 {
77 NON_DISCOVERABLE_DEVICE *Device;
78 EFI_STATUS Status;
79 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
80 INTN Idx;
81
82 Status = gBS->OpenProtocol (DeviceHandle,
83 &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Device,
84 This->DriverBindingHandle, DeviceHandle,
85 EFI_OPEN_PROTOCOL_BY_DRIVER);
86 if (EFI_ERROR (Status)) {
87 return Status;
88 }
89
90 Status = EFI_UNSUPPORTED;
91 for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) {
92 if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices [Idx])) {
93 Status = EFI_SUCCESS;
94 break;
95 }
96 }
97
98 if (EFI_ERROR (Status)) {
99 goto CloseProtocol;
100 }
101
102 //
103 // We only support MMIO devices, so iterate over the resources to ensure
104 // that they only describe things that we can handle
105 //
106 for (Desc = Device->Resources; Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
107 Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
108 if (Desc->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR ||
109 Desc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
110 Status = EFI_UNSUPPORTED;
111 break;
112 }
113 }
114
115 CloseProtocol:
116 gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
117 This->DriverBindingHandle, DeviceHandle);
118
119 return Status;
120 }
121
122 /**
123 This routine is called right after the .Supported() called and
124 Start this driver on ControllerHandle.
125
126 @param This Protocol instance pointer.
127 @param DeviceHandle Handle of device to bind driver to.
128 @param RemainingDevicePath A pointer to the device path.
129 it should be ignored by device driver.
130
131 @retval EFI_SUCCESS This driver is added to this device.
132 @retval other Some error occurs when binding this driver to this device.
133
134 **/
135 STATIC
136 EFI_STATUS
137 EFIAPI
138 NonDiscoverablePciDeviceStart (
139 IN EFI_DRIVER_BINDING_PROTOCOL *This,
140 IN EFI_HANDLE DeviceHandle,
141 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
142 )
143 {
144 NON_DISCOVERABLE_PCI_DEVICE *Dev;
145 EFI_STATUS Status;
146
147 ASSERT (mUniqueIdCounter < MAX_NON_DISCOVERABLE_PCI_DEVICE_ID);
148 if (mUniqueIdCounter >= MAX_NON_DISCOVERABLE_PCI_DEVICE_ID) {
149 return EFI_OUT_OF_RESOURCES;
150 }
151
152 Dev = AllocateZeroPool (sizeof *Dev);
153 if (Dev == NULL) {
154 return EFI_OUT_OF_RESOURCES;
155 }
156
157 Status = gBS->OpenProtocol (DeviceHandle,
158 &gEdkiiNonDiscoverableDeviceProtocolGuid,
159 (VOID **)&Dev->Device, This->DriverBindingHandle,
160 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
161 if (EFI_ERROR (Status)) {
162 goto FreeDev;
163 }
164
165 InitializePciIoProtocol (Dev);
166
167 //
168 // Setup complete, attempt to export the driver instance's
169 // EFI_PCI_IO_PROTOCOL interface.
170 //
171 Dev->Signature = NON_DISCOVERABLE_PCI_DEVICE_SIG;
172 Status = gBS->InstallProtocolInterface (&DeviceHandle, &gEfiPciIoProtocolGuid,
173 EFI_NATIVE_INTERFACE, &Dev->PciIo);
174 if (EFI_ERROR (Status)) {
175 goto CloseProtocol;
176 }
177
178 Dev->UniqueId = mUniqueIdCounter++;
179
180 return EFI_SUCCESS;
181
182 CloseProtocol:
183 gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
184 This->DriverBindingHandle, DeviceHandle);
185
186 FreeDev:
187 FreePool (Dev);
188
189 return Status;
190 }
191
192 /**
193 Stop this driver on ControllerHandle.
194
195 @param This Protocol instance pointer.
196 @param DeviceHandle Handle of device to stop driver on.
197 @param NumberOfChildren Not used.
198 @param ChildHandleBuffer Not used.
199
200 @retval EFI_SUCCESS This driver is removed from this device.
201 @retval other Some error occurs when removing this driver from this device.
202
203 **/
204 STATIC
205 EFI_STATUS
206 EFIAPI
207 NonDiscoverablePciDeviceStop (
208 IN EFI_DRIVER_BINDING_PROTOCOL *This,
209 IN EFI_HANDLE DeviceHandle,
210 IN UINTN NumberOfChildren,
211 IN EFI_HANDLE *ChildHandleBuffer
212 )
213 {
214 EFI_STATUS Status;
215 EFI_PCI_IO_PROTOCOL *PciIo;
216 NON_DISCOVERABLE_PCI_DEVICE *Dev;
217
218 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
219 (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,
220 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
221 if (EFI_ERROR (Status)) {
222 return Status;
223 }
224
225 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (PciIo);
226
227 //
228 // Handle Stop() requests for in-use driver instances gracefully.
229 //
230 Status = gBS->UninstallProtocolInterface (DeviceHandle,
231 &gEfiPciIoProtocolGuid, &Dev->PciIo);
232 if (EFI_ERROR (Status)) {
233 return Status;
234 }
235
236 gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
237 This->DriverBindingHandle, DeviceHandle);
238
239 FreePool (Dev);
240
241 return EFI_SUCCESS;
242 }
243
244
245 //
246 // The static object that groups the Supported() (ie. probe), Start() and
247 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
248 // C, 10.1 EFI Driver Binding Protocol.
249 //
250 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
251 &NonDiscoverablePciDeviceSupported,
252 &NonDiscoverablePciDeviceStart,
253 &NonDiscoverablePciDeviceStop,
254 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
255 NULL,
256 NULL
257 };
258
259 /**
260 Entry point of this driver.
261
262 @param ImageHandle Image handle this driver.
263 @param SystemTable Pointer to the System Table.
264
265 @retval EFI_SUCCESS The entry point is executed successfully.
266 @retval other Some error occurred when executing this entry point.
267
268 **/
269 EFI_STATUS
270 EFIAPI
271 NonDiscoverablePciDeviceDxeEntryPoint (
272 IN EFI_HANDLE ImageHandle,
273 IN EFI_SYSTEM_TABLE *SystemTable
274 )
275 {
276 EFI_STATUS Status;
277
278 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
279 ASSERT_EFI_ERROR(Status);
280
281 return EfiLibInstallDriverBindingComponentName2 (
282 ImageHandle,
283 SystemTable,
284 &gDriverBinding,
285 ImageHandle,
286 &gComponentName,
287 &gComponentName2
288 );
289 }