]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
MdeModulePkg Xhci: Also RecoverHaltedEndpoint for BABBLE_ERROR
[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 goto FREE_URB;
666 } else {
667 if (*TransferResult == EFI_USB_NOERROR) {
668 Status = EFI_SUCCESS;
669 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
670 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
671 if (EFI_ERROR (RecoveryStatus)) {
672 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
673 }
674 Status = EFI_DEVICE_ERROR;
675 goto FREE_URB;
676 } else {
677 goto FREE_URB;
678 }
679 }
680
681 //
682 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
683 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
684 // Hook Set_Config request from UsbBus as we need configure device endpoint.
685 //
686 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
687 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
688 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
689 DescriptorType = (UINT8) (Request->Value >> 8);
690 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
691 ASSERT (Data != NULL);
692 //
693 // Store a copy of device scriptor as hub device need this info to configure endpoint.
694 //
695 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
696 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
697 //
698 // If it's a usb3.0 device, then its max packet size is a 2^n.
699 //
700 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
701 } else {
702 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
703 }
704 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
705 if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {
706 Status = EFI_OUT_OF_RESOURCES;
707 goto FREE_URB;
708 }
709 if (Xhc->HcCParams.Data.Csz == 0) {
710 Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);
711 } else {
712 Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);
713 }
714 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
715 ASSERT (Data != NULL);
716 if (*DataLength == ((UINT16 *) Data)[1]) {
717 //
718 // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.
719 //
720 Index = (UINT8) Request->Value;
721 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
722 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
723 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {
724 Status = EFI_OUT_OF_RESOURCES;
725 goto FREE_URB;
726 }
727 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
728 }
729 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
730 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
731 ASSERT (Data != NULL);
732 HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;
733 ASSERT (HubDesc->NumPorts <= 15);
734 //
735 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
736 //
737 TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
738 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
739 //
740 // Don't support multi-TT feature for super speed hub now.
741 //
742 MTT = 0;
743 DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
744 } else {
745 MTT = 0;
746 }
747
748 if (Xhc->HcCParams.Data.Csz == 0) {
749 Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
750 } else {
751 Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
752 }
753 }
754 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
755 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
756 //
757 // Hook Set_Config request from UsbBus as we need configure device endpoint.
758 //
759 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
760 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
761 if (Xhc->HcCParams.Data.Csz == 0) {
762 Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
763 } else {
764 Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
765 }
766 break;
767 }
768 }
769 } else if ((Request->Request == USB_REQ_GET_STATUS) &&
770 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
771 ASSERT (Data != NULL);
772 //
773 // Hook Get_Status request from UsbBus to keep track of the port status change.
774 //
775 State = *(UINT32 *) Data;
776 PortStatus.PortStatus = 0;
777 PortStatus.PortChangeStatus = 0;
778
779 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
780 //
781 // For super speed hub, its bit10~12 presents the attached device speed.
782 //
783 if ((State & XHC_PORTSC_PS) >> 10 == 0) {
784 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
785 }
786 } else {
787 //
788 // For high or full/low speed hub, its bit9~10 presents the attached device speed.
789 //
790 if (XHC_BIT_IS_SET (State, BIT9)) {
791 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
792 } else if (XHC_BIT_IS_SET (State, BIT10)) {
793 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
794 }
795 }
796
797 //
798 // Convert the XHCI port/port change state to UEFI status
799 //
800 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
801 for (Index = 0; Index < MapSize; Index++) {
802 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
803 PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
804 }
805 }
806
807 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
808 for (Index = 0; Index < MapSize; Index++) {
809 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
810 PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
811 }
812 }
813
814 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
815
816 for (Index = 0; Index < MapSize; Index++) {
817 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
818 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
819 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
820 ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;
821 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
822 ClearPortRequest.Index = Request->Index;
823 ClearPortRequest.Length = 0;
824
825 XhcPeiControlTransfer (
826 PeiServices,
827 This,
828 DeviceAddress,
829 DeviceSpeed,
830 MaximumPacketLength,
831 &ClearPortRequest,
832 EfiUsbNoData,
833 NULL,
834 &Len,
835 TimeOut,
836 Translator,
837 TransferResult
838 );
839 }
840 }
841
842 XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
843
844 *(UINT32 *) Data = *(UINT32 *) &PortStatus;
845 }
846
847 FREE_URB:
848 XhcPeiFreeUrb (Xhc, Urb);
849
850 ON_EXIT:
851
852 if (EFI_ERROR (Status)) {
853 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
854 }
855
856 return Status;
857 }
858
859 /**
860 Submits bulk transfer to a bulk endpoint of a USB device.
861
862 @param PeiServices The pointer of EFI_PEI_SERVICES.
863 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
864 @param DeviceAddress Target device address.
865 @param EndPointAddress Endpoint number and its direction in bit 7.
866 @param DeviceSpeed Device speed, Low speed device doesn't support
867 bulk transfer.
868 @param MaximumPacketLength Maximum packet size the endpoint is capable of
869 sending or receiving.
870 @param Data Array of pointers to the buffers of data to transmit
871 from or receive into.
872 @param DataLength The lenght of the data buffer.
873 @param DataToggle On input, the initial data toggle for the transfer;
874 On output, it is updated to to next data toggle to use of
875 the subsequent bulk transfer.
876 @param TimeOut Indicates the maximum time, in millisecond, which the
877 transfer is allowed to complete.
878 If Timeout is 0, then the caller must wait for the function
879 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
880 @param Translator A pointr to the transaction translator data.
881 @param TransferResult A pointer to the detailed result information of the
882 bulk transfer.
883
884 @retval EFI_SUCCESS The transfer was completed successfully.
885 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
886 @retval EFI_INVALID_PARAMETER Parameters are invalid.
887 @retval EFI_TIMEOUT The transfer failed due to timeout.
888 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
889
890 **/
891 EFI_STATUS
892 EFIAPI
893 XhcPeiBulkTransfer (
894 IN EFI_PEI_SERVICES **PeiServices,
895 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
896 IN UINT8 DeviceAddress,
897 IN UINT8 EndPointAddress,
898 IN UINT8 DeviceSpeed,
899 IN UINTN MaximumPacketLength,
900 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
901 IN OUT UINTN *DataLength,
902 IN OUT UINT8 *DataToggle,
903 IN UINTN TimeOut,
904 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
905 OUT UINT32 *TransferResult
906 )
907 {
908 PEI_XHC_DEV *Xhc;
909 URB *Urb;
910 UINT8 SlotId;
911 EFI_STATUS Status;
912 EFI_STATUS RecoveryStatus;
913
914 //
915 // Validate the parameters
916 //
917 if ((DataLength == NULL) || (*DataLength == 0) ||
918 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
919 return EFI_INVALID_PARAMETER;
920 }
921
922 if ((*DataToggle != 0) && (*DataToggle != 1)) {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
927 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
928 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||
929 ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {
930 return EFI_INVALID_PARAMETER;
931 }
932
933 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
934
935 *TransferResult = EFI_USB_ERR_SYSTEM;
936 Status = EFI_DEVICE_ERROR;
937
938 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
939 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));
940 goto ON_EXIT;
941 }
942
943 //
944 // Check if the device is still enabled before every transaction.
945 //
946 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
947 if (SlotId == 0) {
948 goto ON_EXIT;
949 }
950
951 //
952 // Create a new URB, insert it into the asynchronous
953 // schedule list, then poll the execution status.
954 //
955 Urb = XhcPeiCreateUrb (
956 Xhc,
957 DeviceAddress,
958 EndPointAddress,
959 DeviceSpeed,
960 MaximumPacketLength,
961 XHC_BULK_TRANSFER,
962 NULL,
963 Data[0],
964 *DataLength,
965 NULL,
966 NULL
967 );
968
969 if (Urb == NULL) {
970 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));
971 Status = EFI_OUT_OF_RESOURCES;
972 goto ON_EXIT;
973 }
974
975 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
976
977 *TransferResult = Urb->Result;
978 *DataLength = Urb->Completed;
979
980 if (Status == EFI_TIMEOUT) {
981 //
982 // The transfer timed out. Abort the transfer by dequeueing of the TD.
983 //
984 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
985 if (EFI_ERROR(RecoveryStatus)) {
986 DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
987 }
988 } else {
989 if (*TransferResult == EFI_USB_NOERROR) {
990 Status = EFI_SUCCESS;
991 } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
992 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
993 if (EFI_ERROR (RecoveryStatus)) {
994 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
995 }
996 Status = EFI_DEVICE_ERROR;
997 }
998 }
999
1000 XhcPeiFreeUrb (Xhc, Urb);
1001
1002 ON_EXIT:
1003
1004 if (EFI_ERROR (Status)) {
1005 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1006 }
1007
1008 return Status;
1009 }
1010
1011 /**
1012 Retrieves the number of root hub ports.
1013
1014 @param[in] PeiServices The pointer to the PEI Services Table.
1015 @param[in] This The pointer to this instance of the
1016 PEI_USB2_HOST_CONTROLLER_PPI.
1017 @param[out] PortNumber The pointer to the number of the root hub ports.
1018
1019 @retval EFI_SUCCESS The port number was retrieved successfully.
1020 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
1021
1022 **/
1023 EFI_STATUS
1024 EFIAPI
1025 XhcPeiGetRootHubPortNumber (
1026 IN EFI_PEI_SERVICES **PeiServices,
1027 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1028 OUT UINT8 *PortNumber
1029 )
1030 {
1031 PEI_XHC_DEV *XhcDev;
1032 XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1033
1034 if (PortNumber == NULL) {
1035 return EFI_INVALID_PARAMETER;
1036 }
1037
1038 *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;
1039 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));
1040 return EFI_SUCCESS;
1041 }
1042
1043 /**
1044 Clears a feature for the specified root hub port.
1045
1046 @param PeiServices The pointer of EFI_PEI_SERVICES.
1047 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1048 @param PortNumber Specifies the root hub port whose feature
1049 is requested to be cleared.
1050 @param PortFeature Indicates the feature selector associated with the
1051 feature clear request.
1052
1053 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
1054 for the USB root hub port specified by PortNumber.
1055 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1056
1057 **/
1058 EFI_STATUS
1059 EFIAPI
1060 XhcPeiClearRootHubPortFeature (
1061 IN EFI_PEI_SERVICES **PeiServices,
1062 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1063 IN UINT8 PortNumber,
1064 IN EFI_USB_PORT_FEATURE PortFeature
1065 )
1066 {
1067 PEI_XHC_DEV *Xhc;
1068 UINT32 Offset;
1069 UINT32 State;
1070 EFI_STATUS Status;
1071
1072 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1073 Status = EFI_SUCCESS;
1074
1075 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1076 Status = EFI_INVALID_PARAMETER;
1077 goto ON_EXIT;
1078 }
1079
1080 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1081 State = XhcPeiReadOpReg (Xhc, Offset);
1082 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1083
1084 //
1085 // Mask off the port status change bits, these bits are
1086 // write clean bits
1087 //
1088 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1089
1090 switch (PortFeature) {
1091 case EfiUsbPortEnable:
1092 //
1093 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1094 // A port may be disabled by software writing a '1' to this flag.
1095 //
1096 State |= XHC_PORTSC_PED;
1097 State &= ~XHC_PORTSC_RESET;
1098 XhcPeiWriteOpReg (Xhc, Offset, State);
1099 break;
1100
1101 case EfiUsbPortSuspend:
1102 State |= XHC_PORTSC_LWS;
1103 XhcPeiWriteOpReg (Xhc, Offset, State);
1104 State &= ~XHC_PORTSC_PLS;
1105 XhcPeiWriteOpReg (Xhc, Offset, State);
1106 break;
1107
1108 case EfiUsbPortReset:
1109 //
1110 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
1111 // Register bits indicate status when read, a clear bit may be set by
1112 // writing a '1'. Writing a '0' to RW1S bits has no effect.
1113 //
1114 break;
1115
1116 case EfiUsbPortPower:
1117 if (Xhc->HcCParams.Data.Ppc) {
1118 //
1119 // Port Power Control supported
1120 //
1121 State &= ~XHC_PORTSC_PP;
1122 XhcPeiWriteOpReg (Xhc, Offset, State);
1123 }
1124 break;
1125
1126 case EfiUsbPortOwner:
1127 //
1128 // XHCI root hub port don't has the owner bit, ignore the operation
1129 //
1130 break;
1131
1132 case EfiUsbPortConnectChange:
1133 //
1134 // Clear connect status change
1135 //
1136 State |= XHC_PORTSC_CSC;
1137 XhcPeiWriteOpReg (Xhc, Offset, State);
1138 break;
1139
1140 case EfiUsbPortEnableChange:
1141 //
1142 // Clear enable status change
1143 //
1144 State |= XHC_PORTSC_PEC;
1145 XhcPeiWriteOpReg (Xhc, Offset, State);
1146 break;
1147
1148 case EfiUsbPortOverCurrentChange:
1149 //
1150 // Clear PortOverCurrent change
1151 //
1152 State |= XHC_PORTSC_OCC;
1153 XhcPeiWriteOpReg (Xhc, Offset, State);
1154 break;
1155
1156 case EfiUsbPortResetChange:
1157 //
1158 // Clear Port Reset change
1159 //
1160 State |= XHC_PORTSC_PRC;
1161 XhcPeiWriteOpReg (Xhc, Offset, State);
1162 break;
1163
1164 case EfiUsbPortSuspendChange:
1165 //
1166 // Not supported or not related operation
1167 //
1168 break;
1169
1170 default:
1171 Status = EFI_INVALID_PARAMETER;
1172 break;
1173 }
1174
1175 ON_EXIT:
1176 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1177 return Status;
1178 }
1179
1180 /**
1181 Sets a feature for the specified root hub port.
1182
1183 @param PeiServices The pointer of EFI_PEI_SERVICES
1184 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
1185 @param PortNumber Root hub port to set.
1186 @param PortFeature Feature to set.
1187
1188 @retval EFI_SUCCESS The feature specified by PortFeature was set.
1189 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1190 @retval EFI_TIMEOUT The time out occurred.
1191
1192 **/
1193 EFI_STATUS
1194 EFIAPI
1195 XhcPeiSetRootHubPortFeature (
1196 IN EFI_PEI_SERVICES **PeiServices,
1197 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1198 IN UINT8 PortNumber,
1199 IN EFI_USB_PORT_FEATURE PortFeature
1200 )
1201 {
1202 PEI_XHC_DEV *Xhc;
1203 UINT32 Offset;
1204 UINT32 State;
1205 EFI_STATUS Status;
1206
1207 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1208 Status = EFI_SUCCESS;
1209
1210 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1211 Status = EFI_INVALID_PARAMETER;
1212 goto ON_EXIT;
1213 }
1214
1215 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1216 State = XhcPeiReadOpReg (Xhc, Offset);
1217 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1218
1219 //
1220 // Mask off the port status change bits, these bits are
1221 // write clean bits
1222 //
1223 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1224
1225 switch (PortFeature) {
1226 case EfiUsbPortEnable:
1227 //
1228 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1229 // A port may be disabled by software writing a '1' to this flag.
1230 //
1231 break;
1232
1233 case EfiUsbPortSuspend:
1234 State |= XHC_PORTSC_LWS;
1235 XhcPeiWriteOpReg (Xhc, Offset, State);
1236 State &= ~XHC_PORTSC_PLS;
1237 State |= (3 << 5) ;
1238 XhcPeiWriteOpReg (Xhc, Offset, State);
1239 break;
1240
1241 case EfiUsbPortReset:
1242 //
1243 // Make sure Host Controller not halt before reset it
1244 //
1245 if (XhcPeiIsHalt (Xhc)) {
1246 Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);
1247 if (EFI_ERROR (Status)) {
1248 break;
1249 }
1250 }
1251
1252 //
1253 // 4.3.1 Resetting a Root Hub Port
1254 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
1255 // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)
1256 // bit in the PORTSC field is set to '1'.
1257 //
1258 State |= XHC_PORTSC_RESET;
1259 XhcPeiWriteOpReg (Xhc, Offset, State);
1260 XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
1261 break;
1262
1263 case EfiUsbPortPower:
1264 if (Xhc->HcCParams.Data.Ppc) {
1265 //
1266 // Port Power Control supported
1267 //
1268 State |= XHC_PORTSC_PP;
1269 XhcPeiWriteOpReg (Xhc, Offset, State);
1270 }
1271 break;
1272
1273 case EfiUsbPortOwner:
1274 //
1275 // XHCI root hub port don't has the owner bit, ignore the operation
1276 //
1277 break;
1278
1279 default:
1280 Status = EFI_INVALID_PARAMETER;
1281 }
1282
1283 ON_EXIT:
1284 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1285 return Status;
1286 }
1287
1288 /**
1289 Retrieves the current status of a USB root hub port.
1290
1291 @param PeiServices The pointer of EFI_PEI_SERVICES.
1292 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1293 @param PortNumber The root hub port to retrieve the state from.
1294 @param PortStatus Variable to receive the port state.
1295
1296 @retval EFI_SUCCESS The status of the USB root hub port specified.
1297 by PortNumber was returned in PortStatus.
1298 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
1299
1300 **/
1301 EFI_STATUS
1302 EFIAPI
1303 XhcPeiGetRootHubPortStatus (
1304 IN EFI_PEI_SERVICES **PeiServices,
1305 IN PEI_USB2_HOST_CONTROLLER_PPI *This,
1306 IN UINT8 PortNumber,
1307 OUT EFI_USB_PORT_STATUS *PortStatus
1308 )
1309 {
1310 PEI_XHC_DEV *Xhc;
1311 UINT32 Offset;
1312 UINT32 State;
1313 UINTN Index;
1314 UINTN MapSize;
1315 USB_DEV_ROUTE ParentRouteChart;
1316
1317 if (PortStatus == NULL) {
1318 return EFI_INVALID_PARAMETER;
1319 }
1320
1321 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1322
1323 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1324 return EFI_INVALID_PARAMETER;
1325 }
1326
1327 //
1328 // Clear port status.
1329 //
1330 PortStatus->PortStatus = 0;
1331 PortStatus->PortChangeStatus = 0;
1332
1333 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1334 State = XhcPeiReadOpReg (Xhc, Offset);
1335 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));
1336
1337 //
1338 // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.
1339 //
1340 switch ((State & XHC_PORTSC_PS) >> 10) {
1341 case 2:
1342 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
1343 break;
1344
1345 case 3:
1346 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1347 break;
1348
1349 case 4:
1350 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1351 break;
1352
1353 default:
1354 break;
1355 }
1356
1357 //
1358 // Convert the XHCI port/port change state to UEFI status
1359 //
1360 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1361
1362 for (Index = 0; Index < MapSize; Index++) {
1363 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
1364 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
1365 }
1366 }
1367 //
1368 // Bit5~8 reflects its current link state.
1369 //
1370 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
1371 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
1372 }
1373
1374 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1375
1376 for (Index = 0; Index < MapSize; Index++) {
1377 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
1378 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
1379 }
1380 }
1381
1382 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
1383
1384 for (Index = 0; Index < MapSize; Index++) {
1385 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
1386 XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
1387 }
1388 }
1389
1390 //
1391 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
1392 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
1393 //
1394 ParentRouteChart.Dword = 0;
1395 XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
1396
1397 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));
1398 return EFI_SUCCESS;
1399 }
1400
1401 /**
1402 @param FileHandle Handle of the file being invoked.
1403 @param PeiServices Describes the list of possible PEI Services.
1404
1405 @retval EFI_SUCCESS PPI successfully installed.
1406
1407 **/
1408 EFI_STATUS
1409 EFIAPI
1410 XhcPeimEntry (
1411 IN EFI_PEI_FILE_HANDLE FileHandle,
1412 IN CONST EFI_PEI_SERVICES **PeiServices
1413 )
1414 {
1415 PEI_USB_CONTROLLER_PPI *UsbControllerPpi;
1416 EFI_STATUS Status;
1417 UINT8 Index;
1418 UINTN ControllerType;
1419 UINTN BaseAddress;
1420 UINTN MemPages;
1421 PEI_XHC_DEV *XhcDev;
1422 EFI_PHYSICAL_ADDRESS TempPtr;
1423 UINT32 PageSize;
1424
1425 //
1426 // Shadow this PEIM to run from memory.
1427 //
1428 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1429 return EFI_SUCCESS;
1430 }
1431
1432 Status = PeiServicesLocatePpi (
1433 &gPeiUsbControllerPpiGuid,
1434 0,
1435 NULL,
1436 (VOID **) &UsbControllerPpi
1437 );
1438 if (EFI_ERROR (Status)) {
1439 return EFI_UNSUPPORTED;
1440 }
1441
1442 Index = 0;
1443 while (TRUE) {
1444 Status = UsbControllerPpi->GetUsbController (
1445 (EFI_PEI_SERVICES **) PeiServices,
1446 UsbControllerPpi,
1447 Index,
1448 &ControllerType,
1449 &BaseAddress
1450 );
1451 //
1452 // When status is error, it means no controller is found.
1453 //
1454 if (EFI_ERROR (Status)) {
1455 break;
1456 }
1457
1458 //
1459 // This PEIM is for XHC type controller.
1460 //
1461 if (ControllerType != PEI_XHCI_CONTROLLER) {
1462 Index++;
1463 continue;
1464 }
1465
1466 MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));
1467 Status = PeiServicesAllocatePages (
1468 EfiBootServicesData,
1469 MemPages,
1470 &TempPtr
1471 );
1472 if (EFI_ERROR (Status)) {
1473 return EFI_OUT_OF_RESOURCES;
1474 }
1475 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));
1476 XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);
1477
1478 XhcDev->Signature = USB_XHC_DEV_SIGNATURE;
1479 XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
1480 XhcDev->CapLength = (UINT8) (XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);
1481 XhcDev->HcSParams1.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);
1482 XhcDev->HcSParams2.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);
1483 XhcDev->HcCParams.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);
1484 XhcDev->DBOff = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);
1485 XhcDev->RTSOff = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);
1486
1487 //
1488 // This PageSize field defines the page size supported by the xHC implementation.
1489 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1490 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1491 //
1492 PageSize = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
1493 XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
1494
1495 DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));
1496 DEBUG ((EFI_D_INFO, "XhciPei: CapLength: %x\n", XhcDev->CapLength));
1497 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1: %x\n", XhcDev->HcSParams1.Dword));
1498 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2: %x\n", XhcDev->HcSParams2.Dword));
1499 DEBUG ((EFI_D_INFO, "XhciPei: HcCParams: %x\n", XhcDev->HcCParams.Dword));
1500 DEBUG ((EFI_D_INFO, "XhciPei: DBOff: %x\n", XhcDev->DBOff));
1501 DEBUG ((EFI_D_INFO, "XhciPei: RTSOff: %x\n", XhcDev->RTSOff));
1502 DEBUG ((EFI_D_INFO, "XhciPei: PageSize: %x\n", XhcDev->PageSize));
1503
1504 XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);
1505 ASSERT (XhcPeiIsHalt (XhcDev));
1506
1507 //
1508 // Initialize the schedule
1509 //
1510 XhcPeiInitSched (XhcDev);
1511
1512 //
1513 // Start the Host Controller
1514 //
1515 XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);
1516
1517 //
1518 // Wait for root port state stable
1519 //
1520 MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);
1521
1522 XhcDev->Usb2HostControllerPpi.ControlTransfer = XhcPeiControlTransfer;
1523 XhcDev->Usb2HostControllerPpi.BulkTransfer = XhcPeiBulkTransfer;
1524 XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = XhcPeiGetRootHubPortNumber;
1525 XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = XhcPeiGetRootHubPortStatus;
1526 XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = XhcPeiSetRootHubPortFeature;
1527 XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = XhcPeiClearRootHubPortFeature;
1528
1529 XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1530 XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1531 XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;
1532
1533 PeiServicesInstallPpi (&XhcDev->PpiDescriptor);
1534
1535 Index++;
1536 }
1537
1538 return EFI_SUCCESS;
1539 }
1540