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