1 /** @file
2 Usb3 Debug Port library instance
3
4 Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Base.h>
10
11 #include <PiDxe.h>
12 #include <Library/SerialPortLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/UefiLib.h>
16 #include <Library/PciLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/TimerLib.h>
19 #include <Library/Usb3DebugPortParamLib.h>
20 #include <Protocol/SmmBase2.h>
21 #include <Protocol/SmmAccess2.h>
22 #include <Protocol/IoMmu.h>
23 #include <Protocol/PciIo.h>
24 #include <Protocol/DxeSmmReadyToLock.h>
25 #include "Usb3DebugPortLibInternal.h"
26
27 extern EFI_SMRAM_DESCRIPTOR mSmramCheckRanges[MAX_SMRAM_RANGE];
28 extern UINTN mSmramCheckRangeCount;
29 extern BOOLEAN mUsb3InSmm;
30 extern UINT64 mUsb3MmioSize;
31 extern BOOLEAN mUsb3GetCapSuccess;
32
33 GUID gUsb3DbgGuid = USB3_DBG_GUID;
34
35 USB3_DEBUG_PORT_CONTROLLER mUsb3DebugPort;
36 USB3_DEBUG_PORT_INSTANCE *mUsb3Instance = NULL;
37 EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
38
39 /**
40 Creates a named event that can be signaled.
41
42 This function creates an event using NotifyTpl, NoifyFunction.
43 If Name is NULL, then ASSERT().
44 If NotifyTpl is not a legal TPL value, then ASSERT().
45 If NotifyFunction is NULL, then ASSERT().
46
47 @param Name Supplies the GUID name of the event.
48 @param NotifyTpl Supplies the task priority level of the event notifications.
49 @param NotifyFunction Supplies the function to notify when the event is signaled.
50 @param Event A pointer to the event created.
51
52 @retval EFI_SUCCESS A named event was created.
53 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
54
55 **/
56 EFI_STATUS
57 EFIAPI
Usb3NamedEventListen(IN CONST EFI_GUID * Name,IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,IN EFI_EVENT * Event)58 Usb3NamedEventListen (
59 IN CONST EFI_GUID *Name,
60 IN EFI_TPL NotifyTpl,
61 IN EFI_EVENT_NOTIFY NotifyFunction,
62 IN EFI_EVENT *Event
63 )
64 {
65 EFI_STATUS Status;
66 VOID *RegistrationLocal;
67
68 ASSERT (Name != NULL);
69 ASSERT (NotifyFunction != NULL);
70 ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
71
72 //
73 // Create event
74 //
75 Status = gBS->CreateEvent (
76 EVT_NOTIFY_SIGNAL,
77 NotifyTpl,
78 NotifyFunction,
79 NULL,
80 Event
81 );
82 ASSERT_EFI_ERROR (Status);
83
84 //
85 // Register for an installation of protocol interface
86 //
87 Status = gBS->RegisterProtocolNotify (
88 (EFI_GUID *) Name,
89 *Event,
90 &RegistrationLocal
91 );
92 ASSERT_EFI_ERROR (Status);
93
94 return Status;
95 }
96
97 /**
98 USB3 map one DMA buffer.
99
100 @param PciIo Pointer to PciIo for USB3 debug port.
101 @param Address DMA buffer address to be mapped.
102 @param NumberOfBytes Number of bytes to be mapped.
103
104 **/
105 VOID
Usb3MapOneDmaBuffer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN EFI_PHYSICAL_ADDRESS Address,IN UINTN NumberOfBytes)106 Usb3MapOneDmaBuffer (
107 IN EFI_PCI_IO_PROTOCOL *PciIo,
108 IN EFI_PHYSICAL_ADDRESS Address,
109 IN UINTN NumberOfBytes
110 )
111 {
112 EFI_STATUS Status;
113 VOID *HostAddress;
114 EFI_PHYSICAL_ADDRESS DeviceAddress;
115 VOID *Mapping;
116
117 HostAddress = (VOID *) (UINTN) Address;
118 Status = PciIo->Map (
119 PciIo,
120 EfiPciIoOperationBusMasterCommonBuffer,
121 HostAddress,
122 &NumberOfBytes,
123 &DeviceAddress,
124 &Mapping
125 );
126 ASSERT_EFI_ERROR (Status);
127 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
128 }
129
130 /**
131 USB3 map DMA buffers.
132
133 @param Instance Pointer to USB3 debug port instance.
134 @param PciIo Pointer to PciIo for USB3 debug port.
135
136 **/
137 VOID
Usb3MapDmaBuffers(IN USB3_DEBUG_PORT_INSTANCE * Instance,IN EFI_PCI_IO_PROTOCOL * PciIo)138 Usb3MapDmaBuffers (
139 IN USB3_DEBUG_PORT_INSTANCE *Instance,
140 IN EFI_PCI_IO_PROTOCOL *PciIo
141 )
142 {
143 Usb3MapOneDmaBuffer (
144 PciIo,
145 Instance->Urb.Data,
146 XHC_DEBUG_PORT_DATA_LENGTH
147 );
148
149 Usb3MapOneDmaBuffer (
150 PciIo,
151 Instance->TransferRingIn.RingSeg0,
152 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
153 );
154
155 Usb3MapOneDmaBuffer (
156 PciIo,
157 Instance->TransferRingOut.RingSeg0,
158 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
159 );
160
161 Usb3MapOneDmaBuffer (
162 PciIo,
163 Instance->EventRing.EventRingSeg0,
164 sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
165 );
166
167 Usb3MapOneDmaBuffer (
168 PciIo,
169 Instance->EventRing.ERSTBase,
170 sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
171 );
172
173 Usb3MapOneDmaBuffer (
174 PciIo,
175 Instance->DebugCapabilityContext,
176 sizeof (XHC_DC_CONTEXT)
177 );
178
179 Usb3MapOneDmaBuffer (
180 PciIo,
181 ((XHC_DC_CONTEXT *) (UINTN) Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
182 STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
183 );
184 }
185
186 /**
187 Invoke a notification event
188
189 @param[in] Event Event whose notification function is being invoked.
190 @param[in] Context The pointer to the notification function's context,
191 which is implementation-dependent.
192
193 **/
194 VOID
195 EFIAPI
Usb3DxeSmmReadyToLockNotify(IN EFI_EVENT Event,IN VOID * Context)196 Usb3DxeSmmReadyToLockNotify (
197 IN EFI_EVENT Event,
198 IN VOID *Context
199 )
200 {
201 ASSERT (mUsb3Instance != NULL);
202
203 //
204 // For the case that the USB3 debug port instance and DMA buffers are
205 // from PEI HOB with IOMMU enabled.
206 // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
207 // by SMM environment.
208 //
209 InitializeUsb3DebugPort (mUsb3Instance);
210
211 SaveUsb3InstanceAddress (mUsb3Instance);
212
213 gBS->CloseEvent (Event);
214 }
215
216 /**
217 USB3 get IOMMU protocol.
218
219 @return Pointer to IOMMU protocol.
220
221 **/
222 EDKII_IOMMU_PROTOCOL *
Usb3GetIoMmu(VOID)223 Usb3GetIoMmu (
224 VOID
225 )
226 {
227 EFI_STATUS Status;
228 EDKII_IOMMU_PROTOCOL *IoMmu;
229
230 IoMmu = NULL;
231 Status = gBS->LocateProtocol (
232 &gEdkiiIoMmuProtocolGuid,
233 NULL,
234 (VOID **) &IoMmu
235 );
236 if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
237 return IoMmu;
238 }
239
240 return NULL;
241 }
242
243 /**
244 Invoke a notification event
245
246 @param[in] Event Event whose notification function is being invoked.
247 @param[in] Context The pointer to the notification function's context,
248 which is implementation-dependent.
249
250 **/
251 VOID
252 EFIAPI
Usb3PciIoNotify(IN EFI_EVENT Event,IN VOID * Context)253 Usb3PciIoNotify (
254 IN EFI_EVENT Event,
255 IN VOID *Context
256 )
257 {
258 EFI_STATUS Status;
259 UINTN PciIoHandleCount;
260 EFI_HANDLE *PciIoHandleBuffer;
261 UINTN Index;
262 EFI_PCI_IO_PROTOCOL *PciIo;
263 UINTN PciSegment;
264 UINTN PciBusNumber;
265 UINTN PciDeviceNumber;
266 UINTN PciFunctionNumber;
267 EFI_EVENT SmmReadyToLockEvent;
268
269 Status = gBS->LocateHandleBuffer (
270 ByProtocol,
271 &gEfiPciIoProtocolGuid,
272 NULL,
273 &PciIoHandleCount,
274 &PciIoHandleBuffer
275 );
276 if (!EFI_ERROR (Status) &&
277 (PciIoHandleBuffer != NULL) &&
278 (PciIoHandleCount != 0)) {
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 if ((PciBusNumber == mUsb3DebugPort.PciAddress.Bus) &&
289 (PciDeviceNumber == mUsb3DebugPort.PciAddress.Device) &&
290 (PciFunctionNumber == mUsb3DebugPort.PciAddress.Function)) {
291 //
292 // Found the PciIo for USB3 debug port.
293 //
294 ASSERT (mUsb3Instance != NULL);
295 if (Usb3GetIoMmu () != NULL) {
296 Usb3MapDmaBuffers (mUsb3Instance, PciIo);
297
298 if (mUsb3Instance->FromHob) {
299 mUsb3PciIo = PciIo;
300 Usb3NamedEventListen (
301 &gEfiDxeSmmReadyToLockProtocolGuid,
302 TPL_NOTIFY,
303 Usb3DxeSmmReadyToLockNotify,
304 &SmmReadyToLockEvent
305 );
306 }
307 }
308 gBS->CloseEvent (Event);
309 break;
310 }
311 }
312
313 gBS->FreePool (PciIoHandleBuffer);
314 }
315 }
316
317 /**
318 Return XHCI MMIO base address.
319
320 **/
321 EFI_PHYSICAL_ADDRESS
GetXhciBaseAddress(VOID)322 GetXhciBaseAddress (
323 VOID
324 )
325 {
326 UINT8 Bus;
327 UINT8 Device;
328 UINT8 Function;
329 EFI_PHYSICAL_ADDRESS Address;
330 UINT32 Low;
331 UINT32 High;
332
333 if (mUsb3DebugPort.Controller == 0) {
334 mUsb3DebugPort.Controller = GetUsb3DebugPortController();
335 }
336
337 Bus = mUsb3DebugPort.PciAddress.Bus;
338 Device = mUsb3DebugPort.PciAddress.Device;
339 Function = mUsb3DebugPort.PciAddress.Function;
340
341 Low = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
342 High = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
343 Address = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
344 //
345 // Mask other parts which are not part of base address
346 //
347 Address &= XHCI_BASE_ADDRESS_64_BIT_MASK;
348 return Address;
349 }
350
351 /**
352 Return XHCI debug instance address.
353
354 **/
355 USB3_DEBUG_PORT_INSTANCE *
GetUsb3DebugPortInstance(VOID)356 GetUsb3DebugPortInstance (
357 VOID
358 )
359 {
360 USB3_DEBUG_PORT_INSTANCE *Instance;
361 EFI_PHYSICAL_ADDRESS XhcMmioBase;
362 UINT64 CapabilityPointer;
363 UINT32 Capability;
364 BOOLEAN Flag;
365 UINT8 Bus;
366 UINT8 Device;
367 UINT8 Function;
368 UINT16 Command;
369 USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
370
371 Instance = NULL;
372
373 XhcMmioBase = GetXhciBaseAddress ();
374
375 if ((XhcMmioBase == 0) || (XhcMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
376 return NULL;
377 }
378
379 if (mUsb3Instance != NULL) {
380 FixUsb3InstanceResource (mUsb3Instance, XhcMmioBase);
381 return mUsb3Instance;
382 }
383
384 Command = GetXhciPciCommand ();
385
386 UsbDebugPort.Controller = GetUsb3DebugPortController();
387 Bus = UsbDebugPort.PciAddress.Bus;
388 Device = UsbDebugPort.PciAddress.Device;
389 Function = UsbDebugPort.PciAddress.Function;
390
391 //
392 // Set Command Register
393 //
394 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
395 PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
396 PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
397 }
398
399 //
400 // Calculate capability offset from HCCPARAMS [16:31], in 32-bit words
401 //
402 CapabilityPointer = XhcMmioBase + (MmioRead32 ((UINTN)(XhcMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
403
404 //
405 // Search XHCI debug capability
406 //
407 Flag = FALSE;
408 Capability = MmioRead32 ((UINTN)CapabilityPointer);
409 while (TRUE) {
410 if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
411 Flag = TRUE;
412 break;
413 }
414 if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
415 //
416 // Reach the end of list, quit
417 //
418 break;
419 }
420 CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
421 Capability = MmioRead32 ((UINTN)CapabilityPointer);
422 }
423
424 if (Flag) {
425 Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN) MmioRead32 ((UINTN) (CapabilityPointer + XHC_DC_DCDDI2));
426
427 if (Instance != NULL) {
428 FixUsb3InstanceResource (Instance, XhcMmioBase);
429 }
430 }
431
432 //
433 // Restore Command Register
434 //
435 PciWrite16(PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
436
437 return Instance;
438 }
439
440
441 /**
442 Initialize USB3 debug port.
443
444 This method invokes various internal functions to facilitate
445 detection and initialization of USB3 debug port.
446
447 @retval RETURN_SUCCESS The USB3 debug port was initialized.
448 **/
449 RETURN_STATUS
450 EFIAPI
USB3Initialize(VOID)451 USB3Initialize (
452 VOID
453 )
454 {
455 //
456 // Leave it empty, we assume PEI phase already do initialization
457 //
458 return RETURN_SUCCESS;
459 }
460
461 /**
462 Initialize USB3 debug port.
463
464 This method invokes various internal functions to facilitate
465 detection and initialization of USB3 debug port.
466
467 @retval RETURN_SUCCESS The serial device was initialized.
468 **/
469 RETURN_STATUS
470 EFIAPI
USB3InitializeReal(VOID)471 USB3InitializeReal (
472 VOID
473 )
474 {
475 USB3_DEBUG_PORT_INSTANCE UsbDbg;
476 USB3_DEBUG_PORT_INSTANCE *Instance;
477 EFI_PHYSICAL_ADDRESS Address;
478 EFI_STATUS Status;
479 EFI_EVENT Event;
480
481 if ((gST == NULL) || (gBS == NULL)) {
482 //
483 // gST and gBS have not been initialized yet
484 //
485 return EFI_DEVICE_ERROR;
486 }
487
488 Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &mUsb3Instance);
489 if (!EFI_ERROR (Status)) {
490 goto Done;
491 }
492
493 //
494 // It is first time to run DXE instance, copy Instance from Hob to ACPINvs
495 // NOTE: Hob is not ready at this time, so copy it from XHCI register.
496 //
497 Instance = GetUsb3DebugPortInstance ();
498 if (Instance == NULL) {
499 //
500 // Initialize USB debug
501 //
502 SetMem (&UsbDbg, sizeof(UsbDbg), 0);
503 DiscoverUsb3DebugPort (&UsbDbg);
504 if (UsbDbg.DebugSupport) {
505 InitializeUsb3DebugPort (&UsbDbg);
506 }
507 Instance = &UsbDbg;
508 }
509 Address = SIZE_4GB;
510 Status = gBS->AllocatePages (
511 AllocateMaxAddress,
512 EfiACPIMemoryNVS,
513 EFI_SIZE_TO_PAGES (sizeof (USB3_DEBUG_PORT_INSTANCE)),
514 &Address
515 );
516 if (EFI_ERROR (Status)) {
517 return Status;
518 }
519
520 CopyMem (
521 (VOID *)(UINTN)Address,
522 Instance,
523 sizeof (USB3_DEBUG_PORT_INSTANCE)
524 );
525 mUsb3Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN)Address;
526
527 Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, mUsb3Instance);
528 if (EFI_ERROR (Status)) {
529 return Status;
530 }
531
532 if (mUsb3Instance->DebugSupport) {
533 SaveUsb3InstanceAddress (mUsb3Instance);
534 }
535
536 Done:
537 if ((mUsb3Instance != NULL) && mUsb3Instance->Ready && (mUsb3Instance->PciIoEvent == 0)) {
538 Status = Usb3NamedEventListen (
539 &gEfiPciIoProtocolGuid,
540 TPL_NOTIFY,
541 Usb3PciIoNotify,
542 &Event
543 );
544 if (!EFI_ERROR (Status)) {
545 mUsb3Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS) (UINTN) Event;
546 }
547 }
548
549 return RETURN_SUCCESS;
550 }
551
552 /**
553 Calculate the size of XHCI MMIO space.
554
555 @retval TURE The XHCI MMIO is in SMRAM ranges.
556 @retval FALSE The XHCI MMIO is out of SMRAM ranges.
557 **/
558 UINT64
CalculateMmioSize(VOID)559 CalculateMmioSize (
560 VOID
561 )
562 {
563 UINT8 Bus;
564 UINT8 Device;
565 UINT8 Function;
566 UINT32 Value;
567 UINT32 Mask;
568 UINT64 MmioSize;
569 UINT16 Command;
570 USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
571 EFI_PHYSICAL_ADDRESS XhcMmioBase;
572
573 UsbDebugPort.Controller = GetUsb3DebugPortController();
574 Bus = UsbDebugPort.PciAddress.Bus;
575 Device = UsbDebugPort.PciAddress.Device;
576 Function = UsbDebugPort.PciAddress.Function;
577
578 Mask = 0xFFFFFFF0;
579 MmioSize = 0;
580
581 XhcMmioBase = GetXhciBaseAddress ();
582
583 //
584 // Disable MSE
585 //
586 Command = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
587 PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command & ~(EFI_PCI_COMMAND_MEMORY_SPACE));
588
589 //
590 // Get Mmio Size
591 //
592 PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), 0xFFFFFFFF);
593 Value = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
594
595 switch (Value & 0x07) {
596 case 0x0:
597 //
598 // Memory space: anywhere in 32 bit address space
599 //
600 MmioSize = (~(Value & Mask)) + 1;
601 break;
602 case 0x4:
603 //
604 // Memory space: anywhere in 64 bit address space
605 //
606 MmioSize = Value & Mask;
607 PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);
608 Value = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
609 //
610 // Fix the length to support some spefic 64 bit BAR
611 //
612 Value |= ((UINT32)(-1) << HighBitSet32 (Value));
613 //
614 // Calculate the size of 64bit bar
615 //
616 MmioSize |= LShiftU64 ((UINT64) Value, 32);
617 MmioSize = (~(MmioSize)) + 1;
618 break;
619 default:
620 //
621 // Unknown BAR type
622 //
623 MmioSize = (~(Value & Mask)) + 1;
624 break;
625 };
626
627
628 //
629 // Restore MMIO address
630 //
631 PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)XhcMmioBase);
632 PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), (UINT32) (XhcMmioBase >> 32));
633
634 PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
635
636 return MmioSize;
637 }
638
639 /**
640 The constructor function initialize USB3 debug port.
641
642 @param ImageHandle The firmware allocated handle for the EFI image.
643 @param SystemTable A pointer to the EFI System Table.
644
645 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
646
647 **/
648 EFI_STATUS
649 EFIAPI
Usb3DebugPortLibDxeConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)650 Usb3DebugPortLibDxeConstructor (
651 IN EFI_HANDLE ImageHandle,
652 IN EFI_SYSTEM_TABLE *SystemTable
653 )
654 {
655 EFI_SMM_BASE2_PROTOCOL *SmmBase;
656 EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
657 UINTN Size;
658 EFI_STATUS Status;
659
660 //
661 // Do real initialization here, because we need copy data from Hob to ACPINvs.
662 // We must do it in constructor because it depends on UefiBootServicesTableLib.
663 //
664 if (FeaturePcdGet (PcdUsb3DebugFeatureEnable)) {
665 USB3InitializeReal ();
666 }
667
668 mUsb3MmioSize = CalculateMmioSize ();
669
670 if (gBS != NULL) {
671 SmmBase = NULL;
672 Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&SmmBase);
673 if (!EFI_ERROR (Status)) {
674 SmmBase->InSmm(SmmBase, &mUsb3InSmm);
675 }
676
677 if (mUsb3InSmm) {
678 //
679 // Get SMRAM information
680 //
681 SmmAccess = NULL;
682 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
683 if (!EFI_ERROR (Status)) {
684 Size = sizeof (mSmramCheckRanges);
685
686 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramCheckRanges);
687 if (!EFI_ERROR (Status)) {
688 mSmramCheckRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
689 }
690 }
691 }
692 }
693
694 return EFI_SUCCESS;
695 }
696
697 /**
698 The destructor function.
699
700 @param ImageHandle The firmware allocated handle for the EFI image.
701 @param SystemTable A pointer to the EFI System Table.
702
703 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
704
705 **/
706 EFI_STATUS
707 EFIAPI
Usb3DebugPortLibDxeDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)708 Usb3DebugPortLibDxeDestructor (
709 IN EFI_HANDLE ImageHandle,
710 IN EFI_SYSTEM_TABLE *SystemTable
711 )
712 {
713 if ((mUsb3Instance != NULL) && (mUsb3Instance->PciIoEvent != 0)) {
714 //
715 // Close the event created.
716 //
717 gBS->CloseEvent ((EFI_EVENT) (UINTN) mUsb3Instance->PciIoEvent);
718 mUsb3Instance->PciIoEvent = 0;
719 }
720 return EFI_SUCCESS;
721 }
722
723 /**
724 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
725 OperationBusMasterCommonBuffer64 mapping.
726
727 @param PciIo Pointer to PciIo for USB3 debug port.
728 @param Pages The number of pages to allocate.
729 @param Address A pointer to store the base system memory address of the
730 allocated range.
731
732 @retval EFI_SUCCESS The requested memory pages were allocated.
733 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
734 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
735 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
736 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
737
738 **/
739 EFI_STATUS
Usb3AllocateDmaBuffer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINTN Pages,OUT VOID ** Address)740 Usb3AllocateDmaBuffer (
741 IN EFI_PCI_IO_PROTOCOL *PciIo,
742 IN UINTN Pages,
743 OUT VOID **Address
744 )
745 {
746 EFI_STATUS Status;
747
748 *Address = NULL;
749 Status = PciIo->AllocateBuffer (
750 PciIo,
751 AllocateAnyPages,
752 EfiRuntimeServicesData,
753 Pages,
754 Address,
755 0
756 );
757 if (!EFI_ERROR (Status)) {
758 Usb3MapOneDmaBuffer (
759 PciIo,
760 (EFI_PHYSICAL_ADDRESS) (UINTN) *Address,
761 EFI_PAGES_TO_SIZE (Pages)
762 );
763 }
764 return Status;
765 }
766
767 /**
768 Allocate aligned memory for XHC's usage.
769
770 @param BufferSize The size, in bytes, of the Buffer.
771
772 @return A pointer to the allocated buffer or NULL if allocation fails.
773
774 **/
775 VOID*
AllocateAlignBuffer(IN UINTN BufferSize)776 AllocateAlignBuffer (
777 IN UINTN BufferSize
778 )
779 {
780 VOID *Buf;
781 EFI_PHYSICAL_ADDRESS Address;
782 EFI_STATUS Status;
783
784 Buf = NULL;
785
786 if (gBS != NULL) {
787 if (mUsb3PciIo != NULL) {
788 Usb3AllocateDmaBuffer (
789 mUsb3PciIo,
790 EFI_SIZE_TO_PAGES (BufferSize),
791 &Buf
792 );
793 } else {
794 Address = 0xFFFFFFFF;
795 Status = gBS->AllocatePages (
796 AllocateMaxAddress,
797 EfiACPIMemoryNVS,
798 EFI_SIZE_TO_PAGES (BufferSize),
799 &Address
800 );
801 if (!EFI_ERROR (Status)) {
802 Buf = (VOID *)(UINTN)Address;
803 }
804 }
805 }
806
807 return Buf;
808 }
809
810 /**
811 Check whether AllocatePages in permanent memory is ready.
812
813 @retval TRUE AllocatePages in permanent memory is ready.
814 @retval FALSE AllocatePages in permanent memory is not ready.
815
816 **/
817 BOOLEAN
IsAllocatePagesReady(VOID)818 IsAllocatePagesReady (
819 VOID
820 )
821 {
822 if (gBS != NULL) {
823 return TRUE;
824 }
825
826 return FALSE;
827 }
828
829