]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
MdeModulePkg/Bus: Fix typos in comments
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / Xhci.c
index 0c08301e9ba4b92b3ad8a9ac1fbfafecdd37c3e5..2f6137ef570decf69256bb3809653c70d4cca0b0 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The XHCI controller driver.\r
 \r
-Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -32,6 +32,35 @@ USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
   {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
 };\r
 \r
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {\r
+  {XHC_PORTSC_CSC, EfiUsbPortConnectChange},\r
+  {XHC_PORTSC_PEC, EfiUsbPortEnableChange},\r
+  {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+  {XHC_PORTSC_PRC, EfiUsbPortResetChange}\r
+};\r
+\r
+USB_PORT_STATE_MAP  mUsbHubPortStateMap[] = {\r
+  {XHC_HUB_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},\r
+  {XHC_HUB_PORTSC_PED,   USB_PORT_STAT_ENABLE},\r
+  {XHC_HUB_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},\r
+  {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}\r
+};\r
+\r
+USB_PORT_STATE_MAP  mUsbHubPortChangeMap[] = {\r
+  {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
+  {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
+  {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
+  {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
+};\r
+\r
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {\r
+  {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},\r
+  {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},\r
+  {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+  {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},\r
+  {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}\r
+};\r
+\r
 EFI_DRIVER_BINDING_PROTOCOL  gXhciDriverBinding = {\r
   XhcDriverBindingSupported,\r
   XhcDriverBindingStart,\r
@@ -96,7 +125,7 @@ XhcGetCapability (
   Xhc             = XHC_FROM_THIS (This);\r
   *MaxSpeed       = EFI_USB_SPEED_SUPER;\r
   *PortNumber     = (UINT8) (Xhc->HcSParams1.Data.MaxPorts);\r
-  *Is64BitCapable = (UINT8) (Xhc->HcCParams.Data.Ac64);\r
+  *Is64BitCapable = (UINT8) Xhc->Support64BitDma;\r
   DEBUG ((EFI_D_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
 \r
   gBS->RestoreTPL (OldTpl);\r
@@ -129,9 +158,20 @@ XhcReset (
   EFI_STATUS         Status;\r
   EFI_TPL            OldTpl;\r
 \r
-  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+  Xhc = XHC_FROM_THIS (This);\r
+  \r
+  if (Xhc->DevicePath != NULL) {\r
+    //\r
+    // Report Status Code to indicate reset happens\r
+    //\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_PROGRESS_CODE,\r
+      (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),\r
+      Xhc->DevicePath\r
+      );\r
+  }  \r
 \r
-  Xhc    = XHC_FROM_THIS (This);\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
 \r
   switch (Attributes) {\r
   case EFI_USB_HC_RESET_GLOBAL:\r
@@ -139,6 +179,11 @@ XhcReset (
   // Flow through, same behavior as Host Controller Reset\r
   //\r
   case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
+    if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) &&\r
+        ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0)) {\r
+      Status = EFI_SUCCESS;\r
+      goto ON_EXIT;\r
+    }\r
     //\r
     // Host Controller must be Halt when Reset it\r
     //\r
@@ -402,6 +447,14 @@ XhcGetRootHubPortStatus (
     }\r
   }\r
 \r
+  MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+  for (Index = 0; Index < MapSize; Index++) {\r
+    if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {\r
+      XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);\r
+    }\r
+  }\r
+\r
   //\r
   // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
   // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
@@ -439,8 +492,6 @@ XhcSetRootHubPortFeature (
   UINT32                  Offset;\r
   UINT32                  State;\r
   UINT32                  TotalPort;\r
-  UINT8                   SlotId;\r
-  USB_DEV_ROUTE           RouteChart;\r
   EFI_STATUS              Status;\r
   EFI_TPL                 OldTpl;\r
 \r
@@ -496,24 +547,13 @@ XhcSetRootHubPortFeature (
       }\r
     }\r
 \r
-    RouteChart.Route.RouteString = 0;\r
-    RouteChart.Route.RootPortNum = PortNumber + 1;\r
-    RouteChart.Route.TierNum     = 1;\r
     //\r
-    // If the port reset operation happens after the usb super speed device is enabled,\r
-    // The subsequent configuration, such as getting device descriptor, will fail.\r
-    // So here a workaround is introduced to skip the reset operation if the device is enabled.\r
+    // 4.3.1 Resetting a Root Hub Port\r
+    // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
     //\r
-    SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
-    if (SlotId == 0) {\r
-      //\r
-      // 4.3.1 Resetting a Root Hub Port\r
-      // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
-      //\r
-      State |= XHC_PORTSC_RESET;\r
-      XhcWriteOpReg (Xhc, Offset, State);\r
-      XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
-    }\r
+    State |= XHC_PORTSC_RESET;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
     break;\r
 \r
   case EfiUsbPortPower:\r
@@ -733,6 +773,8 @@ XhcControlTransfer (
   UINTN                   MapSize;\r
   EFI_USB_PORT_STATUS     PortStatus;\r
   UINT32                  State;\r
+  EFI_USB_DEVICE_REQUEST  ClearPortRequest;\r
+  UINTN                   Len;\r
 \r
   //\r
   // Validate parameters\r
@@ -778,6 +820,7 @@ XhcControlTransfer (
 \r
   Status          = EFI_DEVICE_ERROR;\r
   *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Len             = 0;\r
 \r
   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
     DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n"));\r
@@ -809,6 +852,11 @@ XhcControlTransfer (
         Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;\r
       }\r
     }\r
+\r
+    if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto ON_EXIT;\r
+    }\r
     //\r
     // The actual device address has been assigned by XHCI during initializing the device slot.\r
     // So we just need establish the mapping relationship between the device address requested from UsbBus\r
@@ -819,20 +867,6 @@ XhcControlTransfer (
     Status = EFI_SUCCESS;\r
     goto ON_EXIT;\r
   }\r
-  \r
-  //\r
-  // If the port reset operation happens after the usb super speed device is enabled,\r
-  // The subsequent configuration, such as getting device descriptor, will fail.\r
-  // So here a workaround is introduced to skip the reset operation if the device is enabled.\r
-  //\r
-  if ((Request->Request     == USB_REQ_SET_FEATURE) &&\r
-      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)) &&\r
-      (Request->Value       == EfiUsbPortReset)) {\r
-    if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
-      Status = EFI_SUCCESS;\r
-      goto ON_EXIT;\r
-    }\r
-  }\r
 \r
   //\r
   // Create a new URB, insert it into the asynchronous\r
@@ -861,7 +895,7 @@ XhcControlTransfer (
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ON_EXIT;\r
   }\r
-  ASSERT (Urb->EvtRing == &Xhc->EventRing);\r
+\r
   Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
 \r
   //\r
@@ -871,15 +905,39 @@ XhcControlTransfer (
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
-    ASSERT_EFI_ERROR (RecoveryStatus);\r
-    Status = EFI_DEVICE_ERROR;\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcControlTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
+    }\r
     goto FREE_URB;\r
   } else {\r
-    goto FREE_URB;\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto FREE_URB;\r
+    } else {\r
+      goto FREE_URB;\r
+    }\r
+  }\r
+\r
+  Xhc->PciIo->Flush (Xhc->PciIo);\r
+  \r
+  if (Urb->DataMap != NULL) {\r
+    Status = Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);\r
+    ASSERT_EFI_ERROR (Status);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto FREE_URB;\r
+    }  \r
   }\r
 \r
   //\r
@@ -891,13 +949,13 @@ XhcControlTransfer (
       ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) || \r
       ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {\r
     DescriptorType = (UINT8)(Request->Value >> 8);\r
-    if ((DescriptorType == USB_DESC_TYPE_DEVICE) && (*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR))) {\r
+    if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
         ASSERT (Data != NULL);\r
         //\r
         // Store a copy of device scriptor as hub device need this info to configure endpoint.\r
         //\r
         CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
-        if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {\r
+        if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {\r
           //\r
           // If it's a usb3.0 device, then its max packet size is a 2^n.\r
           //\r
@@ -907,11 +965,10 @@ XhcControlTransfer (
         }\r
         Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
         if (Xhc->HcCParams.Data.Csz == 0) {\r
-          Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);\r\r
+          Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);\r
         } else {\r
-          Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r\r
+          Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r
         }\r
-        ASSERT_EFI_ERROR (Status);\r
     } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {\r
       ASSERT (Data != NULL);\r
       if (*DataLength == ((UINT16 *)Data)[1]) {\r
@@ -922,6 +979,10 @@ XhcControlTransfer (
         ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
         Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool(*DataLength);\r
         CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
+        //\r
+        // Default to use AlternateSetting 0 for all interfaces.\r
+        //\r
+        Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8));\r
       }\r
     } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
                (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {\r
@@ -947,7 +1008,6 @@ XhcControlTransfer (
       } else {\r
         Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
       }\r
-      ASSERT_EFI_ERROR (Status);\r
     }\r
   } else if ((Request->Request     == USB_REQ_SET_CONFIG) &&\r
              (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
@@ -961,10 +1021,23 @@ XhcControlTransfer (
         } else {\r
           Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
         }\r
-        ASSERT_EFI_ERROR (Status);\r
         break;\r
       }\r
     }\r
+  } else if ((Request->Request     == USB_REQ_SET_INTERFACE) &&\r
+             (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE))) {\r
+    //\r
+    // Hook Set_Interface request from UsbBus as we need configure interface setting.\r
+    // Request->Value indicates AlterlateSetting to set\r
+    // Request->Index indicates Interface to set\r
+    //\r
+    if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] != (UINT8) Request->Value) {\r
+      if (Xhc->HcCParams.Data.Csz == 0) {\r
+        Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);\r
+      } else {\r
+        Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);\r
+      }\r
+    }\r
   } else if ((Request->Request     == USB_REQ_GET_STATUS) &&\r
              (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {\r
     ASSERT (Data != NULL);\r
@@ -982,37 +1055,64 @@ XhcControlTransfer (
       if ((State & XHC_PORTSC_PS) >> 10 == 0) {\r
         PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
       }\r
-    } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+    } else {\r
       //\r
-      // For high speed hub, its bit9~10 presents the attached device speed.\r
+      // For high or full/low speed hub, its bit9~10 presents the attached device speed.\r
       //\r
       if (XHC_BIT_IS_SET (State, BIT9)) {\r
         PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
       } else if (XHC_BIT_IS_SET (State, BIT10)) {\r
         PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
       }\r
-    } else {\r
-      ASSERT (0);\r
     }\r
 \r
     //\r
     // Convert the XHCI port/port change state to UEFI status\r
     //\r
-    MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+    MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
     for (Index = 0; Index < MapSize; Index++) {\r
-      if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
-        PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbPortStateMap[Index].UefiState);\r
+      if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {\r
+        PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);\r
       }\r
     }\r
-    MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
 \r
+    MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
     for (Index = 0; Index < MapSize; Index++) {\r
-      if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
-      PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+      if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {\r
+        PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);\r
+      }\r
+    }\r
+\r
+    MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+    for (Index = 0; Index < MapSize; Index++) {\r
+      if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {\r
+        ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+        ClearPortRequest.RequestType  = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);\r
+        ClearPortRequest.Request      = (UINT8) USB_REQ_CLEAR_FEATURE;\r
+        ClearPortRequest.Value        = mUsbHubClearPortChangeMap[Index].Selector;\r
+        ClearPortRequest.Index        = Request->Index;\r
+        ClearPortRequest.Length       = 0;\r
+\r
+        XhcControlTransfer (\r
+          This, \r
+          DeviceAddress,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          &ClearPortRequest,\r
+          EfiUsbNoData,\r
+          NULL,\r
+          &Len,\r
+          Timeout,\r
+          Translator,\r
+          TransferResult\r
+          );\r
       }\r
     }\r
 \r
     XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
+\r
+    *(UINT32 *)Data = *(UINT32*)&PortStatus;\r
   }\r
 \r
 FREE_URB:\r
@@ -1147,22 +1247,33 @@ XhcBulkTransfer (
     goto ON_EXIT;\r
   }\r
 \r
-  ASSERT (Urb->EvtRing == &Xhc->EventRing);\r
-\r
   Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
 \r
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
-    ASSERT_EFI_ERROR (RecoveryStatus);\r
-    Status = EFI_DEVICE_ERROR;\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcBulkTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
+    }\r
+  } else {\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
   }\r
 \r
-  FreePool (Urb);\r
+  Xhc->PciIo->Flush (Xhc->PciIo);\r
+  XhcFreeUrb (Xhc, Urb);\r
 \r
 ON_EXIT:\r
 \r
@@ -1272,7 +1383,7 @@ XhcAsyncInterruptTransfer (
     }\r
 \r
     Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);\r
-    DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer, Status = %r\n", Status));\r
+    DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));\r
     goto ON_EXIT;\r
   }\r
 \r
@@ -1321,8 +1432,6 @@ XhcAsyncInterruptTransfer (
     goto ON_EXIT;\r
   }\r
 \r
-  ASSERT (Urb->EvtRing == &Xhc->EventRing);\r
-\r
   InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);\r
   //\r
   // Ring the doorbell\r
@@ -1330,6 +1439,7 @@ XhcAsyncInterruptTransfer (
   Status = RingIntTransferDoorBell (Xhc, Urb);\r
 \r
 ON_EXIT:\r
+  Xhc->PciIo->Flush (Xhc->PciIo);\r
   gBS->RestoreTPL (OldTpl);\r
 \r
   return Status;\r
@@ -1394,10 +1504,6 @@ XhcSyncInterruptTransfer (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (!XHCI_IS_DATAIN (EndPointAddress)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
   if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -1453,15 +1559,28 @@ XhcSyncInterruptTransfer (
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
-    ASSERT_EFI_ERROR (RecoveryStatus);\r
-    Status = EFI_DEVICE_ERROR;\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
+    }\r
+  } else {\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
   }\r
 \r
-  FreePool (Urb);\r
+  Xhc->PciIo->Flush (Xhc->PciIo);\r
+  XhcFreeUrb (Xhc, Urb);\r
 \r
 ON_EXIT:\r
   if (EFI_ERROR (Status)) {\r
@@ -1661,6 +1780,7 @@ ON_EXIT:
   Create and initialize a USB_XHCI_INSTANCE structure.\r
 \r
   @param  PciIo                  The PciIo on this device.\r
+  @param  DevicePath             The device path of host controller.\r
   @param  OriginalPciAttributes  Original PCI attributes.\r
 \r
   @return The allocated and initialized USB_XHCI_INSTANCE structure if created,\r
@@ -1669,8 +1789,9 @@ ON_EXIT:
 **/\r
 USB_XHCI_INSTANCE*\r
 XhcCreateUsbHc (\r
-  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
-  IN UINT64               OriginalPciAttributes\r
+  IN EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
+  IN UINT64                    OriginalPciAttributes\r
   )\r
 {\r
   USB_XHCI_INSTANCE       *Xhc;\r
@@ -1689,6 +1810,7 @@ XhcCreateUsbHc (
   //\r
   Xhc->Signature             = XHCI_INSTANCE_SIG;\r
   Xhc->PciIo                 = PciIo;\r
+  Xhc->DevicePath            = DevicePath;\r
   Xhc->OriginalPciAttributes = OriginalPciAttributes;\r
   CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));\r
 \r
@@ -1714,7 +1836,8 @@ XhcCreateUsbHc (
 \r
   ExtCapReg            = (UINT16) (Xhc->HcCParams.Data.ExtCapReg);\r
   Xhc->ExtCapRegBase   = ExtCapReg << 2;\r
-  Xhc->UsbLegSupOffset = XhcGetLegSupCapAddr (Xhc);\r
+  Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);\r
+  Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);\r
 \r
   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));\r
   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));\r
@@ -1723,13 +1846,14 @@ XhcCreateUsbHc (
   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));\r
   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));\r
   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));\r
 \r
   //\r
   // Create AsyncRequest Polling Timer\r
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
+                  TPL_NOTIFY,\r
                   XhcMonitorAsyncRequests,\r
                   Xhc,\r
                   &Xhc->PollTimer\r
@@ -1750,7 +1874,7 @@ ON_ERROR:
   One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
 \r
   @param  Event                   Pointer to this event\r
-  @param  Context                 Event hanlder private data\r
+  @param  Context                 Event handler private data\r
 \r
 **/\r
 VOID\r
@@ -1778,6 +1902,8 @@ XhcExitBootService (
     gBS->CloseEvent (Xhc->PollTimer);\r
   }\r
 \r
+  XhcClearBiosOwnership (Xhc);\r
+\r
   //\r
   // Restore original PCI attributes\r
   //\r
@@ -1787,8 +1913,6 @@ XhcExitBootService (
                   Xhc->OriginalPciAttributes,\r
                   NULL\r
                   );\r
-\r
-  XhcClearBiosOwnership (Xhc);\r
 }\r
 \r
 /**\r
@@ -1818,6 +1942,7 @@ XhcDriverBindingStart (
   UINT64                  OriginalPciAttributes;\r
   BOOLEAN                 PciAttributesSaved;\r
   USB_XHCI_INSTANCE       *Xhc;\r
+  EFI_DEVICE_PATH_PROTOCOL  *HcDevicePath;\r
 \r
   //\r
   // Open the PciIo Protocol, then enable the USB host controller\r
@@ -1835,6 +1960,19 @@ XhcDriverBindingStart (
     return Status;\r
   }\r
 \r
+  //\r
+  // Open Device Path Protocol for on USB host controller\r
+  //\r
+  HcDevicePath = NULL;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &HcDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
   PciAttributesSaved = FALSE;\r
   //\r
   // Save original PCI attributes\r
@@ -1858,7 +1996,7 @@ XhcDriverBindingStart (
                     &Supports\r
                     );\r
   if (!EFI_ERROR (Status)) {\r
-    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
     Status = PciIo->Attributes (\r
                       PciIo,\r
                       EfiPciIoAttributeOperationEnable,\r
@@ -1875,13 +2013,33 @@ XhcDriverBindingStart (
   //\r
   // Create then install USB2_HC_PROTOCOL\r
   //\r
-  Xhc = XhcCreateUsbHc (PciIo, OriginalPciAttributes);\r
+  Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);\r
 \r
   if (Xhc == NULL) {\r
     DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  //\r
+  // Enable 64-bit DMA support in the PCI layer if this controller\r
+  // supports it.\r
+  //\r
+  if (Xhc->HcCParams.Data.Ac64 != 0) {\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
+                      NULL\r
+                      );\r
+    if (!EFI_ERROR (Status)) {\r
+      Xhc->Support64BitDma = TRUE;\r
+    } else {\r
+      DEBUG ((EFI_D_WARN,\r
+        "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",\r
+        __FUNCTION__, Controller, Status));\r
+    }\r
+  }\r
+\r
   XhcSetBiosOwnership (Xhc);\r
 \r
   XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
@@ -1991,7 +2149,7 @@ CLOSE_PCIIO:
 \r
 \r
 /**\r
-  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  Stop this driver on ControllerHandle. Support stopping any child handles\r
   created by this driver.\r
 \r
   @param  This                 Protocol instance pointer.\r
@@ -2036,6 +2194,16 @@ XhcDriverBindingStop (
     return Status;\r
   }\r
 \r
+  Status = gBS->UninstallProtocolInterface (\r
+                  Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  Usb2Hc\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   Xhc   = XHC_FROM_THIS (Usb2Hc);\r
   PciIo = Xhc->PciIo;\r
 \r
@@ -2061,19 +2229,6 @@ XhcDriverBindingStop (
     }\r
   }\r
 \r
-  XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
-  XhcClearBiosOwnership (Xhc);\r
-\r
-  Status = gBS->UninstallProtocolInterface (\r
-                  Controller,\r
-                  &gEfiUsb2HcProtocolGuid,\r
-                  Usb2Hc\r
-                  );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
   if (Xhc->PollTimer != NULL) {\r
     gBS->CloseEvent (Xhc->PollTimer);\r
   }\r
@@ -2082,6 +2237,8 @@ XhcDriverBindingStop (
     gBS->CloseEvent (Xhc->ExitBootServiceEvent);\r
   }\r
 \r
+  XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+  XhcClearBiosOwnership (Xhc);\r
   XhciDelAllAsyncIntTransfers (Xhc);\r
   XhcFreeSched (Xhc);\r
 \r