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