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