]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
SourceLevelDebugPkg/DebugCommunicationLib: Fix various typos
[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 for (Index = 0; Index < PciIoHandleCount; Index++) {
279 Status = gBS->HandleProtocol (
280 PciIoHandleBuffer[Index],
281 &gEfiPciIoProtocolGuid,
282 (VOID **) &PciIo
283 );
284 ASSERT_EFI_ERROR (Status);
285 Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
286 ASSERT_EFI_ERROR (Status);
287 PciAddress = (UINT32) ((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));
288 if (PciAddress == PcdGet32(PcdUsbXhciPciAddress)) {
289 //
290 // Found the PciIo for USB3 debug port.
291 //
292 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
293 if (Usb3GetIoMmu () != NULL) {
294 Instance = GetUsb3DebugPortInstance ();
295 ASSERT (Instance != NULL);
296 if (Instance->Ready) {
297 Instance->InNotify = TRUE;
298 Usb3MapDmaBuffers (Instance, PciIo);
299 Instance->InNotify = FALSE;
300
301 if (Instance->FromHob) {
302 mUsb3PciIo = PciIo;
303 Usb3NamedEventListen (
304 &gEfiDxeSmmReadyToLockProtocolGuid,
305 TPL_NOTIFY,
306 Usb3DxeSmmReadyToLockNotify,
307 &SmmReadyToLockEvent
308 );
309 }
310 }
311 }
312 gBS->CloseEvent (Event);
313 break;
314 }
315 }
316
317 gBS->FreePool (PciIoHandleBuffer);
318 }
319 }
320
321 /**
322 Return USB3 debug instance address pointer.
323
324 **/
325 EFI_PHYSICAL_ADDRESS *
326 GetUsb3DebugPortInstanceAddrPtr (
327 VOID
328 )
329 {
330 if (mUsb3InstanceAddrPtr == NULL) {
331 //
332 // Use the local variables temporarily.
333 //
334 mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) &mUsb3Instance;
335 mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;
336 }
337 return mUsb3InstanceAddrPtr;
338 }
339
340 /**
341 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
342 OperationBusMasterCommonBuffer64 mapping.
343
344 @param PciIo Pointer to PciIo for USB3 debug port.
345 @param Pages The number of pages to allocate.
346 @param Address A pointer to store the base system memory address of the
347 allocated range.
348
349 @retval EFI_SUCCESS The requested memory pages were allocated.
350 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
351 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
352 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
353 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
354
355 **/
356 EFI_STATUS
357 Usb3AllocateDmaBuffer (
358 IN EFI_PCI_IO_PROTOCOL *PciIo,
359 IN UINTN Pages,
360 OUT VOID **Address
361 )
362 {
363 EFI_STATUS Status;
364
365 *Address = NULL;
366 Status = PciIo->AllocateBuffer (
367 PciIo,
368 AllocateAnyPages,
369 EfiRuntimeServicesData,
370 Pages,
371 Address,
372 0
373 );
374 if (!EFI_ERROR (Status)) {
375 Usb3MapOneDmaBuffer (
376 PciIo,
377 (EFI_PHYSICAL_ADDRESS) (UINTN) *Address,
378 EFI_PAGES_TO_SIZE (Pages)
379 );
380 }
381 return Status;
382 }
383
384 /**
385 Allocate aligned memory for XHC's usage.
386
387 @param BufferSize The size, in bytes, of the Buffer.
388
389 @return A pointer to the allocated buffer or NULL if allocation fails.
390
391 **/
392 VOID*
393 AllocateAlignBuffer (
394 IN UINTN BufferSize
395 )
396 {
397 EFI_PHYSICAL_ADDRESS TmpAddr;
398 EFI_STATUS Status;
399 VOID *Buf;
400
401 Buf = NULL;
402
403 if (gBS != NULL) {
404 if (mUsb3PciIo != NULL) {
405 Usb3AllocateDmaBuffer (
406 mUsb3PciIo,
407 EFI_SIZE_TO_PAGES (BufferSize),
408 &Buf
409 );
410 } else {
411 TmpAddr = 0xFFFFFFFF;
412 Status = gBS->AllocatePages (
413 AllocateMaxAddress,
414 EfiACPIMemoryNVS,
415 EFI_SIZE_TO_PAGES (BufferSize),
416 &TmpAddr
417 );
418 if (!EFI_ERROR (Status)) {
419 Buf = (VOID *) (UINTN) TmpAddr;
420 }
421 }
422 }
423
424 return Buf;
425 }
426
427 /**
428 The constructor function initialize USB3 debug port.
429
430 @param ImageHandle The firmware allocated handle for the EFI image.
431 @param SystemTable A pointer to the EFI System Table.
432
433 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
434
435 **/
436 EFI_STATUS
437 EFIAPI
438 DebugCommunicationUsb3DxeConstructor (
439 IN EFI_HANDLE ImageHandle,
440 IN EFI_SYSTEM_TABLE *SystemTable
441 )
442 {
443 EFI_PHYSICAL_ADDRESS *AddrPtr;
444 USB3_DEBUG_PORT_HANDLE *Instance;
445 EFI_PHYSICAL_ADDRESS Address;
446 EFI_STATUS Status;
447 EFI_EVENT Event;
448
449 Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &AddrPtr);
450 if (EFI_ERROR (Status) || (AddrPtr == NULL)) {
451 //
452 // Instead of using local variables, install system configuration table for
453 // the local instance and the buffer to save instance address pointer.
454 //
455 Address = SIZE_4GB;
456 Status = gBS->AllocatePages (
457 AllocateMaxAddress,
458 EfiACPIMemoryNVS,
459 EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),
460 &Address
461 );
462 if (EFI_ERROR (Status)) {
463 return Status;
464 }
465
466 AddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) Address;
467 ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
468 Instance = (USB3_DEBUG_PORT_HANDLE *) (AddrPtr + 1);
469 CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
470 *AddrPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) Instance;
471
472 Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);
473 if (EFI_ERROR (Status)) {
474 return Status;
475 }
476 }
477
478 if (mUsb3InstanceAddrPtr != NULL) {
479 *AddrPtr = *mUsb3InstanceAddrPtr;
480 }
481 mUsb3InstanceAddrPtr = AddrPtr;
482
483 Instance = GetUsb3DebugPortInstance ();
484 ASSERT (Instance != NULL);
485
486 if (Instance->PciIoEvent == 0) {
487 Status = Usb3NamedEventListen (
488 &gEfiPciIoProtocolGuid,
489 TPL_NOTIFY,
490 Usb3PciIoNotify,
491 &Event
492 );
493 if (!EFI_ERROR (Status)) {
494 Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS) (UINTN) Event;
495 }
496 }
497
498 return EFI_SUCCESS;
499 }
500
501 /**
502 The destructor function.
503
504 @param ImageHandle The firmware allocated handle for the EFI image.
505 @param SystemTable A pointer to the EFI System Table.
506
507 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
508
509 **/
510 EFI_STATUS
511 EFIAPI
512 DebugCommunicationUsb3DxeDestructor (
513 IN EFI_HANDLE ImageHandle,
514 IN EFI_SYSTEM_TABLE *SystemTable
515 )
516 {
517 USB3_DEBUG_PORT_HANDLE *Instance;
518
519 Instance = GetUsb3DebugPortInstance ();
520 ASSERT (Instance != NULL);
521
522 if (Instance->PciIoEvent != 0) {
523 //
524 // Close the event created.
525 //
526 gBS->CloseEvent ((EFI_EVENT) (UINTN) Instance->PciIoEvent);
527 Instance->PciIoEvent = 0;
528 }
529 return EFI_SUCCESS;
530 }
531