]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
d8fa41f68f5577aa595bf9dd4c09d9ddc935ab73
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / Xhci.c
1 /** @file
2 The XHCI controller driver.
3
4 Copyright (c) 2011 - 2022, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "Xhci.h"
10
11 //
12 // Two arrays used to translate the XHCI port state (change)
13 // to the UEFI protocol's port state (change).
14 //
15 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
16 { XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION },
17 { XHC_PORTSC_PED, USB_PORT_STAT_ENABLE },
18 { XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },
19 { XHC_PORTSC_RESET, USB_PORT_STAT_RESET }
20 };
21
22 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
23 { XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },
24 { XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },
25 { XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },
26 { XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET }
27 };
28
29 USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
30 { XHC_PORTSC_CSC, EfiUsbPortConnectChange },
31 { XHC_PORTSC_PEC, EfiUsbPortEnableChange },
32 { XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange },
33 { XHC_PORTSC_PRC, EfiUsbPortResetChange }
34 };
35
36 USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
37 { XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION },
38 { XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE },
39 { XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },
40 { XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET }
41 };
42
43 USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
44 { XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },
45 { XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },
46 { XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },
47 { XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET }
48 };
49
50 USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
51 { XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange },
52 { XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange },
53 { XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange },
54 { XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange },
55 { XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange }
56 };
57
58 EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = {
59 XhcDriverBindingSupported,
60 XhcDriverBindingStart,
61 XhcDriverBindingStop,
62 0x30,
63 NULL,
64 NULL
65 };
66
67 //
68 // Template for Xhci's Usb2 Host Controller Protocol Instance.
69 //
70 EFI_USB2_HC_PROTOCOL gXhciUsb2HcTemplate = {
71 XhcGetCapability,
72 XhcReset,
73 XhcGetState,
74 XhcSetState,
75 XhcControlTransfer,
76 XhcBulkTransfer,
77 XhcAsyncInterruptTransfer,
78 XhcSyncInterruptTransfer,
79 XhcIsochronousTransfer,
80 XhcAsyncIsochronousTransfer,
81 XhcGetRootHubPortStatus,
82 XhcSetRootHubPortFeature,
83 XhcClearRootHubPortFeature,
84 0x3,
85 0x0
86 };
87
88 /**
89 Retrieves the capability of root hub ports.
90
91 @param This The EFI_USB2_HC_PROTOCOL instance.
92 @param MaxSpeed Max speed supported by the controller.
93 @param PortNumber Number of the root hub ports.
94 @param Is64BitCapable Whether the controller supports 64-bit memory
95 addressing.
96
97 @retval EFI_SUCCESS Host controller capability were retrieved successfully.
98 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
99
100 **/
101 EFI_STATUS
102 EFIAPI
103 XhcGetCapability (
104 IN EFI_USB2_HC_PROTOCOL *This,
105 OUT UINT8 *MaxSpeed,
106 OUT UINT8 *PortNumber,
107 OUT UINT8 *Is64BitCapable
108 )
109 {
110 USB_XHCI_INSTANCE *Xhc;
111 EFI_TPL OldTpl;
112
113 if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {
114 return EFI_INVALID_PARAMETER;
115 }
116
117 OldTpl = gBS->RaiseTPL (XHC_TPL);
118
119 Xhc = XHC_FROM_THIS (This);
120 *MaxSpeed = EFI_USB_SPEED_SUPER;
121 *PortNumber = (UINT8)(Xhc->HcSParams1.Data.MaxPorts);
122 *Is64BitCapable = (UINT8)Xhc->Support64BitDma;
123 DEBUG ((DEBUG_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));
124
125 gBS->RestoreTPL (OldTpl);
126
127 return EFI_SUCCESS;
128 }
129
130 /**
131 Provides software reset for the USB host controller.
132
133 @param This This EFI_USB2_HC_PROTOCOL instance.
134 @param Attributes A bit mask of the reset operation to perform.
135
136 @retval EFI_SUCCESS The reset operation succeeded.
137 @retval EFI_INVALID_PARAMETER Attributes is not valid.
138 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
139 not currently supported by the host controller.
140 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
141
142 **/
143 EFI_STATUS
144 EFIAPI
145 XhcReset (
146 IN EFI_USB2_HC_PROTOCOL *This,
147 IN UINT16 Attributes
148 )
149 {
150 USB_XHCI_INSTANCE *Xhc;
151 EFI_STATUS Status;
152 EFI_TPL OldTpl;
153
154 Xhc = XHC_FROM_THIS (This);
155
156 if (Xhc->DevicePath != NULL) {
157 //
158 // Report Status Code to indicate reset happens
159 //
160 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
161 EFI_PROGRESS_CODE,
162 (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
163 Xhc->DevicePath
164 );
165 }
166
167 OldTpl = gBS->RaiseTPL (XHC_TPL);
168
169 switch (Attributes) {
170 case EFI_USB_HC_RESET_GLOBAL:
171 //
172 // Flow through, same behavior as Host Controller Reset
173 //
174 case EFI_USB_HC_RESET_HOST_CONTROLLER:
175 if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) &&
176 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0))
177 {
178 Status = EFI_SUCCESS;
179 goto ON_EXIT;
180 }
181
182 //
183 // Host Controller must be Halt when Reset it
184 //
185 if (!XhcIsHalt (Xhc)) {
186 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
187
188 if (EFI_ERROR (Status)) {
189 Status = EFI_DEVICE_ERROR;
190 goto ON_EXIT;
191 }
192 }
193
194 Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
195 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
196
197 if (EFI_ERROR (Status)) {
198 goto ON_EXIT;
199 }
200
201 //
202 // Clean up the asynchronous transfers, currently only
203 // interrupt supports asynchronous operation.
204 //
205 XhciDelAllAsyncIntTransfers (Xhc);
206 XhcFreeSched (Xhc);
207
208 XhcInitSched (Xhc);
209 break;
210
211 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
212 case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
213 Status = EFI_UNSUPPORTED;
214 break;
215
216 default:
217 Status = EFI_INVALID_PARAMETER;
218 }
219
220 ON_EXIT:
221 DEBUG ((DEBUG_INFO, "XhcReset: status %r\n", Status));
222 gBS->RestoreTPL (OldTpl);
223
224 return Status;
225 }
226
227 /**
228 Retrieve the current state of the USB host controller.
229
230 @param This This EFI_USB2_HC_PROTOCOL instance.
231 @param State Variable to return the current host controller
232 state.
233
234 @retval EFI_SUCCESS Host controller state was returned in State.
235 @retval EFI_INVALID_PARAMETER State is NULL.
236 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
237 retrieve the host controller's current state.
238
239 **/
240 EFI_STATUS
241 EFIAPI
242 XhcGetState (
243 IN EFI_USB2_HC_PROTOCOL *This,
244 OUT EFI_USB_HC_STATE *State
245 )
246 {
247 USB_XHCI_INSTANCE *Xhc;
248 EFI_TPL OldTpl;
249
250 if (State == NULL) {
251 return EFI_INVALID_PARAMETER;
252 }
253
254 OldTpl = gBS->RaiseTPL (XHC_TPL);
255
256 Xhc = XHC_FROM_THIS (This);
257
258 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
259 *State = EfiUsbHcStateHalt;
260 } else {
261 *State = EfiUsbHcStateOperational;
262 }
263
264 DEBUG ((DEBUG_INFO, "XhcGetState: current state %d\n", *State));
265 gBS->RestoreTPL (OldTpl);
266
267 return EFI_SUCCESS;
268 }
269
270 /**
271 Sets the USB host controller to a specific state.
272
273 @param This This EFI_USB2_HC_PROTOCOL instance.
274 @param State The state of the host controller that will be set.
275
276 @retval EFI_SUCCESS The USB host controller was successfully placed
277 in the state specified by State.
278 @retval EFI_INVALID_PARAMETER State is invalid.
279 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
280
281 **/
282 EFI_STATUS
283 EFIAPI
284 XhcSetState (
285 IN EFI_USB2_HC_PROTOCOL *This,
286 IN EFI_USB_HC_STATE State
287 )
288 {
289 USB_XHCI_INSTANCE *Xhc;
290 EFI_STATUS Status;
291 EFI_USB_HC_STATE CurState;
292 EFI_TPL OldTpl;
293
294 Status = XhcGetState (This, &CurState);
295
296 if (EFI_ERROR (Status)) {
297 return EFI_DEVICE_ERROR;
298 }
299
300 if (CurState == State) {
301 return EFI_SUCCESS;
302 }
303
304 OldTpl = gBS->RaiseTPL (XHC_TPL);
305
306 Xhc = XHC_FROM_THIS (This);
307
308 switch (State) {
309 case EfiUsbHcStateHalt:
310 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
311 break;
312
313 case EfiUsbHcStateOperational:
314 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE)) {
315 Status = EFI_DEVICE_ERROR;
316 break;
317 }
318
319 //
320 // Software must not write a one to this field unless the host controller
321 // is in the Halted state. Doing so will yield undefined results.
322 // refers to Spec[XHCI1.0-2.3.1]
323 //
324 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
325 Status = EFI_DEVICE_ERROR;
326 break;
327 }
328
329 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
330 break;
331
332 case EfiUsbHcStateSuspend:
333 Status = EFI_UNSUPPORTED;
334 break;
335
336 default:
337 Status = EFI_INVALID_PARAMETER;
338 }
339
340 DEBUG ((DEBUG_INFO, "XhcSetState: status %r\n", Status));
341 gBS->RestoreTPL (OldTpl);
342
343 return Status;
344 }
345
346 /**
347 Retrieves the current status of a USB root hub port.
348
349 @param This This EFI_USB2_HC_PROTOCOL instance.
350 @param PortNumber The root hub port to retrieve the state from.
351 This value is zero-based.
352 @param PortStatus Variable to receive the port state.
353
354 @retval EFI_SUCCESS The status of the USB root hub port specified.
355 by PortNumber was returned in PortStatus.
356 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
357 @retval EFI_DEVICE_ERROR Can't read register.
358
359 **/
360 EFI_STATUS
361 EFIAPI
362 XhcGetRootHubPortStatus (
363 IN EFI_USB2_HC_PROTOCOL *This,
364 IN UINT8 PortNumber,
365 OUT EFI_USB_PORT_STATUS *PortStatus
366 )
367 {
368 USB_XHCI_INSTANCE *Xhc;
369 UINT32 Offset;
370 UINT32 State;
371 UINT32 TotalPort;
372 UINTN Index;
373 UINTN MapSize;
374 UINT8 PortSpeed;
375 EFI_STATUS Status;
376 USB_DEV_ROUTE ParentRouteChart;
377 EFI_TPL OldTpl;
378
379 if (PortStatus == NULL) {
380 return EFI_INVALID_PARAMETER;
381 }
382
383 OldTpl = gBS->RaiseTPL (XHC_TPL);
384
385 Xhc = XHC_FROM_THIS (This);
386 Status = EFI_SUCCESS;
387
388 TotalPort = Xhc->HcSParams1.Data.MaxPorts;
389
390 if (PortNumber >= TotalPort) {
391 Status = EFI_INVALID_PARAMETER;
392 goto ON_EXIT;
393 }
394
395 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));
396 PortStatus->PortStatus = 0;
397 PortStatus->PortChangeStatus = 0;
398
399 State = XhcReadOpReg (Xhc, Offset);
400
401 PortSpeed = (State & XHC_PORTSC_PS) >> 10;
402
403 //
404 // According to XHCI 1.1 spec November 2017,
405 // Section 7.2 xHCI Support Protocol Capability
406 //
407 if (PortSpeed > 0) {
408 PortStatus->PortStatus = XhcCheckUsbPortSpeedUsedPsic (Xhc, PortSpeed, PortNumber);
409 // If no match found in ext cap reg, fall back to PORTSC
410 if (PortStatus->PortStatus == 0) {
411 //
412 // According to XHCI 1.1 spec November 2017,
413 // bit 10~13 of the root port status register identifies the speed of the attached device.
414 //
415 switch (PortSpeed) {
416 case 2:
417 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
418 break;
419
420 case 3:
421 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
422 break;
423
424 case 4:
425 case 5:
426 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
427 break;
428
429 default:
430 break;
431 }
432 }
433 }
434
435 //
436 // Convert the XHCI port/port change state to UEFI status
437 //
438 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
439
440 for (Index = 0; Index < MapSize; Index++) {
441 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
442 PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
443 }
444 }
445
446 //
447 // Bit5~8 reflects its current link state.
448 //
449 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
450 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
451 }
452
453 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
454
455 for (Index = 0; Index < MapSize; Index++) {
456 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
457 PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
458 }
459 }
460
461 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
462
463 for (Index = 0; Index < MapSize; Index++) {
464 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
465 XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
466 }
467 }
468
469 //
470 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
471 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
472 //
473 ParentRouteChart.Dword = 0;
474 Status = XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
475
476 //
477 // Force resetting the port by clearing the USB_PORT_STAT_C_RESET bit in PortChangeStatus
478 // when XhcPollPortStatusChange fails
479 //
480 if (EFI_ERROR (Status)) {
481 PortStatus->PortChangeStatus &= ~(USB_PORT_STAT_C_RESET);
482 Status = EFI_SUCCESS;
483 }
484
485 ON_EXIT:
486 gBS->RestoreTPL (OldTpl);
487 return Status;
488 }
489
490 /**
491 Sets a feature for the specified root hub port.
492
493 @param This This EFI_USB2_HC_PROTOCOL instance.
494 @param PortNumber Root hub port to set.
495 @param PortFeature Feature to set.
496
497 @retval EFI_SUCCESS The feature specified by PortFeature was set.
498 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
499 @retval EFI_DEVICE_ERROR Can't read register.
500
501 **/
502 EFI_STATUS
503 EFIAPI
504 XhcSetRootHubPortFeature (
505 IN EFI_USB2_HC_PROTOCOL *This,
506 IN UINT8 PortNumber,
507 IN EFI_USB_PORT_FEATURE PortFeature
508 )
509 {
510 USB_XHCI_INSTANCE *Xhc;
511 UINT32 Offset;
512 UINT32 State;
513 UINT32 TotalPort;
514 EFI_STATUS Status;
515 EFI_TPL OldTpl;
516
517 OldTpl = gBS->RaiseTPL (XHC_TPL);
518
519 Xhc = XHC_FROM_THIS (This);
520 Status = EFI_SUCCESS;
521
522 TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
523
524 if (PortNumber >= TotalPort) {
525 Status = EFI_INVALID_PARAMETER;
526 goto ON_EXIT;
527 }
528
529 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));
530 State = XhcReadOpReg (Xhc, Offset);
531
532 //
533 // Mask off the port status change bits, these bits are
534 // write clean bit
535 //
536 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
537
538 switch (PortFeature) {
539 case EfiUsbPortEnable:
540 //
541 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
542 // A port may be disabled by software writing a '1' to this flag.
543 //
544 Status = EFI_SUCCESS;
545 break;
546
547 case EfiUsbPortSuspend:
548 State |= XHC_PORTSC_LWS;
549 XhcWriteOpReg (Xhc, Offset, State);
550 State &= ~XHC_PORTSC_PLS;
551 State |= (3 << 5);
552 XhcWriteOpReg (Xhc, Offset, State);
553 break;
554
555 case EfiUsbPortReset:
556 DEBUG ((DEBUG_INFO, "XhcUsbPortReset!\n"));
557 //
558 // Make sure Host Controller not halt before reset it
559 //
560 if (XhcIsHalt (Xhc)) {
561 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
562
563 if (EFI_ERROR (Status)) {
564 DEBUG ((DEBUG_INFO, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status));
565 break;
566 }
567 }
568
569 //
570 // 4.3.1 Resetting a Root Hub Port
571 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
572 //
573 State |= XHC_PORTSC_RESET;
574 XhcWriteOpReg (Xhc, Offset, State);
575 XhcWaitOpRegBit (Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
576 break;
577
578 case EfiUsbPortPower:
579 //
580 // Not supported, ignore the operation
581 //
582 Status = EFI_SUCCESS;
583 break;
584
585 case EfiUsbPortOwner:
586 //
587 // XHCI root hub port don't has the owner bit, ignore the operation
588 //
589 Status = EFI_SUCCESS;
590 break;
591
592 default:
593 Status = EFI_INVALID_PARAMETER;
594 }
595
596 ON_EXIT:
597 DEBUG ((DEBUG_INFO, "XhcSetRootHubPortFeature: status %r\n", Status));
598 gBS->RestoreTPL (OldTpl);
599
600 return Status;
601 }
602
603 /**
604 Clears a feature for the specified root hub port.
605
606 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
607 @param PortNumber Specifies the root hub port whose feature is
608 requested to be cleared.
609 @param PortFeature Indicates the feature selector associated with the
610 feature clear request.
611
612 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
613 for the USB root hub port specified by PortNumber.
614 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
615 @retval EFI_DEVICE_ERROR Can't read register.
616
617 **/
618 EFI_STATUS
619 EFIAPI
620 XhcClearRootHubPortFeature (
621 IN EFI_USB2_HC_PROTOCOL *This,
622 IN UINT8 PortNumber,
623 IN EFI_USB_PORT_FEATURE PortFeature
624 )
625 {
626 USB_XHCI_INSTANCE *Xhc;
627 UINT32 Offset;
628 UINT32 State;
629 UINT32 TotalPort;
630 EFI_STATUS Status;
631 EFI_TPL OldTpl;
632
633 OldTpl = gBS->RaiseTPL (XHC_TPL);
634
635 Xhc = XHC_FROM_THIS (This);
636 Status = EFI_SUCCESS;
637
638 TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
639
640 if (PortNumber >= TotalPort) {
641 Status = EFI_INVALID_PARAMETER;
642 goto ON_EXIT;
643 }
644
645 Offset = XHC_PORTSC_OFFSET + (0x10 * PortNumber);
646
647 //
648 // Mask off the port status change bits, these bits are
649 // write clean bit
650 //
651 State = XhcReadOpReg (Xhc, Offset);
652 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
653
654 switch (PortFeature) {
655 case EfiUsbPortEnable:
656 //
657 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
658 // A port may be disabled by software writing a '1' to this flag.
659 //
660 State |= XHC_PORTSC_PED;
661 State &= ~XHC_PORTSC_RESET;
662 XhcWriteOpReg (Xhc, Offset, State);
663 break;
664
665 case EfiUsbPortSuspend:
666 State |= XHC_PORTSC_LWS;
667 XhcWriteOpReg (Xhc, Offset, State);
668 State &= ~XHC_PORTSC_PLS;
669 XhcWriteOpReg (Xhc, Offset, State);
670 break;
671
672 case EfiUsbPortReset:
673 //
674 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
675 // Register bits indicate status when read, a clear bit may be set by
676 // writing a '1'. Writing a '0' to RW1S bits has no effect.
677 //
678 break;
679
680 case EfiUsbPortOwner:
681 //
682 // XHCI root hub port don't has the owner bit, ignore the operation
683 //
684 break;
685
686 case EfiUsbPortConnectChange:
687 //
688 // Clear connect status change
689 //
690 State |= XHC_PORTSC_CSC;
691 XhcWriteOpReg (Xhc, Offset, State);
692 break;
693
694 case EfiUsbPortEnableChange:
695 //
696 // Clear enable status change
697 //
698 State |= XHC_PORTSC_PEC;
699 XhcWriteOpReg (Xhc, Offset, State);
700 break;
701
702 case EfiUsbPortOverCurrentChange:
703 //
704 // Clear PortOverCurrent change
705 //
706 State |= XHC_PORTSC_OCC;
707 XhcWriteOpReg (Xhc, Offset, State);
708 break;
709
710 case EfiUsbPortResetChange:
711 //
712 // Clear Port Reset change
713 //
714 State |= XHC_PORTSC_PRC;
715 XhcWriteOpReg (Xhc, Offset, State);
716 break;
717
718 case EfiUsbPortPower:
719 case EfiUsbPortSuspendChange:
720 //
721 // Not supported or not related operation
722 //
723 break;
724
725 default:
726 Status = EFI_INVALID_PARAMETER;
727 break;
728 }
729
730 ON_EXIT:
731 DEBUG ((DEBUG_INFO, "XhcClearRootHubPortFeature: status %r\n", Status));
732 gBS->RestoreTPL (OldTpl);
733
734 return Status;
735 }
736
737 /**
738 Submits a new transaction to a target USB device.
739
740 @param Xhc The XHCI Instance.
741 @param DeviceAddress The target device address.
742 @param EndPointAddress Endpoint number and its direction encoded in bit 7
743 @param DeviceSpeed Target device speed.
744 @param MaximumPacketLength Maximum packet size the default control transfer
745 endpoint is capable of sending or receiving.
746 @param Type The transaction type.
747 @param Request USB device request to send.
748 @param Data Data buffer to be transmitted or received from USB
749 device.
750 @param DataLength The size (in bytes) of the data buffer.
751 @param Timeout Indicates the maximum timeout, in millisecond.
752 @param TransferResult Return the result of this control transfer.
753
754 @retval EFI_SUCCESS Transfer was completed successfully.
755 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
756 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
757 @retval EFI_TIMEOUT Transfer failed due to timeout.
758 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
759 **/
760 EFI_STATUS
761 XhcTransfer (
762 IN USB_XHCI_INSTANCE *Xhc,
763 IN UINT8 DeviceAddress,
764 IN UINT8 EndPointAddress,
765 IN UINT8 DeviceSpeed,
766 IN UINTN MaximumPacketLength,
767 IN UINTN Type,
768 IN EFI_USB_DEVICE_REQUEST *Request,
769 IN OUT VOID *Data,
770 IN OUT UINTN *DataLength,
771 IN UINTN Timeout,
772 OUT UINT32 *TransferResult
773 )
774 {
775 EFI_STATUS Status;
776 EFI_STATUS RecoveryStatus;
777 URB *Urb;
778
779 ASSERT ((Type == XHC_CTRL_TRANSFER) || (Type == XHC_BULK_TRANSFER) || (Type == XHC_INT_TRANSFER_SYNC));
780 Urb = XhcCreateUrb (
781 Xhc,
782 DeviceAddress,
783 EndPointAddress,
784 DeviceSpeed,
785 MaximumPacketLength,
786 Type,
787 Request,
788 Data,
789 *DataLength,
790 NULL,
791 NULL
792 );
793
794 if (Urb == NULL) {
795 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: failed to create URB!\n", Type));
796 return EFI_OUT_OF_RESOURCES;
797 }
798
799 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
800
801 if (Status == EFI_TIMEOUT) {
802 //
803 // The transfer timed out. Abort the transfer by dequeueing of the TD.
804 //
805 RecoveryStatus = XhcDequeueTrbFromEndpoint (Xhc, Urb);
806 if (RecoveryStatus == EFI_ALREADY_STARTED) {
807 //
808 // The URB is finished just before stopping endpoint.
809 // Change returning status from EFI_TIMEOUT to EFI_SUCCESS.
810 //
811 ASSERT (Urb->Result == EFI_USB_NOERROR);
812 Status = EFI_SUCCESS;
813 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: pending URB is finished, Length = %d.\n", Type, Urb->Completed));
814 } else if (EFI_ERROR (RecoveryStatus)) {
815 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcDequeueTrbFromEndpoint failed!\n", Type));
816 }
817 }
818
819 *TransferResult = Urb->Result;
820 *DataLength = Urb->Completed;
821
822 if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
823 ASSERT (Status == EFI_DEVICE_ERROR);
824 RecoveryStatus = XhcRecoverHaltedEndpoint (Xhc, Urb);
825 if (EFI_ERROR (RecoveryStatus)) {
826 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcRecoverHaltedEndpoint failed!\n", Type));
827 }
828 }
829
830 Xhc->PciIo->Flush (Xhc->PciIo);
831 XhcFreeUrb (Xhc, Urb);
832 return Status;
833 }
834
835 /**
836 Submits control transfer to a target USB device.
837
838 @param This This EFI_USB2_HC_PROTOCOL instance.
839 @param DeviceAddress The target device address.
840 @param DeviceSpeed Target device speed.
841 @param MaximumPacketLength Maximum packet size the default control transfer
842 endpoint is capable of sending or receiving.
843 @param Request USB device request to send.
844 @param TransferDirection Specifies the data direction for the data stage
845 @param Data Data buffer to be transmitted or received from USB
846 device.
847 @param DataLength The size (in bytes) of the data buffer.
848 @param Timeout Indicates the maximum timeout, in millisecond.
849 @param Translator Transaction translator to be used by this device.
850 @param TransferResult Return the result of this control transfer.
851
852 @retval EFI_SUCCESS Transfer was completed successfully.
853 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
854 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
855 @retval EFI_TIMEOUT Transfer failed due to timeout.
856 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
857
858 **/
859 EFI_STATUS
860 EFIAPI
861 XhcControlTransfer (
862 IN EFI_USB2_HC_PROTOCOL *This,
863 IN UINT8 DeviceAddress,
864 IN UINT8 DeviceSpeed,
865 IN UINTN MaximumPacketLength,
866 IN EFI_USB_DEVICE_REQUEST *Request,
867 IN EFI_USB_DATA_DIRECTION TransferDirection,
868 IN OUT VOID *Data,
869 IN OUT UINTN *DataLength,
870 IN UINTN Timeout,
871 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
872 OUT UINT32 *TransferResult
873 )
874 {
875 USB_XHCI_INSTANCE *Xhc;
876 UINT8 Endpoint;
877 UINT8 Index;
878 UINT8 DescriptorType;
879 UINT8 SlotId;
880 UINT8 TTT;
881 UINT8 MTT;
882 UINT32 MaxPacket0;
883 EFI_USB_HUB_DESCRIPTOR *HubDesc;
884 EFI_TPL OldTpl;
885 EFI_STATUS Status;
886 UINTN MapSize;
887 EFI_USB_PORT_STATUS PortStatus;
888 UINT32 State;
889 EFI_USB_DEVICE_REQUEST ClearPortRequest;
890 UINTN Len;
891
892 //
893 // Validate parameters
894 //
895 if ((Request == NULL) || (TransferResult == NULL)) {
896 return EFI_INVALID_PARAMETER;
897 }
898
899 if ((TransferDirection != EfiUsbDataIn) &&
900 (TransferDirection != EfiUsbDataOut) &&
901 (TransferDirection != EfiUsbNoData))
902 {
903 return EFI_INVALID_PARAMETER;
904 }
905
906 if ((TransferDirection == EfiUsbNoData) &&
907 ((Data != NULL) || (*DataLength != 0)))
908 {
909 return EFI_INVALID_PARAMETER;
910 }
911
912 if ((TransferDirection != EfiUsbNoData) &&
913 ((Data == NULL) || (*DataLength == 0)))
914 {
915 return EFI_INVALID_PARAMETER;
916 }
917
918 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
919 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
920 (MaximumPacketLength != 512)
921 )
922 {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
927 return EFI_INVALID_PARAMETER;
928 }
929
930 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
931 return EFI_INVALID_PARAMETER;
932 }
933
934 OldTpl = gBS->RaiseTPL (XHC_TPL);
935
936 Xhc = XHC_FROM_THIS (This);
937
938 Status = EFI_DEVICE_ERROR;
939 *TransferResult = EFI_USB_ERR_SYSTEM;
940 Len = 0;
941
942 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
943 DEBUG ((DEBUG_ERROR, "XhcControlTransfer: HC halted at entrance\n"));
944 goto ON_EXIT;
945 }
946
947 //
948 // Check if the device is still enabled before every transaction.
949 //
950 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
951 if (SlotId == 0) {
952 goto ON_EXIT;
953 }
954
955 //
956 // Hook the Set_Address request from UsbBus.
957 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
958 //
959 if ((Request->Request == USB_REQ_SET_ADDRESS) &&
960 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))
961 {
962 //
963 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
964 // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer().
965 //
966 for (Index = 0; Index < 255; Index++) {
967 if (!Xhc->UsbDevContext[Index + 1].Enabled &&
968 (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
969 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value))
970 {
971 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
972 }
973 }
974
975 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
976 Status = EFI_DEVICE_ERROR;
977 goto ON_EXIT;
978 }
979
980 //
981 // The actual device address has been assigned by XHCI during initializing the device slot.
982 // So we just need establish the mapping relationship between the device address requested from UsbBus
983 // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface
984 // can find out the actual device address by it.
985 //
986 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value;
987 Status = EFI_SUCCESS;
988 goto ON_EXIT;
989 }
990
991 //
992 // Create a new URB, insert it into the asynchronous
993 // schedule list, then poll the execution status.
994 // Note that we encode the direction in address although default control
995 // endpoint is bidirectional. XhcCreateUrb expects this
996 // combination of Ep addr and its direction.
997 //
998 Endpoint = (UINT8)(0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
999 Status = XhcTransfer (
1000 Xhc,
1001 DeviceAddress,
1002 Endpoint,
1003 DeviceSpeed,
1004 MaximumPacketLength,
1005 XHC_CTRL_TRANSFER,
1006 Request,
1007 Data,
1008 DataLength,
1009 Timeout,
1010 TransferResult
1011 );
1012
1013 if (EFI_ERROR (Status)) {
1014 goto ON_EXIT;
1015 }
1016
1017 //
1018 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
1019 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
1020 // Hook Set_Config request from UsbBus as we need configure device endpoint.
1021 //
1022 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
1023 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
1024 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE)))))
1025 {
1026 DescriptorType = (UINT8)(Request->Value >> 8);
1027 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
1028 ASSERT (Data != NULL);
1029 //
1030 // Store a copy of device scriptor as hub device need this info to configure endpoint.
1031 //
1032 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
1033 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
1034 //
1035 // If it's a usb3.0 device, then its max packet size is a 2^n.
1036 //
1037 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
1038 } else {
1039 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
1040 }
1041
1042 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
1043 if (Xhc->HcCParams.Data.Csz == 0) {
1044 Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);
1045 } else {
1046 Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);
1047 }
1048 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
1049 ASSERT (Data != NULL);
1050 if (*DataLength == ((UINT16 *)Data)[1]) {
1051 //
1052 // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.
1053 //
1054 Index = (UINT8)Request->Value;
1055 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
1056 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
1057 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
1058 //
1059 // Default to use AlternateSetting 0 for all interfaces.
1060 //
1061 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8));
1062 }
1063 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
1064 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2))
1065 {
1066 ASSERT (Data != NULL);
1067 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;
1068 ASSERT (HubDesc->NumPorts <= 15);
1069 //
1070 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
1071 //
1072 TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
1073 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
1074 //
1075 // Don't support multi-TT feature for super speed hub now.
1076 //
1077 MTT = 0;
1078 DEBUG ((DEBUG_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
1079 } else {
1080 MTT = 0;
1081 }
1082
1083 if (Xhc->HcCParams.Data.Csz == 0) {
1084 Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
1085 } else {
1086 Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
1087 }
1088 }
1089 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
1090 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))
1091 {
1092 //
1093 // Hook Set_Config request from UsbBus as we need configure device endpoint.
1094 //
1095 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1096 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
1097 if (Xhc->HcCParams.Data.Csz == 0) {
1098 Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1099 } else {
1100 Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1101 }
1102
1103 break;
1104 }
1105 }
1106 } else if ((Request->Request == USB_REQ_SET_INTERFACE) &&
1107 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE)))
1108 {
1109 //
1110 // Hook Set_Interface request from UsbBus as we need configure interface setting.
1111 // Request->Value indicates AlterlateSetting to set
1112 // Request->Index indicates Interface to set
1113 //
1114 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8)Request->Index] != (UINT8)Request->Value) {
1115 if (Xhc->HcCParams.Data.Csz == 0) {
1116 Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
1117 } else {
1118 Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
1119 }
1120 }
1121 } else if ((Request->Request == USB_REQ_GET_STATUS) &&
1122 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)))
1123 {
1124 ASSERT (Data != NULL);
1125 //
1126 // Hook Get_Status request from UsbBus to keep track of the port status change.
1127 //
1128 State = *(UINT32 *)Data;
1129 PortStatus.PortStatus = 0;
1130 PortStatus.PortChangeStatus = 0;
1131
1132 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1133 //
1134 // For super speed hub, its bit10~12 presents the attached device speed.
1135 //
1136 if ((State & XHC_PORTSC_PS) >> 10 == 0) {
1137 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1138 }
1139 } else {
1140 //
1141 // For high or full/low speed hub, its bit9~10 presents the attached device speed.
1142 //
1143 if (XHC_BIT_IS_SET (State, BIT9)) {
1144 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
1145 } else if (XHC_BIT_IS_SET (State, BIT10)) {
1146 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1147 }
1148 }
1149
1150 //
1151 // Convert the XHCI port/port change state to UEFI status
1152 //
1153 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1154 for (Index = 0; Index < MapSize; Index++) {
1155 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
1156 PortStatus.PortStatus = (UINT16)(PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
1157 }
1158 }
1159
1160 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1161 for (Index = 0; Index < MapSize; Index++) {
1162 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
1163 PortStatus.PortChangeStatus = (UINT16)(PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
1164 }
1165 }
1166
1167 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
1168
1169 for (Index = 0; Index < MapSize; Index++) {
1170 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
1171 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
1172 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
1173 ClearPortRequest.Request = (UINT8)USB_REQ_CLEAR_FEATURE;
1174 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
1175 ClearPortRequest.Index = Request->Index;
1176 ClearPortRequest.Length = 0;
1177
1178 XhcControlTransfer (
1179 This,
1180 DeviceAddress,
1181 DeviceSpeed,
1182 MaximumPacketLength,
1183 &ClearPortRequest,
1184 EfiUsbNoData,
1185 NULL,
1186 &Len,
1187 Timeout,
1188 Translator,
1189 TransferResult
1190 );
1191 }
1192 }
1193
1194 XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
1195
1196 *(UINT32 *)Data = *(UINT32 *)&PortStatus;
1197 }
1198
1199 ON_EXIT:
1200 if (EFI_ERROR (Status)) {
1201 DEBUG ((DEBUG_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1202 }
1203
1204 gBS->RestoreTPL (OldTpl);
1205
1206 return Status;
1207 }
1208
1209 /**
1210 Submits bulk transfer to a bulk endpoint of a USB device.
1211
1212 @param This This EFI_USB2_HC_PROTOCOL instance.
1213 @param DeviceAddress Target device address.
1214 @param EndPointAddress Endpoint number and its direction in bit 7.
1215 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
1216 transfer.
1217 @param MaximumPacketLength Maximum packet size the endpoint is capable of
1218 sending or receiving.
1219 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1220 @param Data Array of pointers to the buffers of data to transmit
1221 from or receive into.
1222 @param DataLength The lenght of the data buffer.
1223 @param DataToggle On input, the initial data toggle for the transfer;
1224 On output, it is updated to to next data toggle to
1225 use of the subsequent bulk transfer.
1226 @param Timeout Indicates the maximum time, in millisecond, which
1227 the transfer is allowed to complete.
1228 @param Translator A pointr to the transaction translator data.
1229 @param TransferResult A pointer to the detailed result information of the
1230 bulk transfer.
1231
1232 @retval EFI_SUCCESS The transfer was completed successfully.
1233 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1234 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1235 @retval EFI_TIMEOUT The transfer failed due to timeout.
1236 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
1237
1238 **/
1239 EFI_STATUS
1240 EFIAPI
1241 XhcBulkTransfer (
1242 IN EFI_USB2_HC_PROTOCOL *This,
1243 IN UINT8 DeviceAddress,
1244 IN UINT8 EndPointAddress,
1245 IN UINT8 DeviceSpeed,
1246 IN UINTN MaximumPacketLength,
1247 IN UINT8 DataBuffersNumber,
1248 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
1249 IN OUT UINTN *DataLength,
1250 IN OUT UINT8 *DataToggle,
1251 IN UINTN Timeout,
1252 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1253 OUT UINT32 *TransferResult
1254 )
1255 {
1256 USB_XHCI_INSTANCE *Xhc;
1257 UINT8 SlotId;
1258 EFI_STATUS Status;
1259 EFI_TPL OldTpl;
1260 UINTN DebugErrorLevel;
1261
1262 //
1263 // Validate the parameters
1264 //
1265 if ((DataLength == NULL) || (*DataLength == 0) ||
1266 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))
1267 {
1268 return EFI_INVALID_PARAMETER;
1269 }
1270
1271 if ((*DataToggle != 0) && (*DataToggle != 1)) {
1272 return EFI_INVALID_PARAMETER;
1273 }
1274
1275 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1276 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1277 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) ||
1278 ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024)))
1279 {
1280 return EFI_INVALID_PARAMETER;
1281 }
1282
1283 OldTpl = gBS->RaiseTPL (XHC_TPL);
1284
1285 Xhc = XHC_FROM_THIS (This);
1286
1287 *TransferResult = EFI_USB_ERR_SYSTEM;
1288 Status = EFI_DEVICE_ERROR;
1289
1290 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1291 DEBUG ((DEBUG_ERROR, "XhcBulkTransfer: HC is halted\n"));
1292 goto ON_EXIT;
1293 }
1294
1295 //
1296 // Check if the device is still enabled before every transaction.
1297 //
1298 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1299 if (SlotId == 0) {
1300 goto ON_EXIT;
1301 }
1302
1303 //
1304 // Create a new URB, insert it into the asynchronous
1305 // schedule list, then poll the execution status.
1306 //
1307 Status = XhcTransfer (
1308 Xhc,
1309 DeviceAddress,
1310 EndPointAddress,
1311 DeviceSpeed,
1312 MaximumPacketLength,
1313 XHC_BULK_TRANSFER,
1314 NULL,
1315 Data[0],
1316 DataLength,
1317 Timeout,
1318 TransferResult
1319 );
1320
1321 ON_EXIT:
1322 if (EFI_ERROR (Status)) {
1323 if (Status == EFI_TIMEOUT) {
1324 DebugErrorLevel = DEBUG_VERBOSE;
1325 } else {
1326 DebugErrorLevel = DEBUG_ERROR;
1327 }
1328
1329 DEBUG ((DebugErrorLevel, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1330 }
1331
1332 gBS->RestoreTPL (OldTpl);
1333
1334 return Status;
1335 }
1336
1337 /**
1338 Submits an asynchronous interrupt transfer to an
1339 interrupt endpoint of a USB device.
1340
1341 @param This This EFI_USB2_HC_PROTOCOL instance.
1342 @param DeviceAddress Target device address.
1343 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1344 @param DeviceSpeed Indicates device speed.
1345 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1346 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
1347 transfer If FALSE, to remove the specified
1348 asynchronous interrupt.
1349 @param DataToggle On input, the initial data toggle to use; on output,
1350 it is updated to indicate the next data toggle.
1351 @param PollingInterval The he interval, in milliseconds, that the transfer
1352 is polled.
1353 @param DataLength The length of data to receive at the rate specified
1354 by PollingInterval.
1355 @param Translator Transaction translator to use.
1356 @param CallBackFunction Function to call at the rate specified by
1357 PollingInterval.
1358 @param Context Context to CallBackFunction.
1359
1360 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
1361 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1362 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
1363 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
1364
1365 **/
1366 EFI_STATUS
1367 EFIAPI
1368 XhcAsyncInterruptTransfer (
1369 IN EFI_USB2_HC_PROTOCOL *This,
1370 IN UINT8 DeviceAddress,
1371 IN UINT8 EndPointAddress,
1372 IN UINT8 DeviceSpeed,
1373 IN UINTN MaximumPacketLength,
1374 IN BOOLEAN IsNewTransfer,
1375 IN OUT UINT8 *DataToggle,
1376 IN UINTN PollingInterval,
1377 IN UINTN DataLength,
1378 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1379 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
1380 IN VOID *Context OPTIONAL
1381 )
1382 {
1383 USB_XHCI_INSTANCE *Xhc;
1384 URB *Urb;
1385 EFI_STATUS Status;
1386 UINT8 SlotId;
1387 UINT8 Index;
1388 EFI_TPL OldTpl;
1389
1390 //
1391 // Validate parameters
1392 //
1393 if (!XHCI_IS_DATAIN (EndPointAddress)) {
1394 return EFI_INVALID_PARAMETER;
1395 }
1396
1397 if (IsNewTransfer) {
1398 if (DataLength == 0) {
1399 return EFI_INVALID_PARAMETER;
1400 }
1401
1402 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1403 return EFI_INVALID_PARAMETER;
1404 }
1405
1406 if ((PollingInterval > 255) || (PollingInterval < 1)) {
1407 return EFI_INVALID_PARAMETER;
1408 }
1409 }
1410
1411 OldTpl = gBS->RaiseTPL (XHC_TPL);
1412
1413 Xhc = XHC_FROM_THIS (This);
1414
1415 //
1416 // Delete Async interrupt transfer request.
1417 //
1418 if (!IsNewTransfer) {
1419 //
1420 // The delete request may happen after device is detached.
1421 //
1422 for (Index = 0; Index < 255; Index++) {
1423 if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {
1424 break;
1425 }
1426 }
1427
1428 if (Index == 255) {
1429 Status = EFI_INVALID_PARAMETER;
1430 goto ON_EXIT;
1431 }
1432
1433 Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);
1434 DEBUG ((DEBUG_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));
1435 goto ON_EXIT;
1436 }
1437
1438 Status = EFI_SUCCESS;
1439
1440 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1441 DEBUG ((DEBUG_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));
1442 Status = EFI_DEVICE_ERROR;
1443 goto ON_EXIT;
1444 }
1445
1446 //
1447 // Check if the device is still enabled before every transaction.
1448 //
1449 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1450 if (SlotId == 0) {
1451 goto ON_EXIT;
1452 }
1453
1454 Urb = XhciInsertAsyncIntTransfer (
1455 Xhc,
1456 DeviceAddress,
1457 EndPointAddress,
1458 DeviceSpeed,
1459 MaximumPacketLength,
1460 DataLength,
1461 CallBackFunction,
1462 Context
1463 );
1464 if (Urb == NULL) {
1465 Status = EFI_OUT_OF_RESOURCES;
1466 goto ON_EXIT;
1467 }
1468
1469 //
1470 // Ring the doorbell
1471 //
1472 Status = RingIntTransferDoorBell (Xhc, Urb);
1473
1474 ON_EXIT:
1475 Xhc->PciIo->Flush (Xhc->PciIo);
1476 gBS->RestoreTPL (OldTpl);
1477
1478 return Status;
1479 }
1480
1481 /**
1482 Submits synchronous interrupt transfer to an interrupt endpoint
1483 of a USB device.
1484
1485 @param This This EFI_USB2_HC_PROTOCOL instance.
1486 @param DeviceAddress Target device address.
1487 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1488 @param DeviceSpeed Indicates device speed.
1489 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1490 of sending or receiving.
1491 @param Data Buffer of data that will be transmitted to USB
1492 device or received from USB device.
1493 @param DataLength On input, the size, in bytes, of the data buffer; On
1494 output, the number of bytes transferred.
1495 @param DataToggle On input, the initial data toggle to use; on output,
1496 it is updated to indicate the next data toggle.
1497 @param Timeout Maximum time, in second, to complete.
1498 @param Translator Transaction translator to use.
1499 @param TransferResult Variable to receive the transfer result.
1500
1501 @return EFI_SUCCESS The transfer was completed successfully.
1502 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1503 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1504 @return EFI_TIMEOUT The transfer failed due to timeout.
1505 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1506
1507 **/
1508 EFI_STATUS
1509 EFIAPI
1510 XhcSyncInterruptTransfer (
1511 IN EFI_USB2_HC_PROTOCOL *This,
1512 IN UINT8 DeviceAddress,
1513 IN UINT8 EndPointAddress,
1514 IN UINT8 DeviceSpeed,
1515 IN UINTN MaximumPacketLength,
1516 IN OUT VOID *Data,
1517 IN OUT UINTN *DataLength,
1518 IN OUT UINT8 *DataToggle,
1519 IN UINTN Timeout,
1520 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1521 OUT UINT32 *TransferResult
1522 )
1523 {
1524 USB_XHCI_INSTANCE *Xhc;
1525 UINT8 SlotId;
1526 EFI_STATUS Status;
1527 EFI_TPL OldTpl;
1528
1529 //
1530 // Validates parameters
1531 //
1532 if ((DataLength == NULL) || (*DataLength == 0) ||
1533 (Data == NULL) || (TransferResult == NULL))
1534 {
1535 return EFI_INVALID_PARAMETER;
1536 }
1537
1538 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1539 return EFI_INVALID_PARAMETER;
1540 }
1541
1542 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
1543 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1544 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072)))
1545 {
1546 return EFI_INVALID_PARAMETER;
1547 }
1548
1549 OldTpl = gBS->RaiseTPL (XHC_TPL);
1550
1551 Xhc = XHC_FROM_THIS (This);
1552
1553 *TransferResult = EFI_USB_ERR_SYSTEM;
1554 Status = EFI_DEVICE_ERROR;
1555
1556 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1557 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
1558 goto ON_EXIT;
1559 }
1560
1561 //
1562 // Check if the device is still enabled before every transaction.
1563 //
1564 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1565 if (SlotId == 0) {
1566 goto ON_EXIT;
1567 }
1568
1569 Status = XhcTransfer (
1570 Xhc,
1571 DeviceAddress,
1572 EndPointAddress,
1573 DeviceSpeed,
1574 MaximumPacketLength,
1575 XHC_INT_TRANSFER_SYNC,
1576 NULL,
1577 Data,
1578 DataLength,
1579 Timeout,
1580 TransferResult
1581 );
1582
1583 ON_EXIT:
1584 if (EFI_ERROR (Status)) {
1585 DEBUG ((DEBUG_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1586 }
1587
1588 gBS->RestoreTPL (OldTpl);
1589
1590 return Status;
1591 }
1592
1593 /**
1594 Submits isochronous transfer to a target USB device.
1595
1596 @param This This EFI_USB2_HC_PROTOCOL instance.
1597 @param DeviceAddress Target device address.
1598 @param EndPointAddress End point address with its direction.
1599 @param DeviceSpeed Device speed, Low speed device doesn't support this
1600 type.
1601 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1602 sending or receiving.
1603 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1604 @param Data Array of pointers to the buffers of data that will
1605 be transmitted to USB device or received from USB
1606 device.
1607 @param DataLength The size, in bytes, of the data buffer.
1608 @param Translator Transaction translator to use.
1609 @param TransferResult Variable to receive the transfer result.
1610
1611 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1612
1613 **/
1614 EFI_STATUS
1615 EFIAPI
1616 XhcIsochronousTransfer (
1617 IN EFI_USB2_HC_PROTOCOL *This,
1618 IN UINT8 DeviceAddress,
1619 IN UINT8 EndPointAddress,
1620 IN UINT8 DeviceSpeed,
1621 IN UINTN MaximumPacketLength,
1622 IN UINT8 DataBuffersNumber,
1623 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1624 IN UINTN DataLength,
1625 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1626 OUT UINT32 *TransferResult
1627 )
1628 {
1629 return EFI_UNSUPPORTED;
1630 }
1631
1632 /**
1633 Submits Async isochronous transfer to a target USB device.
1634
1635 @param This This EFI_USB2_HC_PROTOCOL instance.
1636 @param DeviceAddress Target device address.
1637 @param EndPointAddress End point address with its direction.
1638 @param DeviceSpeed Device speed, Low speed device doesn't support this
1639 type.
1640 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1641 sending or receiving.
1642 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1643 @param Data Array of pointers to the buffers of data that will
1644 be transmitted to USB device or received from USB
1645 device.
1646 @param DataLength The size, in bytes, of the data buffer.
1647 @param Translator Transaction translator to use.
1648 @param IsochronousCallBack Function to be called when the transfer complete.
1649 @param Context Context passed to the call back function as
1650 parameter.
1651
1652 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1653
1654 **/
1655 EFI_STATUS
1656 EFIAPI
1657 XhcAsyncIsochronousTransfer (
1658 IN EFI_USB2_HC_PROTOCOL *This,
1659 IN UINT8 DeviceAddress,
1660 IN UINT8 EndPointAddress,
1661 IN UINT8 DeviceSpeed,
1662 IN UINTN MaximumPacketLength,
1663 IN UINT8 DataBuffersNumber,
1664 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1665 IN UINTN DataLength,
1666 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1667 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1668 IN VOID *Context
1669 )
1670 {
1671 return EFI_UNSUPPORTED;
1672 }
1673
1674 /**
1675 Entry point for EFI drivers.
1676
1677 @param ImageHandle EFI_HANDLE.
1678 @param SystemTable EFI_SYSTEM_TABLE.
1679
1680 @retval EFI_SUCCESS Success.
1681 @retval Others Fail.
1682
1683 **/
1684 EFI_STATUS
1685 EFIAPI
1686 XhcDriverEntryPoint (
1687 IN EFI_HANDLE ImageHandle,
1688 IN EFI_SYSTEM_TABLE *SystemTable
1689 )
1690 {
1691 return EfiLibInstallDriverBindingComponentName2 (
1692 ImageHandle,
1693 SystemTable,
1694 &gXhciDriverBinding,
1695 ImageHandle,
1696 &gXhciComponentName,
1697 &gXhciComponentName2
1698 );
1699 }
1700
1701 /**
1702 Test to see if this driver supports ControllerHandle. Any
1703 ControllerHandle that has Usb2HcProtocol installed will
1704 be supported.
1705
1706 @param This Protocol instance pointer.
1707 @param Controller Handle of device to test.
1708 @param RemainingDevicePath Not used.
1709
1710 @return EFI_SUCCESS This driver supports this device.
1711 @return EFI_UNSUPPORTED This driver does not support this device.
1712
1713 **/
1714 EFI_STATUS
1715 EFIAPI
1716 XhcDriverBindingSupported (
1717 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1718 IN EFI_HANDLE Controller,
1719 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1720 )
1721 {
1722 EFI_STATUS Status;
1723 EFI_PCI_IO_PROTOCOL *PciIo;
1724 USB_CLASSC UsbClassCReg;
1725
1726 //
1727 // Test whether there is PCI IO Protocol attached on the controller handle.
1728 //
1729 Status = gBS->OpenProtocol (
1730 Controller,
1731 &gEfiPciIoProtocolGuid,
1732 (VOID **)&PciIo,
1733 This->DriverBindingHandle,
1734 Controller,
1735 EFI_OPEN_PROTOCOL_BY_DRIVER
1736 );
1737
1738 if (EFI_ERROR (Status)) {
1739 return EFI_UNSUPPORTED;
1740 }
1741
1742 Status = PciIo->Pci.Read (
1743 PciIo,
1744 EfiPciIoWidthUint8,
1745 PCI_CLASSCODE_OFFSET,
1746 sizeof (USB_CLASSC) / sizeof (UINT8),
1747 &UsbClassCReg
1748 );
1749
1750 if (EFI_ERROR (Status)) {
1751 Status = EFI_UNSUPPORTED;
1752 goto ON_EXIT;
1753 }
1754
1755 //
1756 // Test whether the controller belongs to Xhci type
1757 //
1758 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1759 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1760 (UsbClassCReg.ProgInterface != PCI_IF_XHCI))
1761 {
1762 Status = EFI_UNSUPPORTED;
1763 }
1764
1765 ON_EXIT:
1766 gBS->CloseProtocol (
1767 Controller,
1768 &gEfiPciIoProtocolGuid,
1769 This->DriverBindingHandle,
1770 Controller
1771 );
1772
1773 return Status;
1774 }
1775
1776 /**
1777 Create and initialize a USB_XHCI_INSTANCE structure.
1778
1779 @param PciIo The PciIo on this device.
1780 @param DevicePath The device path of host controller.
1781 @param OriginalPciAttributes Original PCI attributes.
1782
1783 @return The allocated and initialized USB_XHCI_INSTANCE structure if created,
1784 otherwise NULL.
1785
1786 **/
1787 USB_XHCI_INSTANCE *
1788 XhcCreateUsbHc (
1789 IN EFI_PCI_IO_PROTOCOL *PciIo,
1790 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1791 IN UINT64 OriginalPciAttributes
1792 )
1793 {
1794 USB_XHCI_INSTANCE *Xhc;
1795 EFI_STATUS Status;
1796 UINT32 PageSize;
1797 UINT16 ExtCapReg;
1798 UINT8 ReleaseNumber;
1799
1800 Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));
1801
1802 if (Xhc == NULL) {
1803 return NULL;
1804 }
1805
1806 //
1807 // Initialize private data structure
1808 //
1809 Xhc->Signature = XHCI_INSTANCE_SIG;
1810 Xhc->PciIo = PciIo;
1811 Xhc->DevicePath = DevicePath;
1812 Xhc->OriginalPciAttributes = OriginalPciAttributes;
1813 CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));
1814
1815 Status = PciIo->Pci.Read (
1816 PciIo,
1817 EfiPciIoWidthUint8,
1818 XHC_PCI_SBRN_OFFSET,
1819 1,
1820 &ReleaseNumber
1821 );
1822
1823 if (!EFI_ERROR (Status)) {
1824 Xhc->Usb2Hc.MajorRevision = (ReleaseNumber & 0xF0) >> 4;
1825 Xhc->Usb2Hc.MinorRevision = (ReleaseNumber & 0x0F);
1826 }
1827
1828 InitializeListHead (&Xhc->AsyncIntTransfers);
1829
1830 //
1831 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align
1832 //
1833 Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);
1834 Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);
1835 Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);
1836 Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);
1837 Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);
1838 Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);
1839
1840 //
1841 // This PageSize field defines the page size supported by the xHC implementation.
1842 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1843 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1844 //
1845 PageSize = XhcReadOpReg (Xhc, XHC_PAGESIZE_OFFSET);
1846 if ((PageSize & (~XHC_PAGESIZE_MASK)) != 0) {
1847 DEBUG ((DEBUG_ERROR, "XhcCreateUsb3Hc: Reserved bits are not 0 for PageSize\n"));
1848 goto ON_ERROR;
1849 }
1850
1851 PageSize &= XHC_PAGESIZE_MASK;
1852 Xhc->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
1853
1854 ExtCapReg = (UINT16)(Xhc->HcCParams.Data.ExtCapReg);
1855 Xhc->ExtCapRegBase = ExtCapReg << 2;
1856 Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);
1857 Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);
1858 Xhc->Usb2SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB2);
1859 Xhc->Usb3SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB3);
1860
1861 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));
1862 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));
1863 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));
1864 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));
1865 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));
1866 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));
1867 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));
1868 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));
1869 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb2SupOffset 0x%x\n", Xhc->Usb2SupOffset));
1870 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb3SupOffset 0x%x\n", Xhc->Usb3SupOffset));
1871
1872 //
1873 // Create AsyncRequest Polling Timer
1874 //
1875 Status = gBS->CreateEvent (
1876 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1877 TPL_NOTIFY,
1878 XhcMonitorAsyncRequests,
1879 Xhc,
1880 &Xhc->PollTimer
1881 );
1882
1883 if (EFI_ERROR (Status)) {
1884 goto ON_ERROR;
1885 }
1886
1887 return Xhc;
1888
1889 ON_ERROR:
1890 FreePool (Xhc);
1891 return NULL;
1892 }
1893
1894 /**
1895 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1896
1897 @param Event Pointer to this event
1898 @param Context Event handler private data
1899
1900 **/
1901 VOID
1902 EFIAPI
1903 XhcExitBootService (
1904 EFI_EVENT Event,
1905 VOID *Context
1906 )
1907
1908 {
1909 USB_XHCI_INSTANCE *Xhc;
1910 EFI_PCI_IO_PROTOCOL *PciIo;
1911
1912 Xhc = (USB_XHCI_INSTANCE *)Context;
1913 PciIo = Xhc->PciIo;
1914
1915 //
1916 // Stop AsyncRequest Polling timer then stop the XHCI driver
1917 // and uninstall the XHCI protocl.
1918 //
1919 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
1920 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
1921
1922 if (Xhc->PollTimer != NULL) {
1923 gBS->CloseEvent (Xhc->PollTimer);
1924 }
1925
1926 XhcClearBiosOwnership (Xhc);
1927
1928 //
1929 // Restore original PCI attributes
1930 //
1931 PciIo->Attributes (
1932 PciIo,
1933 EfiPciIoAttributeOperationSet,
1934 Xhc->OriginalPciAttributes,
1935 NULL
1936 );
1937 }
1938
1939 /**
1940 Starting the Usb XHCI Driver.
1941
1942 @param This Protocol instance pointer.
1943 @param Controller Handle of device to test.
1944 @param RemainingDevicePath Not used.
1945
1946 @return EFI_SUCCESS supports this device.
1947 @return EFI_UNSUPPORTED do not support this device.
1948 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1949 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1950
1951 **/
1952 EFI_STATUS
1953 EFIAPI
1954 XhcDriverBindingStart (
1955 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1956 IN EFI_HANDLE Controller,
1957 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1958 )
1959 {
1960 EFI_STATUS Status;
1961 EFI_PCI_IO_PROTOCOL *PciIo;
1962 UINT64 Supports;
1963 UINT64 OriginalPciAttributes;
1964 BOOLEAN PciAttributesSaved;
1965 USB_XHCI_INSTANCE *Xhc;
1966 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
1967
1968 //
1969 // Open the PciIo Protocol, then enable the USB host controller
1970 //
1971 Status = gBS->OpenProtocol (
1972 Controller,
1973 &gEfiPciIoProtocolGuid,
1974 (VOID **)&PciIo,
1975 This->DriverBindingHandle,
1976 Controller,
1977 EFI_OPEN_PROTOCOL_BY_DRIVER
1978 );
1979
1980 if (EFI_ERROR (Status)) {
1981 return Status;
1982 }
1983
1984 //
1985 // Open Device Path Protocol for on USB host controller
1986 //
1987 HcDevicePath = NULL;
1988 Status = gBS->OpenProtocol (
1989 Controller,
1990 &gEfiDevicePathProtocolGuid,
1991 (VOID **)&HcDevicePath,
1992 This->DriverBindingHandle,
1993 Controller,
1994 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1995 );
1996
1997 PciAttributesSaved = FALSE;
1998 //
1999 // Save original PCI attributes
2000 //
2001 Status = PciIo->Attributes (
2002 PciIo,
2003 EfiPciIoAttributeOperationGet,
2004 0,
2005 &OriginalPciAttributes
2006 );
2007
2008 if (EFI_ERROR (Status)) {
2009 goto CLOSE_PCIIO;
2010 }
2011
2012 PciAttributesSaved = TRUE;
2013
2014 Status = PciIo->Attributes (
2015 PciIo,
2016 EfiPciIoAttributeOperationSupported,
2017 0,
2018 &Supports
2019 );
2020 if (!EFI_ERROR (Status)) {
2021 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
2022 Status = PciIo->Attributes (
2023 PciIo,
2024 EfiPciIoAttributeOperationEnable,
2025 Supports,
2026 NULL
2027 );
2028 }
2029
2030 if (EFI_ERROR (Status)) {
2031 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));
2032 goto CLOSE_PCIIO;
2033 }
2034
2035 //
2036 // Create then install USB2_HC_PROTOCOL
2037 //
2038 Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);
2039
2040 if (Xhc == NULL) {
2041 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));
2042 return EFI_OUT_OF_RESOURCES;
2043 }
2044
2045 //
2046 // Enable 64-bit DMA support in the PCI layer if this controller
2047 // supports it.
2048 //
2049 if (Xhc->HcCParams.Data.Ac64 != 0) {
2050 Status = PciIo->Attributes (
2051 PciIo,
2052 EfiPciIoAttributeOperationEnable,
2053 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
2054 NULL
2055 );
2056 if (!EFI_ERROR (Status)) {
2057 Xhc->Support64BitDma = TRUE;
2058 } else {
2059 DEBUG ((
2060 DEBUG_WARN,
2061 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
2062 __FUNCTION__,
2063 Controller,
2064 Status
2065 ));
2066 }
2067 }
2068
2069 XhcSetBiosOwnership (Xhc);
2070
2071 XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
2072 ASSERT (XhcIsHalt (Xhc));
2073
2074 //
2075 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag
2076 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.
2077 //
2078 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
2079
2080 //
2081 // Initialize the schedule
2082 //
2083 XhcInitSched (Xhc);
2084
2085 //
2086 // Start the Host Controller
2087 //
2088 XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
2089
2090 //
2091 // Start the asynchronous interrupt monitor
2092 //
2093 Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);
2094 if (EFI_ERROR (Status)) {
2095 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));
2096 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
2097 goto FREE_POOL;
2098 }
2099
2100 //
2101 // Create event to stop the HC when exit boot service.
2102 //
2103 Status = gBS->CreateEventEx (
2104 EVT_NOTIFY_SIGNAL,
2105 TPL_NOTIFY,
2106 XhcExitBootService,
2107 Xhc,
2108 &gEfiEventExitBootServicesGuid,
2109 &Xhc->ExitBootServiceEvent
2110 );
2111 if (EFI_ERROR (Status)) {
2112 goto FREE_POOL;
2113 }
2114
2115 //
2116 // Install the component name protocol, don't fail the start
2117 // because of something for display.
2118 //
2119 AddUnicodeString2 (
2120 "eng",
2121 gXhciComponentName.SupportedLanguages,
2122 &Xhc->ControllerNameTable,
2123 L"eXtensible Host Controller (USB 3.0)",
2124 TRUE
2125 );
2126 AddUnicodeString2 (
2127 "en",
2128 gXhciComponentName2.SupportedLanguages,
2129 &Xhc->ControllerNameTable,
2130 L"eXtensible Host Controller (USB 3.0)",
2131 FALSE
2132 );
2133
2134 Status = gBS->InstallProtocolInterface (
2135 &Controller,
2136 &gEfiUsb2HcProtocolGuid,
2137 EFI_NATIVE_INTERFACE,
2138 &Xhc->Usb2Hc
2139 );
2140 if (EFI_ERROR (Status)) {
2141 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
2142 goto FREE_POOL;
2143 }
2144
2145 DEBUG ((DEBUG_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));
2146 return EFI_SUCCESS;
2147
2148 FREE_POOL:
2149 gBS->CloseEvent (Xhc->PollTimer);
2150 XhcFreeSched (Xhc);
2151 FreePool (Xhc);
2152
2153 CLOSE_PCIIO:
2154 if (PciAttributesSaved) {
2155 //
2156 // Restore original PCI attributes
2157 //
2158 PciIo->Attributes (
2159 PciIo,
2160 EfiPciIoAttributeOperationSet,
2161 OriginalPciAttributes,
2162 NULL
2163 );
2164 }
2165
2166 gBS->CloseProtocol (
2167 Controller,
2168 &gEfiPciIoProtocolGuid,
2169 This->DriverBindingHandle,
2170 Controller
2171 );
2172
2173 return Status;
2174 }
2175
2176 /**
2177 Stop this driver on ControllerHandle. Support stopping any child handles
2178 created by this driver.
2179
2180 @param This Protocol instance pointer.
2181 @param Controller Handle of device to stop driver on.
2182 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
2183 @param ChildHandleBuffer List of handles for the children we need to stop.
2184
2185 @return EFI_SUCCESS Success.
2186 @return EFI_DEVICE_ERROR Fail.
2187
2188 **/
2189 EFI_STATUS
2190 EFIAPI
2191 XhcDriverBindingStop (
2192 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2193 IN EFI_HANDLE Controller,
2194 IN UINTN NumberOfChildren,
2195 IN EFI_HANDLE *ChildHandleBuffer
2196 )
2197 {
2198 EFI_STATUS Status;
2199 EFI_USB2_HC_PROTOCOL *Usb2Hc;
2200 EFI_PCI_IO_PROTOCOL *PciIo;
2201 USB_XHCI_INSTANCE *Xhc;
2202 UINT8 Index;
2203
2204 //
2205 // Test whether the Controller handler passed in is a valid
2206 // Usb controller handle that should be supported, if not,
2207 // return the error status directly
2208 //
2209 Status = gBS->OpenProtocol (
2210 Controller,
2211 &gEfiUsb2HcProtocolGuid,
2212 (VOID **)&Usb2Hc,
2213 This->DriverBindingHandle,
2214 Controller,
2215 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2216 );
2217
2218 if (EFI_ERROR (Status)) {
2219 return Status;
2220 }
2221
2222 Status = gBS->UninstallProtocolInterface (
2223 Controller,
2224 &gEfiUsb2HcProtocolGuid,
2225 Usb2Hc
2226 );
2227
2228 if (EFI_ERROR (Status)) {
2229 return Status;
2230 }
2231
2232 Xhc = XHC_FROM_THIS (Usb2Hc);
2233 PciIo = Xhc->PciIo;
2234
2235 //
2236 // Stop AsyncRequest Polling timer then stop the XHCI driver
2237 // and uninstall the XHCI protocl.
2238 //
2239 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
2240
2241 //
2242 // Disable the device slots occupied by these devices on its downstream ports.
2243 // Entry 0 is reserved.
2244 //
2245 for (Index = 0; Index < 255; Index++) {
2246 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2247 (Xhc->UsbDevContext[Index + 1].SlotId == 0))
2248 {
2249 continue;
2250 }
2251
2252 if (Xhc->HcCParams.Data.Csz == 0) {
2253 XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2254 } else {
2255 XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2256 }
2257 }
2258
2259 if (Xhc->PollTimer != NULL) {
2260 gBS->CloseEvent (Xhc->PollTimer);
2261 }
2262
2263 if (Xhc->ExitBootServiceEvent != NULL) {
2264 gBS->CloseEvent (Xhc->ExitBootServiceEvent);
2265 }
2266
2267 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
2268 XhcClearBiosOwnership (Xhc);
2269 XhciDelAllAsyncIntTransfers (Xhc);
2270 XhcFreeSched (Xhc);
2271
2272 if (Xhc->ControllerNameTable) {
2273 FreeUnicodeStringTable (Xhc->ControllerNameTable);
2274 }
2275
2276 //
2277 // Restore original PCI attributes
2278 //
2279 PciIo->Attributes (
2280 PciIo,
2281 EfiPciIoAttributeOperationSet,
2282 Xhc->OriginalPciAttributes,
2283 NULL
2284 );
2285
2286 gBS->CloseProtocol (
2287 Controller,
2288 &gEfiPciIoProtocolGuid,
2289 This->DriverBindingHandle,
2290 Controller
2291 );
2292
2293 FreePool (Xhc);
2294
2295 return EFI_SUCCESS;
2296 }