]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
SourceLevelDebugPkg: Apply uncrustify changes
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugCommunicationLibUsb3 / DebugCommunicationLibUsb3Dxe.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 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Base.h>
10 #include <PiDxe.h>
11 #include <Library/UefiBootServicesTableLib.h>
12 #include <Library/HobLib.h>
13 #include <Protocol/PciIo.h>
14 #include <Protocol/IoMmu.h>
15 #include <Protocol/DxeSmmReadyToLock.h>
16 #include "DebugCommunicationLibUsb3Internal.h"
17
18 GUID gUsb3DbgGuid = USB3_DBG_GUID;
19
20 USB3_DEBUG_PORT_HANDLE mUsb3Instance = { USB3DBG_UNINITIALIZED };
21 EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;
22 EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;
23 EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
24
25 /**
26 Creates a named event that can be signaled.
27
28 This function creates an event using NotifyTpl, NotifyFunction.
29 If Name is NULL, then ASSERT().
30 If NotifyTpl is not a legal TPL value, then ASSERT().
31 If NotifyFunction is NULL, then ASSERT().
32
33 @param Name Supplies the GUID name of the event.
34 @param NotifyTpl Supplies the task priority level of the event notifications.
35 @param NotifyFunction Supplies the function to notify when the event is signaled.
36 @param Event A pointer to the event created.
37
38 @retval EFI_SUCCESS A named event was created.
39 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
40
41 **/
42 EFI_STATUS
43 EFIAPI
44 Usb3NamedEventListen (
45 IN CONST EFI_GUID *Name,
46 IN EFI_TPL NotifyTpl,
47 IN EFI_EVENT_NOTIFY NotifyFunction,
48 IN EFI_EVENT *Event
49 )
50 {
51 EFI_STATUS Status;
52 VOID *RegistrationLocal;
53
54 ASSERT (Name != NULL);
55 ASSERT (NotifyFunction != NULL);
56 ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
57
58 //
59 // Create event
60 //
61 Status = gBS->CreateEvent (
62 EVT_NOTIFY_SIGNAL,
63 NotifyTpl,
64 NotifyFunction,
65 NULL,
66 Event
67 );
68 ASSERT_EFI_ERROR (Status);
69
70 //
71 // Register for an installation of protocol interface
72 //
73 Status = gBS->RegisterProtocolNotify (
74 (EFI_GUID *)Name,
75 *Event,
76 &RegistrationLocal
77 );
78 ASSERT_EFI_ERROR (Status);
79
80 return Status;
81 }
82
83 /**
84 USB3 map one DMA buffer.
85
86 @param PciIo Pointer to PciIo for USB3 debug port.
87 @param Address DMA buffer address to be mapped.
88 @param NumberOfBytes Number of bytes to be mapped.
89
90 **/
91 VOID
92 Usb3MapOneDmaBuffer (
93 IN EFI_PCI_IO_PROTOCOL *PciIo,
94 IN EFI_PHYSICAL_ADDRESS Address,
95 IN UINTN NumberOfBytes
96 )
97 {
98 EFI_STATUS Status;
99 VOID *HostAddress;
100 EFI_PHYSICAL_ADDRESS DeviceAddress;
101 VOID *Mapping;
102
103 HostAddress = (VOID *)(UINTN)Address;
104 Status = PciIo->Map (
105 PciIo,
106 EfiPciIoOperationBusMasterCommonBuffer,
107 HostAddress,
108 &NumberOfBytes,
109 &DeviceAddress,
110 &Mapping
111 );
112 ASSERT_EFI_ERROR (Status);
113 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));
114 }
115
116 /**
117 USB3 map DMA buffers.
118
119 @param Instance Pointer to USB3 debug port instance.
120 @param PciIo Pointer to PciIo for USB3 debug port.
121
122 **/
123 VOID
124 Usb3MapDmaBuffers (
125 IN USB3_DEBUG_PORT_HANDLE *Instance,
126 IN EFI_PCI_IO_PROTOCOL *PciIo
127 )
128 {
129 Usb3MapOneDmaBuffer (
130 PciIo,
131 Instance->UrbIn.Data,
132 XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
133 );
134
135 Usb3MapOneDmaBuffer (
136 PciIo,
137 Instance->TransferRingIn.RingSeg0,
138 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
139 );
140
141 Usb3MapOneDmaBuffer (
142 PciIo,
143 Instance->TransferRingOut.RingSeg0,
144 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
145 );
146
147 Usb3MapOneDmaBuffer (
148 PciIo,
149 Instance->EventRing.EventRingSeg0,
150 sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
151 );
152
153 Usb3MapOneDmaBuffer (
154 PciIo,
155 Instance->EventRing.ERSTBase,
156 sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
157 );
158
159 Usb3MapOneDmaBuffer (
160 PciIo,
161 Instance->DebugCapabilityContext,
162 sizeof (XHC_DC_CONTEXT)
163 );
164
165 Usb3MapOneDmaBuffer (
166 PciIo,
167 ((XHC_DC_CONTEXT *)(UINTN)Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
168 STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
169 );
170 }
171
172 /**
173 Invoke a notification event
174
175 @param[in] Event Event whose notification function is being invoked.
176 @param[in] Context The pointer to the notification function's context,
177 which is implementation-dependent.
178
179 **/
180 VOID
181 EFIAPI
182 Usb3DxeSmmReadyToLockNotify (
183 IN EFI_EVENT Event,
184 IN VOID *Context
185 )
186 {
187 USB3_DEBUG_PORT_HANDLE *Instance;
188
189 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
190
191 Instance = GetUsb3DebugPortInstance ();
192 ASSERT (Instance != NULL);
193
194 Instance->InNotify = TRUE;
195
196 //
197 // For the case that the USB3 debug port instance and DMA buffers are
198 // from PEI HOB with IOMMU enabled.
199 // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
200 // by SMM environment.
201 //
202 InitializeUsbDebugHardware (Instance);
203
204 //
205 // Wait some time for host to be ready after re-initialization.
206 //
207 MicroSecondDelay (1000000);
208
209 Instance->InNotify = FALSE;
210 gBS->CloseEvent (Event);
211 }
212
213 /**
214 USB3 get IOMMU protocol.
215
216 @return Pointer to IOMMU protocol.
217
218 **/
219 EDKII_IOMMU_PROTOCOL *
220 Usb3GetIoMmu (
221 VOID
222 )
223 {
224 EFI_STATUS Status;
225 EDKII_IOMMU_PROTOCOL *IoMmu;
226
227 IoMmu = NULL;
228 Status = gBS->LocateProtocol (
229 &gEdkiiIoMmuProtocolGuid,
230 NULL,
231 (VOID **)&IoMmu
232 );
233 if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
234 return IoMmu;
235 }
236
237 return NULL;
238 }
239
240 /**
241 Invoke a notification event
242
243 @param[in] Event Event whose notification function is being invoked.
244 @param[in] Context The pointer to the notification function's context,
245 which is implementation-dependent.
246
247 **/
248 VOID
249 EFIAPI
250 Usb3PciIoNotify (
251 IN EFI_EVENT Event,
252 IN VOID *Context
253 )
254 {
255 EFI_STATUS Status;
256 UINTN PciIoHandleCount;
257 EFI_HANDLE *PciIoHandleBuffer;
258 UINTN Index;
259 EFI_PCI_IO_PROTOCOL *PciIo;
260 UINTN PciSegment;
261 UINTN PciBusNumber;
262 UINTN PciDeviceNumber;
263 UINTN PciFunctionNumber;
264 UINT32 PciAddress;
265 USB3_DEBUG_PORT_HANDLE *Instance;
266 EFI_EVENT SmmReadyToLockEvent;
267
268 Status = gBS->LocateHandleBuffer (
269 ByProtocol,
270 &gEfiPciIoProtocolGuid,
271 NULL,
272 &PciIoHandleCount,
273 &PciIoHandleBuffer
274 );
275 if (!EFI_ERROR (Status) &&
276 (PciIoHandleBuffer != NULL) &&
277 (PciIoHandleCount != 0))
278 {
279 for (Index = 0; Index < PciIoHandleCount; Index++) {
280 Status = gBS->HandleProtocol (
281 PciIoHandleBuffer[Index],
282 &gEfiPciIoProtocolGuid,
283 (VOID **)&PciIo
284 );
285 ASSERT_EFI_ERROR (Status);
286 Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
287 ASSERT_EFI_ERROR (Status);
288 PciAddress = (UINT32)((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));
289 if (PciAddress == PcdGet32 (PcdUsbXhciPciAddress)) {
290 //
291 // Found the PciIo for USB3 debug port.
292 //
293 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
294 if (Usb3GetIoMmu () != NULL) {
295 Instance = GetUsb3DebugPortInstance ();
296 ASSERT (Instance != NULL);
297 if (Instance->Ready) {
298 Instance->InNotify = TRUE;
299 Usb3MapDmaBuffers (Instance, PciIo);
300 Instance->InNotify = FALSE;
301
302 if (Instance->FromHob) {
303 mUsb3PciIo = PciIo;
304 Usb3NamedEventListen (
305 &gEfiDxeSmmReadyToLockProtocolGuid,
306 TPL_NOTIFY,
307 Usb3DxeSmmReadyToLockNotify,
308 &SmmReadyToLockEvent
309 );
310 }
311 }
312 }
313
314 gBS->CloseEvent (Event);
315 break;
316 }
317 }
318
319 gBS->FreePool (PciIoHandleBuffer);
320 }
321 }
322
323 /**
324 Return USB3 debug instance address pointer.
325
326 **/
327 EFI_PHYSICAL_ADDRESS *
328 GetUsb3DebugPortInstanceAddrPtr (
329 VOID
330 )
331 {
332 if (mUsb3InstanceAddrPtr == NULL) {
333 //
334 // Use the local variables temporarily.
335 //
336 mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)&mUsb3Instance;
337 mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;
338 }
339
340 return mUsb3InstanceAddrPtr;
341 }
342
343 /**
344 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
345 OperationBusMasterCommonBuffer64 mapping.
346
347 @param PciIo Pointer to PciIo for USB3 debug port.
348 @param Pages The number of pages to allocate.
349 @param Address A pointer to store the base system memory address of the
350 allocated range.
351
352 @retval EFI_SUCCESS The requested memory pages were allocated.
353 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
354 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
355 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
356 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
357
358 **/
359 EFI_STATUS
360 Usb3AllocateDmaBuffer (
361 IN EFI_PCI_IO_PROTOCOL *PciIo,
362 IN UINTN Pages,
363 OUT VOID **Address
364 )
365 {
366 EFI_STATUS Status;
367
368 *Address = NULL;
369 Status = PciIo->AllocateBuffer (
370 PciIo,
371 AllocateAnyPages,
372 EfiRuntimeServicesData,
373 Pages,
374 Address,
375 0
376 );
377 if (!EFI_ERROR (Status)) {
378 Usb3MapOneDmaBuffer (
379 PciIo,
380 (EFI_PHYSICAL_ADDRESS)(UINTN)*Address,
381 EFI_PAGES_TO_SIZE (Pages)
382 );
383 }
384
385 return Status;
386 }
387
388 /**
389 Allocate aligned memory for XHC's usage.
390
391 @param BufferSize The size, in bytes, of the Buffer.
392
393 @return A pointer to the allocated buffer or NULL if allocation fails.
394
395 **/
396 VOID *
397 AllocateAlignBuffer (
398 IN UINTN BufferSize
399 )
400 {
401 EFI_PHYSICAL_ADDRESS TmpAddr;
402 EFI_STATUS Status;
403 VOID *Buf;
404
405 Buf = NULL;
406
407 if (gBS != NULL) {
408 if (mUsb3PciIo != NULL) {
409 Usb3AllocateDmaBuffer (
410 mUsb3PciIo,
411 EFI_SIZE_TO_PAGES (BufferSize),
412 &Buf
413 );
414 } else {
415 TmpAddr = 0xFFFFFFFF;
416 Status = gBS->AllocatePages (
417 AllocateMaxAddress,
418 EfiACPIMemoryNVS,
419 EFI_SIZE_TO_PAGES (BufferSize),
420 &TmpAddr
421 );
422 if (!EFI_ERROR (Status)) {
423 Buf = (VOID *)(UINTN)TmpAddr;
424 }
425 }
426 }
427
428 return Buf;
429 }
430
431 /**
432 The constructor function initialize USB3 debug port.
433
434 @param ImageHandle The firmware allocated handle for the EFI image.
435 @param SystemTable A pointer to the EFI System Table.
436
437 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
438
439 **/
440 EFI_STATUS
441 EFIAPI
442 DebugCommunicationUsb3DxeConstructor (
443 IN EFI_HANDLE ImageHandle,
444 IN EFI_SYSTEM_TABLE *SystemTable
445 )
446 {
447 EFI_PHYSICAL_ADDRESS *AddrPtr;
448 USB3_DEBUG_PORT_HANDLE *Instance;
449 EFI_PHYSICAL_ADDRESS Address;
450 EFI_STATUS Status;
451 EFI_EVENT Event;
452
453 Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **)&AddrPtr);
454 if (EFI_ERROR (Status) || (AddrPtr == NULL)) {
455 //
456 // Instead of using local variables, install system configuration table for
457 // the local instance and the buffer to save instance address pointer.
458 //
459 Address = SIZE_4GB;
460 Status = gBS->AllocatePages (
461 AllocateMaxAddress,
462 EfiACPIMemoryNVS,
463 EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),
464 &Address
465 );
466 if (EFI_ERROR (Status)) {
467 return Status;
468 }
469
470 AddrPtr = (EFI_PHYSICAL_ADDRESS *)(UINTN)Address;
471 ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
472 Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);
473 CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
474 *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
475
476 Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);
477 if (EFI_ERROR (Status)) {
478 return Status;
479 }
480 }
481
482 if (mUsb3InstanceAddrPtr != NULL) {
483 *AddrPtr = *mUsb3InstanceAddrPtr;
484 }
485
486 mUsb3InstanceAddrPtr = AddrPtr;
487
488 Instance = GetUsb3DebugPortInstance ();
489 ASSERT (Instance != NULL);
490
491 if (Instance->PciIoEvent == 0) {
492 Status = Usb3NamedEventListen (
493 &gEfiPciIoProtocolGuid,
494 TPL_NOTIFY,
495 Usb3PciIoNotify,
496 &Event
497 );
498 if (!EFI_ERROR (Status)) {
499 Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS)(UINTN)Event;
500 }
501 }
502
503 return EFI_SUCCESS;
504 }
505
506 /**
507 The destructor function.
508
509 @param ImageHandle The firmware allocated handle for the EFI image.
510 @param SystemTable A pointer to the EFI System Table.
511
512 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
513
514 **/
515 EFI_STATUS
516 EFIAPI
517 DebugCommunicationUsb3DxeDestructor (
518 IN EFI_HANDLE ImageHandle,
519 IN EFI_SYSTEM_TABLE *SystemTable
520 )
521 {
522 USB3_DEBUG_PORT_HANDLE *Instance;
523
524 Instance = GetUsb3DebugPortInstance ();
525 ASSERT (Instance != NULL);
526
527 if (Instance->PciIoEvent != 0) {
528 //
529 // Close the event created.
530 //
531 gBS->CloseEvent ((EFI_EVENT)(UINTN)Instance->PciIoEvent);
532 Instance->PciIoEvent = 0;
533 }
534
535 return EFI_SUCCESS;
536 }