]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
SourceLevelDebugPkg DebugUsb3: Re-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 if (!Instance->Ready) {
49 return EFI_SUCCESS;
50 }
51
52 Instance->InNotify = TRUE;
53
54 //
55 // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI.
56 //
57 InitializeUsbDebugHardware (Instance);
58
59 //
60 // Wait some time for host to be ready after re-initialization.
61 //
62 MicroSecondDelay (1000000);
63
64 Instance->InNotify = FALSE;
65
66 return EFI_SUCCESS;
67 }
68
69 EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = {
70 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
71 &gEdkiiIoMmuPpiGuid,
72 Usb3IoMmuPpiNotify
73 };
74
75 /**
76 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
77 OperationBusMasterCommonBuffer64 mapping.
78
79 @param IoMmu Pointer to IOMMU PPI.
80 @param Pages The number of pages to allocate.
81 @param HostAddress A pointer to store the base system memory address of the
82 allocated range.
83 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
84 access the hosts HostAddress.
85 @param Mapping A resulting value to pass to Unmap().
86
87 @retval EFI_SUCCESS The requested memory pages were allocated.
88 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
89 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
90 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
91 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
92
93 **/
94 EFI_STATUS
95 IoMmuAllocateBuffer (
96 IN EDKII_IOMMU_PPI *IoMmu,
97 IN UINTN Pages,
98 OUT VOID **HostAddress,
99 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
100 OUT VOID **Mapping
101 )
102 {
103 EFI_STATUS Status;
104 UINTN NumberOfBytes;
105
106 *HostAddress = NULL;
107 *DeviceAddress = 0;
108 *Mapping = NULL;
109
110 Status = IoMmu->AllocateBuffer (
111 IoMmu,
112 EfiRuntimeServicesData,
113 Pages,
114 HostAddress,
115 0
116 );
117 if (EFI_ERROR (Status)) {
118 return EFI_OUT_OF_RESOURCES;
119 }
120
121 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
122 Status = IoMmu->Map (
123 IoMmu,
124 EdkiiIoMmuOperationBusMasterCommonBuffer,
125 *HostAddress,
126 &NumberOfBytes,
127 DeviceAddress,
128 Mapping
129 );
130 if (EFI_ERROR (Status)) {
131 IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
132 *HostAddress = NULL;
133 return EFI_OUT_OF_RESOURCES;
134 }
135 Status = IoMmu->SetAttribute (
136 IoMmu,
137 *Mapping,
138 EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
139 );
140 if (EFI_ERROR (Status)) {
141 IoMmu->Unmap (IoMmu, *Mapping);
142 IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
143 *Mapping = NULL;
144 *HostAddress = NULL;
145 return Status;
146 }
147
148 return Status;
149 }
150
151 /**
152 USB3 get IOMMU PPI.
153
154 @return Pointer to IOMMU PPI.
155
156 **/
157 EDKII_IOMMU_PPI *
158 Usb3GetIoMmu (
159 VOID
160 )
161 {
162 EFI_STATUS Status;
163 EDKII_IOMMU_PPI *IoMmu;
164
165 IoMmu = NULL;
166 Status = PeiServicesLocatePpi (
167 &gEdkiiIoMmuPpiGuid,
168 0,
169 NULL,
170 (VOID **) &IoMmu
171 );
172 if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
173 return IoMmu;
174 }
175
176 return NULL;
177 }
178
179 /**
180 Return USB3 debug instance address pointer.
181
182 **/
183 EFI_PHYSICAL_ADDRESS *
184 GetUsb3DebugPortInstanceAddrPtr (
185 VOID
186 )
187 {
188 USB3_DEBUG_PORT_HANDLE *Instance;
189 EFI_PHYSICAL_ADDRESS *AddrPtr;
190 EFI_PEI_HOB_POINTERS Hob;
191 EFI_STATUS Status;
192
193 Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
194 if (Hob.Raw == NULL) {
195 //
196 // Build HOB for the local instance and the buffer to save instance address pointer.
197 // Use the local instance in HOB temporarily.
198 //
199 AddrPtr = BuildGuidHob (
200 &gUsb3DbgGuid,
201 sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)
202 );
203 ASSERT (AddrPtr != NULL);
204 ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
205 Instance = (USB3_DEBUG_PORT_HANDLE *) (AddrPtr + 1);
206 *AddrPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) Instance;
207 Instance->FromHob = TRUE;
208 Instance->Initialized = USB3DBG_UNINITIALIZED;
209 if (Usb3GetIoMmu () == NULL) {
210 Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc);
211 ASSERT_EFI_ERROR (Status);
212 }
213 } else {
214 AddrPtr = GET_GUID_HOB_DATA (Hob.Guid);
215 }
216
217 return AddrPtr;
218 }
219
220 /**
221 Allocate aligned memory for XHC's usage.
222
223 @param BufferSize The size, in bytes, of the Buffer.
224
225 @return A pointer to the allocated buffer or NULL if allocation fails.
226
227 **/
228 VOID*
229 AllocateAlignBuffer (
230 IN UINTN BufferSize
231 )
232 {
233 VOID *Buf;
234 EFI_PHYSICAL_ADDRESS Address;
235 EFI_STATUS Status;
236 VOID *MemoryDiscoveredPpi;
237 EDKII_IOMMU_PPI *IoMmu;
238 VOID *HostAddress;
239 VOID *Mapping;
240
241 Buf = NULL;
242
243 //
244 // Make sure the allocated memory is physical memory.
245 //
246 Status = PeiServicesLocatePpi (
247 &gEfiPeiMemoryDiscoveredPpiGuid,
248 0,
249 NULL,
250 (VOID **) &MemoryDiscoveredPpi
251 );
252 if (!EFI_ERROR (Status)) {
253 IoMmu = Usb3GetIoMmu ();
254 if (IoMmu != NULL) {
255 Status = IoMmuAllocateBuffer (
256 IoMmu,
257 EFI_SIZE_TO_PAGES (BufferSize),
258 &HostAddress,
259 &Address,
260 &Mapping
261 );
262 if (!EFI_ERROR (Status)) {
263 ASSERT (Address == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
264 Buf = (VOID *)(UINTN) Address;
265 }
266 } else {
267 Status = PeiServicesAllocatePages (
268 EfiACPIMemoryNVS,
269 EFI_SIZE_TO_PAGES (BufferSize),
270 &Address
271 );
272 if (!EFI_ERROR (Status)) {
273 Buf = (VOID *)(UINTN) Address;
274 }
275 }
276 }
277 return Buf;
278 }
279