]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
SourceLevelDebugPkg DebugUsb3: Support IOMMU
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugCommunicationLibUsb3 / DebugCommunicationLibUsb3Pei.c
1 /** @file
2 Debug Port Library implementation based on usb3 debug port.
3
4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this 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,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <PiPei.h>
16 #include <Library/PeiServicesLib.h>
17 #include <Library/HobLib.h>
18 #include <Ppi/MemoryDiscovered.h>
19 #include <Ppi/IoMmu.h>
20 #include "DebugCommunicationLibUsb3Internal.h"
21
22 GUID gUsb3DbgGuid = USB3_DBG_GUID;
23
24 /**
25 USB3 IOMMU PPI notify.
26
27 @param[in] PeiServices Pointer to PEI Services Table.
28 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
29 caused this function to execute.
30 @param[in] Ppi Pointer to the PPI data associated with this function.
31
32 @retval EFI_STATUS Always return EFI_SUCCESS
33 **/
34 EFI_STATUS
35 EFIAPI
36 Usb3IoMmuPpiNotify (
37 IN EFI_PEI_SERVICES **PeiServices,
38 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
39 IN VOID *Ppi
40 )
41 {
42 USB3_DEBUG_PORT_HANDLE *Instance;
43
44 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
45
46 Instance = GetUsb3DebugPortInstance ();
47 ASSERT (Instance != NULL);
48
49 Instance->InNotify = TRUE;
50
51 //
52 // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI.
53 //
54 InitializeUsbDebugHardware (Instance);
55
56 //
57 // Wait some time for host to be ready after re-initialization.
58 //
59 MicroSecondDelay (1000000);
60
61 Instance->InNotify = FALSE;
62
63 return EFI_SUCCESS;
64 }
65
66 EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = {
67 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
68 &gEdkiiIoMmuPpiGuid,
69 Usb3IoMmuPpiNotify
70 };
71
72 /**
73 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
74 OperationBusMasterCommonBuffer64 mapping.
75
76 @param IoMmu Pointer to IOMMU PPI.
77 @param Pages The number of pages to allocate.
78 @param HostAddress A pointer to store the base system memory address of the
79 allocated range.
80 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
81 access the hosts HostAddress.
82 @param Mapping A resulting value to pass to Unmap().
83
84 @retval EFI_SUCCESS The requested memory pages were allocated.
85 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
86 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
87 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
88 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
89
90 **/
91 EFI_STATUS
92 IoMmuAllocateBuffer (
93 IN EDKII_IOMMU_PPI *IoMmu,
94 IN UINTN Pages,
95 OUT VOID **HostAddress,
96 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
97 OUT VOID **Mapping
98 )
99 {
100 EFI_STATUS Status;
101 UINTN NumberOfBytes;
102
103 *HostAddress = NULL;
104 *DeviceAddress = 0;
105 *Mapping = NULL;
106
107 Status = IoMmu->AllocateBuffer (
108 IoMmu,
109 EfiBootServicesData,
110 Pages,
111 HostAddress,
112 0
113 );
114 if (EFI_ERROR (Status)) {
115 return EFI_OUT_OF_RESOURCES;
116 }
117
118 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
119 Status = IoMmu->Map (
120 IoMmu,
121 EdkiiIoMmuOperationBusMasterCommonBuffer,
122 *HostAddress,
123 &NumberOfBytes,
124 DeviceAddress,
125 Mapping
126 );
127 if (EFI_ERROR (Status)) {
128 IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
129 *HostAddress = NULL;
130 return EFI_OUT_OF_RESOURCES;
131 }
132 Status = IoMmu->SetAttribute (
133 IoMmu,
134 *Mapping,
135 EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
136 );
137 if (EFI_ERROR (Status)) {
138 IoMmu->Unmap (IoMmu, *Mapping);
139 IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
140 *Mapping = NULL;
141 *HostAddress = NULL;
142 return Status;
143 }
144
145 return Status;
146 }
147
148 /**
149 USB3 get IOMMU PPI.
150
151 @return Pointer to IOMMU PPI.
152
153 **/
154 EDKII_IOMMU_PPI *
155 Usb3GetIoMmu (
156 VOID
157 )
158 {
159 EFI_STATUS Status;
160 EDKII_IOMMU_PPI *IoMmu;
161
162 IoMmu = NULL;
163 Status = PeiServicesLocatePpi (
164 &gEdkiiIoMmuPpiGuid,
165 0,
166 NULL,
167 (VOID **) &IoMmu
168 );
169 if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
170 return IoMmu;
171 }
172
173 return NULL;
174 }
175
176 /**
177 Return USB3 debug instance address.
178
179 **/
180 USB3_DEBUG_PORT_HANDLE *
181 GetUsb3DebugPortInstance (
182 VOID
183 )
184 {
185 USB3_DEBUG_PORT_HANDLE *Instance;
186 EFI_PEI_HOB_POINTERS Hob;
187 EFI_STATUS Status;
188
189 Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
190 if (Hob.Raw == NULL) {
191 //
192 // Save Instance into HOB
193 //
194 Instance = BuildGuidHob (
195 &gUsb3DbgGuid,
196 sizeof (USB3_DEBUG_PORT_HANDLE)
197 );
198 ASSERT (Instance != NULL);
199 ZeroMem (Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
200
201 Instance->FromHob = TRUE;
202 Instance->Initialized = USB3DBG_UNINITIALIZED;
203 } else {
204 Instance = GET_GUID_HOB_DATA (Hob.Guid);
205 }
206
207 if (!Instance->InNotify) {
208 DiscoverInitializeUsbDebugPort (Instance);
209 }
210
211 if (Instance->Ready &&
212 !Instance->PpiNotifyRegistered &&
213 (Usb3GetIoMmu () == NULL)) {
214 Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc);
215 ASSERT_EFI_ERROR (Status);
216 Instance->PpiNotifyRegistered = TRUE;
217 }
218
219 return Instance;
220 }
221
222 /**
223 Allocate aligned memory for XHC's usage.
224
225 @param BufferSize The size, in bytes, of the Buffer.
226
227 @return A pointer to the allocated buffer or NULL if allocation fails.
228
229 **/
230 VOID*
231 AllocateAlignBuffer (
232 IN UINTN BufferSize
233 )
234 {
235 VOID *Buf;
236 EFI_PHYSICAL_ADDRESS Address;
237 EFI_STATUS Status;
238 VOID *MemoryDiscoveredPpi;
239 EDKII_IOMMU_PPI *IoMmu;
240 VOID *HostAddress;
241 VOID *Mapping;
242
243 Buf = NULL;
244
245 //
246 // Make sure the allocated memory is physical memory.
247 //
248 Status = PeiServicesLocatePpi (
249 &gEfiPeiMemoryDiscoveredPpiGuid,
250 0,
251 NULL,
252 (VOID **) &MemoryDiscoveredPpi
253 );
254 if (!EFI_ERROR (Status)) {
255 IoMmu = Usb3GetIoMmu ();
256 if (IoMmu != NULL) {
257 Status = IoMmuAllocateBuffer (
258 IoMmu,
259 EFI_SIZE_TO_PAGES (BufferSize),
260 &HostAddress,
261 &Address,
262 &Mapping
263 );
264 if (!EFI_ERROR (Status)) {
265 ASSERT (Address == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
266 Buf = (VOID *)(UINTN) Address;
267 }
268 } else {
269 Status = PeiServicesAllocatePages (
270 EfiACPIMemoryNVS,
271 EFI_SIZE_TO_PAGES (BufferSize),
272 &Address
273 );
274 if (!EFI_ERROR (Status)) {
275 Buf = (VOID *)(UINTN) Address;
276 }
277 }
278 }
279 return Buf;
280 }
281