]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
MdeModulePkg XhciPei: Minor refinement about IoMmu
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / XhcPeim.c
1 /** @file
2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4
5 Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include "XhcPeim.h"
19
20 //
21 // Two arrays used to translate the XHCI port state (change)
22 // to the UEFI protocol's port state (change).
23 //
24 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
25 {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
26 {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE},
27 {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
28 {XHC_PORTSC_PP, USB_PORT_STAT_POWER},
29 {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}
30 };
31
32 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
33 {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
34 {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
35 {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
36 {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
37 };
38
39 USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
40 {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
41 {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
42 {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
43 {XHC_PORTSC_PRC, EfiUsbPortResetChange}
44 };
45
46 USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
47 {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
48 {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},
49 {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
50 {XHC_HUB_PORTSC_PP, USB_PORT_STAT_POWER},
51 {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}
52 };
53
54 USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
55 {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
56 {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
57 {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
58 {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
59 };
60
61 USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
62 {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
63 {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
64 {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
65 {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
66 {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
67 };
68
69 /**
70 Read XHCI Operation register.
71
72 @param Xhc The XHCI device.
73 @param Offset The operation register offset.
74
75 @retval the register content read.
76
77 **/
78 UINT32
79 XhcPeiReadOpReg (
80 IN PEI_XHC_DEV *Xhc,
81 IN UINT32 Offset
82 )
83 {
84 UINT32 Data;
85
86 ASSERT (Xhc->CapLength != 0);
87
88 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);
89 return Data;
90 }
91
92 /**
93 Write the data to the XHCI operation register.
94
95 @param Xhc The XHCI device.
96 @param Offset The operation register offset.
97 @param Data The data to write.
98
99 **/
100 VOID
101 XhcPeiWriteOpReg (
102 IN PEI_XHC_DEV *Xhc,
103 IN UINT32 Offset,
104 IN UINT32 Data
105 )
106 {
107 ASSERT (Xhc->CapLength != 0);
108
109 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);
110 }
111
112 /**
113 Set one bit of the operational register while keeping other bits.
114
115 @param Xhc The XHCI device.
116 @param Offset The offset of the operational register.
117 @param Bit The bit mask of the register to set.
118
119 **/
120 VOID
121 XhcPeiSetOpRegBit (
122 IN PEI_XHC_DEV *Xhc,
123 IN UINT32 Offset,
124 IN UINT32 Bit
125 )
126 {
127 UINT32 Data;
128
129 Data = XhcPeiReadOpReg (Xhc, Offset);
130 Data |= Bit;
131 XhcPeiWriteOpReg (Xhc, Offset, Data);
132 }
133
134 /**
135 Clear one bit of the operational register while keeping other bits.
136
137 @param Xhc The XHCI device.
138 @param Offset The offset of the operational register.
139 @param Bit The bit mask of the register to clear.
140
141 **/
142 VOID
143 XhcPeiClearOpRegBit (
144 IN PEI_XHC_DEV *Xhc,
145 IN UINT32 Offset,
146 IN UINT32 Bit
147 )
148 {
149 UINT32 Data;
150
151 Data = XhcPeiReadOpReg (Xhc, Offset);
152 Data &= ~Bit;
153 XhcPeiWriteOpReg (Xhc, Offset, Data);
154 }
155
156 /**
157 Wait the operation register's bit as specified by Bit
158 to become set (or clear).
159
160 @param Xhc The XHCI device.
161 @param Offset The offset of the operational register.
162 @param Bit The bit mask of the register to wait for.
163 @param WaitToSet Wait the bit to set or clear.
164 @param Timeout The time to wait before abort (in millisecond, ms).
165
166 @retval EFI_SUCCESS The bit successfully changed by host controller.
167 @retval EFI_TIMEOUT The time out occurred.
168
169 **/
170 EFI_STATUS
171 XhcPeiWaitOpRegBit (
172 IN PEI_XHC_DEV *Xhc,
173 IN UINT32 Offset,
174 IN UINT32 Bit,
175 IN BOOLEAN WaitToSet,
176 IN UINT32 Timeout
177 )
178 {
179 UINT64 Index;
180
181 for (Index = 0; Index < Timeout * XHC_1_MILLISECOND; Index++) {
182 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
183 return EFI_SUCCESS;
184 }
185
186 MicroSecondDelay (XHC_1_MICROSECOND);
187 }
188
189 return EFI_TIMEOUT;
190 }
191
192 /**
193 Read XHCI capability register.
194
195 @param Xhc The XHCI device.
196 @param Offset Capability register address.
197
198 @retval the register content read.
199
200 **/
201 UINT32
202 XhcPeiReadCapRegister (
203 IN PEI_XHC_DEV *Xhc,
204 IN UINT32 Offset
205 )
206 {
207 UINT32 Data;
208
209 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);
210
211 return Data;
212 }
213
214 /**
215 Read XHCI door bell register.
216
217 @param Xhc The XHCI device.
218 @param Offset The offset of the door bell register.
219
220 @return The register content read
221
222 **/
223 UINT32
224 XhcPeiReadDoorBellReg (
225 IN PEI_XHC_DEV *Xhc,
226 IN UINT32 Offset
227 )
228 {
229 UINT32 Data;
230
231 ASSERT (Xhc->DBOff != 0);
232
233 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset);
234
235 return Data;
236 }
237
238 /**
239 Write the data to the XHCI door bell register.
240
241 @param Xhc The XHCI device.
242 @param Offset The offset of the door bell register.
243 @param Data The data to write.
244
245 **/
246 VOID
247 XhcPeiWriteDoorBellReg (
248 IN PEI_XHC_DEV *Xhc,
249 IN UINT32 Offset,
250 IN UINT32 Data
251 )
252 {
253 ASSERT (Xhc->DBOff != 0);
254
255 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);
256 }
257
258 /**
259 Read XHCI runtime register.
260
261 @param Xhc The XHCI device.
262 @param Offset The offset of the runtime register.
263
264 @return The register content read
265
266 **/
267 UINT32
268 XhcPeiReadRuntimeReg (
269 IN PEI_XHC_DEV *Xhc,
270 IN UINT32 Offset
271 )
272 {
273 UINT32 Data;
274
275 ASSERT (Xhc->RTSOff != 0);
276
277 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);
278
279 return Data;
280 }
281
282 /**
283 Write the data to the XHCI runtime register.
284
285 @param Xhc The XHCI device.
286 @param Offset The offset of the runtime register.
287 @param Data The data to write.
288
289 **/
290 VOID
291 XhcPeiWriteRuntimeReg (
292 IN PEI_XHC_DEV *Xhc,
293 IN UINT32 Offset,
294 IN UINT32 Data
295 )
296 {
297 ASSERT (Xhc->RTSOff != 0);
298
299 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);
300 }
301
302 /**
303 Set one bit of the runtime register while keeping other bits.
304
305 @param Xhc The XHCI device.
306 @param Offset The offset of the runtime register.
307 @param Bit The bit mask of the register to set.
308
309 **/
310 VOID
311 XhcPeiSetRuntimeRegBit (
312 IN PEI_XHC_DEV *Xhc,
313 IN UINT32 Offset,
314 IN UINT32 Bit
315 )
316 {
317 UINT32 Data;
318
319 Data = XhcPeiReadRuntimeReg (Xhc, Offset);
320 Data |= Bit;
321 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
322 }
323
324 /**
325 Clear one bit of the runtime register while keeping other bits.
326
327 @param Xhc The XHCI device.
328 @param Offset The offset of the runtime register.
329 @param Bit The bit mask of the register to set.
330
331 **/
332 VOID
333 XhcPeiClearRuntimeRegBit (
334 IN PEI_XHC_DEV *Xhc,
335 IN UINT32 Offset,
336 IN UINT32 Bit
337 )
338 {
339 UINT32 Data;
340
341 Data = XhcPeiReadRuntimeReg (Xhc, Offset);
342 Data &= ~Bit;
343 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
344 }
345
346 /**
347 Check whether Xhc is halted.
348
349 @param Xhc The XHCI device.
350
351 @retval TRUE The controller is halted.
352 @retval FALSE The controller isn't halted.
353
354 **/
355 BOOLEAN
356 XhcPeiIsHalt (
357 IN PEI_XHC_DEV *Xhc
358 )
359 {
360 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
361 }
362
363 /**
364 Check whether system error occurred.
365
366 @param Xhc The XHCI device.
367
368 @retval TRUE System error happened.
369 @retval FALSE No system error.
370
371 **/
372 BOOLEAN
373 XhcPeiIsSysError (
374 IN PEI_XHC_DEV *Xhc
375 )
376 {
377 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
378 }
379
380 /**
381 Reset the host controller.
382
383 @param Xhc The XHCI device.
384 @param Timeout Time to wait before abort (in millisecond, ms).
385
386 @retval EFI_TIMEOUT The transfer failed due to time out.
387 @retval Others Failed to reset the host.
388
389 **/
390 EFI_STATUS
391 XhcPeiResetHC (
392 IN PEI_XHC_DEV *Xhc,
393 IN UINT32 Timeout
394 )
395 {
396 EFI_STATUS Status;
397
398 //
399 // Host can only be reset when it is halt. If not so, halt it
400 //
401 if (!XhcPeiIsHalt (Xhc)) {
402 Status = XhcPeiHaltHC (Xhc, Timeout);
403
404 if (EFI_ERROR (Status)) {
405 goto ON_EXIT;
406 }
407 }
408
409 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
410 //
411 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
412 // Otherwise there may have the timeout case happened.
413 // The below is a workaround to solve such problem.
414 //
415 MicroSecondDelay (1000);
416 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
417 ON_EXIT:
418 DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));
419 return Status;
420 }
421
422 /**
423 Halt the host controller.
424
425 @param Xhc The XHCI device.
426 @param Timeout Time to wait before abort.
427
428 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
429 @retval EFI_SUCCESS The XHCI is halt.
430
431 **/
432 EFI_STATUS
433 XhcPeiHaltHC (
434 IN PEI_XHC_DEV *Xhc,
435 IN UINT32 Timeout
436 )
437 {
438 EFI_STATUS Status;
439
440 XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
441 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
442 DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));
443 return Status;
444 }
445
446 /**
447 Set the XHCI to run.
448
449 @param Xhc The XHCI device.
450 @param Timeout Time to wait before abort.
451
452 @retval EFI_SUCCESS The XHCI is running.
453 @retval Others Failed to set the XHCI to run.
454
455 **/
456 EFI_STATUS
457 XhcPeiRunHC (
458 IN PEI_XHC_DEV *Xhc,
459 IN UINT32 Timeout
460 )
461 {
462 EFI_STATUS Status;
463
464 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
465 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
466 DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));
467 return Status;
468 }
469
470 /**
471 Submits control transfer to a target USB device.
472
473 @param PeiServices The pointer of EFI_PEI_SERVICES.
474 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
475 @param DeviceAddress The target device address.
476 @param DeviceSpeed Target device speed.
477 @param MaximumPacketLength Maximum packet size the default control transfer
478 endpoint is capable of sending or receiving.
479 @param Request USB device request to send.
480 @param TransferDirection Specifies the data direction for the data stage.
481 @param Data Data buffer to be transmitted or received from USB device.
482 @param DataLength The size (in bytes) of the data buffer.
483 @param TimeOut Indicates the maximum timeout, in millisecond.
484 If Timeout is 0, then the caller must wait for the function
485 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
486 @param Translator Transaction translator to be used by this device.
487 @param TransferResult Return the result of this control transfer.
488
489 @retval EFI_SUCCESS Transfer was completed successfully.
490 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
491 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
492 @retval EFI_TIMEOUT Transfer failed due to timeout.
493 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
494
495 **/
496 EFI_STATUS
497 EFIAPI
498 XhcPeiControlTransfer (
499 IN EFI_PEI_SERVICES **PeiServices,
500 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
501 IN UINT8 DeviceAddress,
502 IN UINT8 DeviceSpeed,
503 IN UINTN MaximumPacketLength,
504 IN EFI_USB_DEVICE_REQUEST *Request,
505 IN EFI_USB_DATA_DIRECTION TransferDirection,
506 IN OUT VOID *Data,
507 IN OUT UINTN *DataLength,
508 IN UINTN TimeOut,
509 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
510 OUT UINT32 *TransferResult
511 )
512 {
513 PEI_XHC_DEV *Xhc;
514 URB *Urb;
515 UINT8 Endpoint;
516 UINT8 Index;
517 UINT8 DescriptorType;
518 UINT8 SlotId;
519 UINT8 TTT;
520 UINT8 MTT;
521 UINT32 MaxPacket0;
522 EFI_USB_HUB_DESCRIPTOR *HubDesc;
523 EFI_STATUS Status;
524 EFI_STATUS RecoveryStatus;
525 UINTN MapSize;
526 EFI_USB_PORT_STATUS PortStatus;
527 UINT32 State;
528 EFI_USB_DEVICE_REQUEST ClearPortRequest;
529 UINTN Len;
530
531 //
532 // Validate parameters
533 //
534 if ((Request == NULL) || (TransferResult == NULL)) {
535 return EFI_INVALID_PARAMETER;
536 }
537
538 if ((TransferDirection != EfiUsbDataIn) &&
539 (TransferDirection != EfiUsbDataOut) &&
540 (TransferDirection != EfiUsbNoData)) {
541 return EFI_INVALID_PARAMETER;
542 }
543
544 if ((TransferDirection == EfiUsbNoData) &&
545 ((Data != NULL) || (*DataLength != 0))) {
546 return EFI_INVALID_PARAMETER;
547 }
548
549 if ((TransferDirection != EfiUsbNoData) &&
550 ((Data == NULL) || (*DataLength == 0))) {
551 return EFI_INVALID_PARAMETER;
552 }
553
554 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
555 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
556 (MaximumPacketLength != 512)
557 ) {
558 return EFI_INVALID_PARAMETER;
559 }
560
561 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
562 return EFI_INVALID_PARAMETER;
563 }
564
565 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
566 return EFI_INVALID_PARAMETER;
567 }
568
569 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
570
571 Status = EFI_DEVICE_ERROR;
572 *TransferResult = EFI_USB_ERR_SYSTEM;
573 Len = 0;
574
575 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
576 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));
577 goto ON_EXIT;
578 }
579
580 //
581 // Check if the device is still enabled before every transaction.
582 //
583 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
584 if (SlotId == 0) {
585 goto ON_EXIT;
586 }
587
588 //
589 // Hook the Set_Address request from UsbBus.
590 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
591 //
592 if ((Request->Request == USB_REQ_SET_ADDRESS) &&
593 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
594 //
595 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
596 // This way is used to clean the history to avoid using wrong device address afterwards.
597 //
598 for (Index = 0; Index < 255; Index++) {
599 if (!Xhc->UsbDevContext[Index + 1].Enabled &&
600 (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
601 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {
602 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
603 }
604 }
605
606 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
607 goto ON_EXIT;
608 }
609 //
610 // The actual device address has been assigned by XHCI during initializing the device slot.
611 // So we just need establish the mapping relationship between the device address requested from UsbBus
612 // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface
613 // can find out the actual device address by it.
614 //
615 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;
616 Status = EFI_SUCCESS;
617 goto ON_EXIT;
618 }
619
620 //
621 // Create a new URB, insert it into the asynchronous
622 // schedule list, then poll the execution status.
623 // Note that we encode the direction in address although default control
624 // endpoint is bidirectional. XhcPeiCreateUrb expects this
625 // combination of Ep addr and its direction.
626 //
627 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
628 Urb = XhcPeiCreateUrb (
629 Xhc,
630 DeviceAddress,
631 Endpoint,
632 DeviceSpeed,
633 MaximumPacketLength,
634 XHC_CTRL_TRANSFER,
635 Request,
636 Data,
637 *DataLength,
638 NULL,
639 NULL
640 );
641
642 if (Urb == NULL) {
643 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));
644 Status = EFI_OUT_OF_RESOURCES;
645 goto ON_EXIT;
646 }
647
648 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
649
650 //
651 // Get the status from URB. The result is updated in XhcPeiCheckUrbResult
652 // which is called by XhcPeiExecTransfer
653 //
654 *TransferResult = Urb->Result;
655 *DataLength = Urb->Completed;
656
657 if (Status == EFI_TIMEOUT) {
658 //
659 // The transfer timed out. Abort the transfer by dequeueing of the TD.
660 //
661 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
662 if (EFI_ERROR(RecoveryStatus)) {
663 DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
664 }
665 XhcPeiFreeUrb (Xhc, Urb);
666 goto ON_EXIT;
667 } else {
668 if (*TransferResult == EFI_USB_NOERROR) {
669 Status = EFI_SUCCESS;
670 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
671 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
672 if (EFI_ERROR (RecoveryStatus)) {
673 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
674 }
675 Status = EFI_DEVICE_ERROR;
676 XhcPeiFreeUrb (Xhc, Urb);
677 goto ON_EXIT;
678 } else {
679 XhcPeiFreeUrb (Xhc, Urb);
680 goto ON_EXIT;
681 }
682 }
683 //
684 // Unmap data before consume.
685 //
686 XhcPeiFreeUrb (Xhc, Urb);
687
688 //
689 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
690 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
691 // Hook Set_Config request from UsbBus as we need configure device endpoint.
692 //
693 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
694 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
695 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
696 DescriptorType = (UINT8) (Request->Value >> 8);
697 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
698 ASSERT (Data != NULL);
699 //
700 // Store a copy of device scriptor as hub device need this info to configure endpoint.
701 //
702 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
703 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
704 //
705 // If it's a usb3.0 device, then its max packet size is a 2^n.
706 //
707 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
708 } else {
709 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
710 }
711 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
712 if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {
713 Status = EFI_OUT_OF_RESOURCES;
714 goto ON_EXIT;
715 }
716 if (Xhc->HcCParams.Data.Csz == 0) {
717 Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);
718 } else {
719 Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);
720 }
721 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
722 ASSERT (Data != NULL);
723 if (*DataLength == ((UINT16 *) Data)[1]) {
724 //
725 // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.
726 //
727 Index = (UINT8) Request->Value;
728 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
729 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
730 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {
731 Status = EFI_OUT_OF_RESOURCES;
732 goto ON_EXIT;
733 }
734 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
735 }
736 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
737 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
738 ASSERT (Data != NULL);
739 HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;
740 ASSERT (HubDesc->NumPorts <= 15);
741 //
742 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
743 //
744 TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
745 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
746 //
747 // Don't support multi-TT feature for super speed hub now.
748 //
749 MTT = 0;
750 DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
751 } else {
752 MTT = 0;
753 }
754
755 if (Xhc->HcCParams.Data.Csz == 0) {
756 Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
757 } else {
758 Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
759 }
760 }
761 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
762 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
763 //
764 // Hook Set_Config request from UsbBus as we need configure device endpoint.
765 //
766 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
767 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
768 if (Xhc->HcCParams.Data.Csz == 0) {
769 Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
770 } else {
771 Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
772 }
773 break;
774 }
775 }
776 } else if ((Request->Request == USB_REQ_GET_STATUS) &&
777 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
778 ASSERT (Data != NULL);
779 //
780 // Hook Get_Status request from UsbBus to keep track of the port status change.
781 //
782 State = *(UINT32 *) Data;
783 PortStatus.PortStatus = 0;
784 PortStatus.PortChangeStatus = 0;
785
786 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
787 //
788 // For super speed hub, its bit10~12 presents the attached device speed.
789 //
790 if ((State & XHC_PORTSC_PS) >> 10 == 0) {
791 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
792 }
793 } else {
794 //
795 // For high or full/low speed hub, its bit9~10 presents the attached device speed.
796 //
797 if (XHC_BIT_IS_SET (State, BIT9)) {
798 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
799 } else if (XHC_BIT_IS_SET (State, BIT10)) {
800 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
801 }
802 }
803
804 //
805 // Convert the XHCI port/port change state to UEFI status
806 //
807 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
808 for (Index = 0; Index < MapSize; Index++) {
809 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
810 PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
811 }
812 }
813
814 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
815 for (Index = 0; Index < MapSize; Index++) {
816 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
817 PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
818 }
819 }
820
821 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
822
823 for (Index = 0; Index < MapSize; Index++) {
824 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
825 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
826 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
827 ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;
828 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
829 ClearPortRequest.Index = Request->Index;
830 ClearPortRequest.Length = 0;
831
832 XhcPeiControlTransfer (
833 PeiServices,
834 This,
835 DeviceAddress,
836 DeviceSpeed,
837 MaximumPacketLength,
838 &ClearPortRequest,
839 EfiUsbNoData,
840 NULL,
841 &Len,
842 TimeOut,
843 Translator,
844 TransferResult
845 );
846 }
847 }
848
849 XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
850
851 *(UINT32 *) Data = *(UINT32 *) &PortStatus;
852 }
853
854 ON_EXIT:
855
856 if (EFI_ERROR (Status)) {
857 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
858 }
859
860 return Status;
861 }
862
863 /**
864 Submits bulk transfer to a bulk endpoint of a USB device.
865
866 @param PeiServices The pointer of EFI_PEI_SERVICES.
867 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
868 @param DeviceAddress Target device address.
869 @param EndPointAddress Endpoint number and its direction in bit 7.
870 @param DeviceSpeed Device speed, Low speed device doesn't support
871 bulk transfer.
872 @param MaximumPacketLength Maximum packet size the endpoint is capable of
873 sending or receiving.
874 @param Data Array of pointers to the buffers of data to transmit
875 from or receive into.
876 @param DataLength The lenght of the data buffer.
877 @param DataToggle On input, the initial data toggle for the transfer;
878 On output, it is updated to to next data toggle to use of
879 the subsequent bulk transfer.
880 @param TimeOut Indicates the maximum time, in millisecond, which the
881 transfer is allowed to complete.
882 If Timeout is 0, then the caller must wait for the function
883 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
884 @param Translator A pointr to the transaction translator data.
885 @param TransferResult A pointer to the detailed result information of the
886 bulk transfer.
887
888 @retval EFI_SUCCESS The transfer was completed successfully.
889 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
890 @retval EFI_INVALID_PARAMETER Parameters are invalid.
891 @retval EFI_TIMEOUT The transfer failed due to timeout.
892 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
893
894 **/
895 EFI_STATUS
896 EFIAPI
897 XhcPeiBulkTransfer (
898 IN EFI_PEI_SERVICES **PeiServices,
899 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
900 IN UINT8 DeviceAddress,
901 IN UINT8 EndPointAddress,
902 IN UINT8 DeviceSpeed,
903 IN UINTN MaximumPacketLength,
904 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
905 IN OUT UINTN *DataLength,
906 IN OUT UINT8 *DataToggle,
907 IN UINTN TimeOut,
908 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
909 OUT UINT32 *TransferResult
910 )
911 {
912 PEI_XHC_DEV *Xhc;
913 URB *Urb;
914 UINT8 SlotId;
915 EFI_STATUS Status;
916 EFI_STATUS RecoveryStatus;
917
918 //
919 // Validate the parameters
920 //
921 if ((DataLength == NULL) || (*DataLength == 0) ||
922 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 if ((*DataToggle != 0) && (*DataToggle != 1)) {
927 return EFI_INVALID_PARAMETER;
928 }
929
930 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
931 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
932 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||
933 ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {
934 return EFI_INVALID_PARAMETER;
935 }
936
937 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
938
939 *TransferResult = EFI_USB_ERR_SYSTEM;
940 Status = EFI_DEVICE_ERROR;
941
942 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
943 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));
944 goto ON_EXIT;
945 }
946
947 //
948 // Check if the device is still enabled before every transaction.
949 //
950 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
951 if (SlotId == 0) {
952 goto ON_EXIT;
953 }
954
955 //
956 // Create a new URB, insert it into the asynchronous
957 // schedule list, then poll the execution status.
958 //
959 Urb = XhcPeiCreateUrb (
960 Xhc,
961 DeviceAddress,
962 EndPointAddress,
963 DeviceSpeed,
964 MaximumPacketLength,
965 XHC_BULK_TRANSFER,
966 NULL,
967 Data[0],
968 *DataLength,
969 NULL,
970 NULL
971 );
972
973 if (Urb == NULL) {
974 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));
975 Status = EFI_OUT_OF_RESOURCES;
976 goto ON_EXIT;
977 }
978
979 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
980
981 *TransferResult = Urb->Result;
982 *DataLength = Urb->Completed;
983
984 if (Status == EFI_TIMEOUT) {
985 //
986 // The transfer timed out. Abort the transfer by dequeueing of the TD.
987 //
988 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
989 if (EFI_ERROR(RecoveryStatus)) {
990 DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
991 }
992 } else {
993 if (*TransferResult == EFI_USB_NOERROR) {
994 Status = EFI_SUCCESS;
995 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
996 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
997 if (EFI_ERROR (RecoveryStatus)) {
998 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
999 }
1000 Status = EFI_DEVICE_ERROR;
1001 }
1002 }
1003
1004 XhcPeiFreeUrb (Xhc, Urb);
1005
1006 ON_EXIT:
1007
1008 if (EFI_ERROR (Status)) {
1009 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1010 }
1011
1012 return Status;
1013 }
1014
1015 /**
1016 Retrieves the number of root hub ports.
1017
1018 @param[in] PeiServices The pointer to the PEI Services Table.
1019 @param[in] This The pointer to this instance of the
1020 PEI_USB2_HOST_CONTROLLER_PPI.
1021 @param[out] PortNumber The pointer to the number of the root hub ports.
1022
1023 @retval EFI_SUCCESS The port number was retrieved successfully.
1024 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
1025
1026 **/
1027 EFI_STATUS
1028 EFIAPI
1029 XhcPeiGetRootHubPortNumber (
1030 IN EFI_PEI_SERVICES **PeiServices,
1031 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1032 OUT UINT8 *PortNumber
1033 )
1034 {
1035 PEI_XHC_DEV *XhcDev;
1036 XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1037
1038 if (PortNumber == NULL) {
1039 return EFI_INVALID_PARAMETER;
1040 }
1041
1042 *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;
1043 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));
1044 return EFI_SUCCESS;
1045 }
1046
1047 /**
1048 Clears a feature for the specified root hub port.
1049
1050 @param PeiServices The pointer of EFI_PEI_SERVICES.
1051 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1052 @param PortNumber Specifies the root hub port whose feature
1053 is requested to be cleared.
1054 @param PortFeature Indicates the feature selector associated with the
1055 feature clear request.
1056
1057 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
1058 for the USB root hub port specified by PortNumber.
1059 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1060
1061 **/
1062 EFI_STATUS
1063 EFIAPI
1064 XhcPeiClearRootHubPortFeature (
1065 IN EFI_PEI_SERVICES **PeiServices,
1066 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1067 IN UINT8 PortNumber,
1068 IN EFI_USB_PORT_FEATURE PortFeature
1069 )
1070 {
1071 PEI_XHC_DEV *Xhc;
1072 UINT32 Offset;
1073 UINT32 State;
1074 EFI_STATUS Status;
1075
1076 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1077 Status = EFI_SUCCESS;
1078
1079 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1080 Status = EFI_INVALID_PARAMETER;
1081 goto ON_EXIT;
1082 }
1083
1084 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1085 State = XhcPeiReadOpReg (Xhc, Offset);
1086 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1087
1088 //
1089 // Mask off the port status change bits, these bits are
1090 // write clean bits
1091 //
1092 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1093
1094 switch (PortFeature) {
1095 case EfiUsbPortEnable:
1096 //
1097 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1098 // A port may be disabled by software writing a '1' to this flag.
1099 //
1100 State |= XHC_PORTSC_PED;
1101 State &= ~XHC_PORTSC_RESET;
1102 XhcPeiWriteOpReg (Xhc, Offset, State);
1103 break;
1104
1105 case EfiUsbPortSuspend:
1106 State |= XHC_PORTSC_LWS;
1107 XhcPeiWriteOpReg (Xhc, Offset, State);
1108 State &= ~XHC_PORTSC_PLS;
1109 XhcPeiWriteOpReg (Xhc, Offset, State);
1110 break;
1111
1112 case EfiUsbPortReset:
1113 //
1114 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
1115 // Register bits indicate status when read, a clear bit may be set by
1116 // writing a '1'. Writing a '0' to RW1S bits has no effect.
1117 //
1118 break;
1119
1120 case EfiUsbPortPower:
1121 if (Xhc->HcCParams.Data.Ppc) {
1122 //
1123 // Port Power Control supported
1124 //
1125 State &= ~XHC_PORTSC_PP;
1126 XhcPeiWriteOpReg (Xhc, Offset, State);
1127 }
1128 break;
1129
1130 case EfiUsbPortOwner:
1131 //
1132 // XHCI root hub port don't has the owner bit, ignore the operation
1133 //
1134 break;
1135
1136 case EfiUsbPortConnectChange:
1137 //
1138 // Clear connect status change
1139 //
1140 State |= XHC_PORTSC_CSC;
1141 XhcPeiWriteOpReg (Xhc, Offset, State);
1142 break;
1143
1144 case EfiUsbPortEnableChange:
1145 //
1146 // Clear enable status change
1147 //
1148 State |= XHC_PORTSC_PEC;
1149 XhcPeiWriteOpReg (Xhc, Offset, State);
1150 break;
1151
1152 case EfiUsbPortOverCurrentChange:
1153 //
1154 // Clear PortOverCurrent change
1155 //
1156 State |= XHC_PORTSC_OCC;
1157 XhcPeiWriteOpReg (Xhc, Offset, State);
1158 break;
1159
1160 case EfiUsbPortResetChange:
1161 //
1162 // Clear Port Reset change
1163 //
1164 State |= XHC_PORTSC_PRC;
1165 XhcPeiWriteOpReg (Xhc, Offset, State);
1166 break;
1167
1168 case EfiUsbPortSuspendChange:
1169 //
1170 // Not supported or not related operation
1171 //
1172 break;
1173
1174 default:
1175 Status = EFI_INVALID_PARAMETER;
1176 break;
1177 }
1178
1179 ON_EXIT:
1180 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1181 return Status;
1182 }
1183
1184 /**
1185 Sets a feature for the specified root hub port.
1186
1187 @param PeiServices The pointer of EFI_PEI_SERVICES
1188 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
1189 @param PortNumber Root hub port to set.
1190 @param PortFeature Feature to set.
1191
1192 @retval EFI_SUCCESS The feature specified by PortFeature was set.
1193 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1194 @retval EFI_TIMEOUT The time out occurred.
1195
1196 **/
1197 EFI_STATUS
1198 EFIAPI
1199 XhcPeiSetRootHubPortFeature (
1200 IN EFI_PEI_SERVICES **PeiServices,
1201 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1202 IN UINT8 PortNumber,
1203 IN EFI_USB_PORT_FEATURE PortFeature
1204 )
1205 {
1206 PEI_XHC_DEV *Xhc;
1207 UINT32 Offset;
1208 UINT32 State;
1209 EFI_STATUS Status;
1210
1211 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1212 Status = EFI_SUCCESS;
1213
1214 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1215 Status = EFI_INVALID_PARAMETER;
1216 goto ON_EXIT;
1217 }
1218
1219 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1220 State = XhcPeiReadOpReg (Xhc, Offset);
1221 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1222
1223 //
1224 // Mask off the port status change bits, these bits are
1225 // write clean bits
1226 //
1227 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1228
1229 switch (PortFeature) {
1230 case EfiUsbPortEnable:
1231 //
1232 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1233 // A port may be disabled by software writing a '1' to this flag.
1234 //
1235 break;
1236
1237 case EfiUsbPortSuspend:
1238 State |= XHC_PORTSC_LWS;
1239 XhcPeiWriteOpReg (Xhc, Offset, State);
1240 State &= ~XHC_PORTSC_PLS;
1241 State |= (3 << 5) ;
1242 XhcPeiWriteOpReg (Xhc, Offset, State);
1243 break;
1244
1245 case EfiUsbPortReset:
1246 //
1247 // Make sure Host Controller not halt before reset it
1248 //
1249 if (XhcPeiIsHalt (Xhc)) {
1250 Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);
1251 if (EFI_ERROR (Status)) {
1252 break;
1253 }
1254 }
1255
1256 //
1257 // 4.3.1 Resetting a Root Hub Port
1258 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
1259 // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)
1260 // bit in the PORTSC field is set to '1'.
1261 //
1262 State |= XHC_PORTSC_RESET;
1263 XhcPeiWriteOpReg (Xhc, Offset, State);
1264 XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
1265 break;
1266
1267 case EfiUsbPortPower:
1268 if (Xhc->HcCParams.Data.Ppc) {
1269 //
1270 // Port Power Control supported
1271 //
1272 State |= XHC_PORTSC_PP;
1273 XhcPeiWriteOpReg (Xhc, Offset, State);
1274 }
1275 break;
1276
1277 case EfiUsbPortOwner:
1278 //
1279 // XHCI root hub port don't has the owner bit, ignore the operation
1280 //
1281 break;
1282
1283 default:
1284 Status = EFI_INVALID_PARAMETER;
1285 }
1286
1287 ON_EXIT:
1288 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1289 return Status;
1290 }
1291
1292 /**
1293 Retrieves the current status of a USB root hub port.
1294
1295 @param PeiServices The pointer of EFI_PEI_SERVICES.
1296 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1297 @param PortNumber The root hub port to retrieve the state from.
1298 @param PortStatus Variable to receive the port state.
1299
1300 @retval EFI_SUCCESS The status of the USB root hub port specified.
1301 by PortNumber was returned in PortStatus.
1302 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
1303
1304 **/
1305 EFI_STATUS
1306 EFIAPI
1307 XhcPeiGetRootHubPortStatus (
1308 IN EFI_PEI_SERVICES **PeiServices,
1309 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1310 IN UINT8 PortNumber,
1311 OUT EFI_USB_PORT_STATUS *PortStatus
1312 )
1313 {
1314 PEI_XHC_DEV *Xhc;
1315 UINT32 Offset;
1316 UINT32 State;
1317 UINTN Index;
1318 UINTN MapSize;
1319 USB_DEV_ROUTE ParentRouteChart;
1320
1321 if (PortStatus == NULL) {
1322 return EFI_INVALID_PARAMETER;
1323 }
1324
1325 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1326
1327 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1328 return EFI_INVALID_PARAMETER;
1329 }
1330
1331 //
1332 // Clear port status.
1333 //
1334 PortStatus->PortStatus = 0;
1335 PortStatus->PortChangeStatus = 0;
1336
1337 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1338 State = XhcPeiReadOpReg (Xhc, Offset);
1339 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));
1340
1341 //
1342 // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.
1343 //
1344 switch ((State & XHC_PORTSC_PS) >> 10) {
1345 case 2:
1346 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
1347 break;
1348
1349 case 3:
1350 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1351 break;
1352
1353 case 4:
1354 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1355 break;
1356
1357 default:
1358 break;
1359 }
1360
1361 //
1362 // Convert the XHCI port/port change state to UEFI status
1363 //
1364 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1365
1366 for (Index = 0; Index < MapSize; Index++) {
1367 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
1368 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
1369 }
1370 }
1371 //
1372 // Bit5~8 reflects its current link state.
1373 //
1374 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
1375 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
1376 }
1377
1378 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1379
1380 for (Index = 0; Index < MapSize; Index++) {
1381 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
1382 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
1383 }
1384 }
1385
1386 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
1387
1388 for (Index = 0; Index < MapSize; Index++) {
1389 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
1390 XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
1391 }
1392 }
1393
1394 //
1395 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
1396 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
1397 //
1398 ParentRouteChart.Dword = 0;
1399 XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
1400
1401 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));
1402 return EFI_SUCCESS;
1403 }
1404
1405 /**
1406 One notified function to stop the Host Controller at the end of PEI
1407
1408 @param[in] PeiServices Pointer to PEI Services Table.
1409 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
1410 caused this function to execute.
1411 @param[in] Ppi Pointer to the PPI data associated with this function.
1412
1413 @retval EFI_SUCCESS The function completes successfully
1414 @retval others
1415 **/
1416 EFI_STATUS
1417 EFIAPI
1418 XhcEndOfPei (
1419 IN EFI_PEI_SERVICES **PeiServices,
1420 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
1421 IN VOID *Ppi
1422 )
1423 {
1424 PEI_XHC_DEV *Xhc;
1425
1426 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(NotifyDescriptor);
1427
1428 XhcPeiHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
1429
1430 XhcPeiFreeSched (Xhc);
1431
1432 return EFI_SUCCESS;
1433 }
1434
1435 /**
1436 @param FileHandle Handle of the file being invoked.
1437 @param PeiServices Describes the list of possible PEI Services.
1438
1439 @retval EFI_SUCCESS PPI successfully installed.
1440
1441 **/
1442 EFI_STATUS
1443 EFIAPI
1444 XhcPeimEntry (
1445 IN EFI_PEI_FILE_HANDLE FileHandle,
1446 IN CONST EFI_PEI_SERVICES **PeiServices
1447 )
1448 {
1449 PEI_USB_CONTROLLER_PPI *UsbControllerPpi;
1450 EFI_STATUS Status;
1451 UINT8 Index;
1452 UINTN ControllerType;
1453 UINTN BaseAddress;
1454 UINTN MemPages;
1455 PEI_XHC_DEV *XhcDev;
1456 EFI_PHYSICAL_ADDRESS TempPtr;
1457 UINT32 PageSize;
1458
1459 //
1460 // Shadow this PEIM to run from memory.
1461 //
1462 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1463 return EFI_SUCCESS;
1464 }
1465
1466 Status = PeiServicesLocatePpi (
1467 &gPeiUsbControllerPpiGuid,
1468 0,
1469 NULL,
1470 (VOID **) &UsbControllerPpi
1471 );
1472 if (EFI_ERROR (Status)) {
1473 return EFI_UNSUPPORTED;
1474 }
1475
1476 IoMmuInit ();
1477
1478 Index = 0;
1479 while (TRUE) {
1480 Status = UsbControllerPpi->GetUsbController (
1481 (EFI_PEI_SERVICES **) PeiServices,
1482 UsbControllerPpi,
1483 Index,
1484 &ControllerType,
1485 &BaseAddress
1486 );
1487 //
1488 // When status is error, it means no controller is found.
1489 //
1490 if (EFI_ERROR (Status)) {
1491 break;
1492 }
1493
1494 //
1495 // This PEIM is for XHC type controller.
1496 //
1497 if (ControllerType != PEI_XHCI_CONTROLLER) {
1498 Index++;
1499 continue;
1500 }
1501
1502 MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));
1503 Status = PeiServicesAllocatePages (
1504 EfiBootServicesData,
1505 MemPages,
1506 &TempPtr
1507 );
1508 if (EFI_ERROR (Status)) {
1509 return EFI_OUT_OF_RESOURCES;
1510 }
1511 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));
1512 XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);
1513
1514 XhcDev->Signature = USB_XHC_DEV_SIGNATURE;
1515 XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
1516 XhcDev->CapLength = (UINT8) (XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);
1517 XhcDev->HcSParams1.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);
1518 XhcDev->HcSParams2.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);
1519 XhcDev->HcCParams.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);
1520 XhcDev->DBOff = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);
1521 XhcDev->RTSOff = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);
1522
1523 //
1524 // This PageSize field defines the page size supported by the xHC implementation.
1525 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1526 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1527 //
1528 PageSize = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
1529 XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
1530
1531 DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));
1532 DEBUG ((EFI_D_INFO, "XhciPei: CapLength: %x\n", XhcDev->CapLength));
1533 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1: %x\n", XhcDev->HcSParams1.Dword));
1534 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2: %x\n", XhcDev->HcSParams2.Dword));
1535 DEBUG ((EFI_D_INFO, "XhciPei: HcCParams: %x\n", XhcDev->HcCParams.Dword));
1536 DEBUG ((EFI_D_INFO, "XhciPei: DBOff: %x\n", XhcDev->DBOff));
1537 DEBUG ((EFI_D_INFO, "XhciPei: RTSOff: %x\n", XhcDev->RTSOff));
1538 DEBUG ((EFI_D_INFO, "XhciPei: PageSize: %x\n", XhcDev->PageSize));
1539
1540 XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);
1541 ASSERT (XhcPeiIsHalt (XhcDev));
1542
1543 //
1544 // Initialize the schedule
1545 //
1546 XhcPeiInitSched (XhcDev);
1547
1548 //
1549 // Start the Host Controller
1550 //
1551 XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);
1552
1553 //
1554 // Wait for root port state stable
1555 //
1556 MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);
1557
1558 XhcDev->Usb2HostControllerPpi.ControlTransfer = XhcPeiControlTransfer;
1559 XhcDev->Usb2HostControllerPpi.BulkTransfer = XhcPeiBulkTransfer;
1560 XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = XhcPeiGetRootHubPortNumber;
1561 XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = XhcPeiGetRootHubPortStatus;
1562 XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = XhcPeiSetRootHubPortFeature;
1563 XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = XhcPeiClearRootHubPortFeature;
1564
1565 XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1566 XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1567 XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;
1568
1569 XhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1570 XhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
1571 XhcDev->EndOfPeiNotifyList.Notify = XhcEndOfPei;
1572
1573 PeiServicesInstallPpi (&XhcDev->PpiDescriptor);
1574 PeiServicesNotifyPpi (&XhcDev->EndOfPeiNotifyList);
1575
1576 Index++;
1577 }
1578
1579 return EFI_SUCCESS;
1580 }
1581