]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
IntelSiliconPkg: Add PlatformVTdSample driver.
[mirror_edk2.git] / IntelSiliconPkg / PlatformVTdSampleDxe / PlatformVTdSampleDxe.c
CommitLineData
5071fb9c
JY
1/** @file\r
2 Platform VTd Sample driver.\r
3\r
4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiDxe.h>\r
16\r
17#include <IndustryStandard/Vtd.h>\r
18#include <Protocol/PlatformVtdPolicy.h>\r
19#include <Protocol/PciIo.h>\r
20#include <Protocol/DevicePath.h>\r
21\r
22#include <Library/IoLib.h>\r
23#include <Library/BaseLib.h>\r
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/MemoryAllocationLib.h>\r
26#include <Library/DebugLib.h>\r
27#include <Library/UefiBootServicesTableLib.h>\r
28#include <Library/DevicePathLib.h>\r
29\r
30typedef struct {\r
31 ACPI_EXTENDED_HID_DEVICE_PATH I2cController;\r
32 UINT8 HidStr[8];\r
33 UINT8 UidStr[1];\r
34 UINT8 CidStr[8];\r
35} PLATFORM_I2C_CONTROLLER_DEVICE_PATH;\r
36\r
37typedef struct {\r
38 ACPI_EXTENDED_HID_DEVICE_PATH I2cDevice;\r
39 UINT8 HidStr[13];\r
40 UINT8 UidStr[1];\r
41 UINT8 CidStr[13];\r
42} PLATFORM_I2C_DEVICE_DEVICE_PATH;\r
43\r
44typedef struct {\r
45 PLATFORM_I2C_CONTROLLER_DEVICE_PATH I2cController;\r
46 PLATFORM_I2C_DEVICE_DEVICE_PATH I2cDevice;\r
47 EFI_DEVICE_PATH_PROTOCOL End;\r
48} PLATFORM_I2C_DEVICE_PATH;\r
49\r
50typedef struct {\r
51 ACPI_HID_DEVICE_PATH PciRootBridge;\r
52 PCI_DEVICE_PATH PciDevice;\r
53 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
54} PLATFORM_PCI_DEVICE_PATH;\r
55\r
56typedef struct {\r
57 ACPI_HID_DEVICE_PATH PciRootBridge;\r
58 PCI_DEVICE_PATH PciBridge;\r
59 PCI_DEVICE_PATH PciDevice;\r
60 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
61} PLATFORM_PCI_BRIDGE_DEVICE_PATH;\r
62\r
63typedef struct {\r
64 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
65 UINT16 Segment;\r
66 VTD_SOURCE_ID SourceId;\r
67} PLATFORM_ACPI_DEVICE_MAPPING;\r
68\r
69#define PLATFORM_PCI_ROOT_BRIDGE \\r
70 { \\r
71 { \\r
72 ACPI_DEVICE_PATH, \\r
73 ACPI_DP, \\r
74 { \\r
75 (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \\r
76 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \\r
77 }, \\r
78 }, \\r
79 EISA_PNP_ID (0x0A03), \\r
80 0 \\r
81 }\r
82\r
83#define PLATFORM_END_ENTIRE \\r
84 { \\r
85 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \\r
86 }\r
87\r
88#define PLATFORM_PCI(Device, Function) \\r
89 { \\r
90 { \\r
91 HARDWARE_DEVICE_PATH, \\r
92 HW_PCI_DP, \\r
93 { \\r
94 (UINT8) (sizeof (PCI_DEVICE_PATH)), \\r
95 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \\r
96 } \\r
97 }, \\r
98 (Function), \\r
99 (Device) \\r
100 }\r
101\r
102#define PLATFORM_I2C(Hid, Uid, Cid, HidStr, UidStr, CidStr) \\r
103 { \\r
104 { \\r
105 { \\r
106 ACPI_DEVICE_PATH, \\r
107 ACPI_EXTENDED_DP, \\r
108 {sizeof(ACPI_EXTENDED_HID_DEVICE_PATH) + sizeof(HidStr) + sizeof(UidStr) + sizeof(CidStr), 0} \\r
109 }, \\r
110 Hid, \\r
111 Uid, \\r
112 Cid \\r
113 }, \\r
114 HidStr, \\r
115 UidStr, \\r
116 CidStr \\r
117 }\r
118\r
119PLATFORM_I2C_DEVICE_PATH mPlatformI2CDevicePath = {\r
120 PLATFORM_I2C(0, 2, 0, "INT33C3", "", "INT33C3"),\r
121 PLATFORM_I2C(0, 1, 0, "I2C01\\TPANEL", "", "I2C01\\TPANEL"),\r
122 PLATFORM_END_ENTIRE\r
123};\r
124\r
125PLATFORM_ACPI_DEVICE_MAPPING mAcpiDeviceMapping[] = {\r
126 {\r
127 (EFI_DEVICE_PATH_PROTOCOL *)&mPlatformI2CDevicePath,\r
128 0x0, // Segment\r
129 {{0x01, 0x15, 0x00}} // Function, Device, Bus\r
130 }\r
131};\r
132\r
133PLATFORM_PCI_BRIDGE_DEVICE_PATH mPlatformPciBridgeDevicePath = {\r
134 PLATFORM_PCI_ROOT_BRIDGE,\r
135 PLATFORM_PCI(0x1C, 1),\r
136 PLATFORM_PCI(0, 0),\r
137 PLATFORM_END_ENTIRE\r
138};\r
139\r
140EDKII_PLATFORM_VTD_DEVICE_INFO mExceptionDeviceList[] = {\r
141 {\r
142 0x0, // Segment\r
143 {{0x00, 0x00, 0x02}} // Function, Device, Bus\r
144 },\r
145};\r
146\r
147/**\r
148 Compares 2 device path.\r
149\r
150 @param[in] DevicePath1 A device path with EndDevicePath node.\r
151 @param[in] DevicePath2 A device path with EndDevicePath node.\r
152\r
153 @retval TRUE 2 device path are identical.\r
154 @retval FALSE 2 device path are not identical.\r
155**/\r
156BOOLEAN\r
157CompareDevicePath (\r
158 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,\r
159 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2\r
160 )\r
161{\r
162 UINTN Size1;\r
163 UINTN Size2;\r
164\r
165 Size1 = GetDevicePathSize (DevicePath1);\r
166 Size2 = GetDevicePathSize (DevicePath2);\r
167 if (Size1 != Size2) {\r
168 return FALSE;\r
169 }\r
170 if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {\r
171 return FALSE;\r
172 }\r
173 return TRUE;\r
174}\r
175\r
176/**\r
177 Get the VTD SourceId from the device handler.\r
178 This function is required for non PCI device handler.\r
179\r
180 Pseudo-algo in Intel VTd driver:\r
181 Status = PlatformGetVTdDeviceId ();\r
182 if (EFI_ERROR(Status)) {\r
183 if (DeviceHandle is PCI) {\r
184 Get SourceId from Bus/Device/Function\r
185 } else {\r
186 return EFI_UNSUPPORTED\r
187 }\r
188 }\r
189 Get VTd engine by Segment/Bus/Device/Function.\r
190\r
191 @param[in] This The protocol instance pointer.\r
192 @param[in] DeviceHandle Device Identifier in UEFI.\r
193 @param[out] DeviceInfo DeviceInfo for indentify the VTd engine in ACPI Table\r
194 and the VTd page entry.\r
195\r
196 @retval EFI_SUCCESS The VtdIndex and SourceId are returned.\r
197 @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.\r
198 @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.\r
199 @retval EFI_NOT_FOUND The Segment or SourceId information is NOT found.\r
200 @retval EFI_UNSUPPORTED This function is not supported.\r
201\r
202**/\r
203EFI_STATUS\r
204EFIAPI\r
205PlatformVTdGetDeviceId (\r
206 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,\r
207 IN EFI_HANDLE DeviceHandle,\r
208 OUT EDKII_PLATFORM_VTD_DEVICE_INFO *DeviceInfo\r
209 )\r
210{\r
211 EFI_PCI_IO_PROTOCOL *PciIo;\r
212 UINTN Seg;\r
213 UINTN Bus;\r
214 UINTN Dev;\r
215 UINTN Func;\r
216 EFI_STATUS Status;\r
217 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
218 UINTN Index;\r
219\r
220 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetDeviceId\n"));\r
221\r
222 if (DeviceInfo == NULL) {\r
223 return EFI_INVALID_PARAMETER;\r
224 }\r
225\r
226 if (DeviceHandle == NULL) {\r
227 return EFI_INVALID_PARAMETER;\r
228 }\r
229\r
230 //\r
231 // Handle PCI device\r
232 //\r
233 Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);\r
234 if (!EFI_ERROR(Status)) {\r
235 Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);\r
236 if (EFI_ERROR(Status)) {\r
237 return EFI_UNSUPPORTED;\r
238 }\r
239 DeviceInfo->Segment = (UINT16)Seg;\r
240 DeviceInfo->SourceId.Bits.Bus = (UINT8)Bus;\r
241 DeviceInfo->SourceId.Bits.Device = (UINT8)Dev;\r
242 DeviceInfo->SourceId.Bits.Function = (UINT8)Func;\r
243\r
244 return EFI_SUCCESS;\r
245 }\r
246\r
247 //\r
248 // Handle ACPI device\r
249 //\r
250 Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);\r
251 if (!EFI_ERROR(Status)) {\r
252 for (Index = 0; Index < ARRAY_SIZE(mAcpiDeviceMapping); Index++) {\r
253 if (CompareDevicePath (mAcpiDeviceMapping[Index].DevicePath, DevicePath)) {\r
254 DeviceInfo->Segment = mAcpiDeviceMapping[Index].Segment;\r
255 DeviceInfo->SourceId = mAcpiDeviceMapping[Index].SourceId;\r
256 return EFI_SUCCESS;\r
257 }\r
258 }\r
259 }\r
260\r
261 return EFI_NOT_FOUND;\r
262}\r
263\r
264/**\r
265 Get a list of the exception devices.\r
266\r
267 The VTd driver should always set ALLOW for the device in this list.\r
268\r
269 @param[in] This The protocol instance pointer.\r
270 @param[out] DeviceInfoCount The count of the list of DeviceInfo.\r
271 @param[out] DeviceInfo A callee allocated buffer to hold a list of DeviceInfo.\r
272\r
273 @retval EFI_SUCCESS The DeviceInfoCount and DeviceInfo are returned.\r
274 @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.\r
275 @retval EFI_UNSUPPORTED This function is not supported.\r
276\r
277**/\r
278EFI_STATUS\r
279EFIAPI\r
280PlatformVTdGetExceptionDeviceList (\r
281 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,\r
282 OUT UINTN *DeviceInfoCount,\r
283 OUT EDKII_PLATFORM_VTD_DEVICE_INFO **DeviceInfo\r
284 )\r
285{\r
286 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetExceptionDeviceList\n"));\r
287\r
288 if (DeviceInfoCount == NULL || DeviceInfo == NULL) {\r
289 return EFI_INVALID_PARAMETER;\r
290 }\r
291\r
292 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionDeviceList));\r
293 if (*DeviceInfo == NULL) {\r
294 return EFI_OUT_OF_RESOURCES;\r
295 }\r
296 CopyMem (*DeviceInfo, mExceptionDeviceList, sizeof(mExceptionDeviceList));\r
297\r
298 *DeviceInfoCount = ARRAY_SIZE(mExceptionDeviceList);\r
299\r
300 return EFI_SUCCESS;\r
301}\r
302\r
303EDKII_PLATFORM_VTD_POLICY_PROTOCOL mPlatformVTdSample = {\r
304 EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION,\r
305 PlatformVTdGetDeviceId,\r
306 PlatformVTdGetExceptionDeviceList,\r
307};\r
308\r
309/**\r
310 Platform VTd sample driver.\r
311\r
312 @param[in] ImageHandle ImageHandle of the loaded driver\r
313 @param[in] SystemTable Pointer to the System Table\r
314\r
315 @retval EFI_SUCCESS The Protocol is installed.\r
316 @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.\r
317 @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.\r
318\r
319**/\r
320EFI_STATUS\r
321EFIAPI\r
322PlatformVTdSampleInitialize (\r
323 IN EFI_HANDLE ImageHandle,\r
324 IN EFI_SYSTEM_TABLE *SystemTable\r
325 )\r
326{\r
327 EFI_STATUS Status;\r
328 EFI_HANDLE Handle;\r
329\r
330 Handle = NULL;\r
331 Status = gBS->InstallMultipleProtocolInterfaces (\r
332 &Handle,\r
333 &gEdkiiPlatformVTdPolicyProtocolGuid, &mPlatformVTdSample,\r
334 NULL\r
335 );\r
336 ASSERT_EFI_ERROR (Status);\r
337\r
338 return Status;\r
339}\r