ReactOS 0.4.17-dev-1281-g065abb3
XhciBulkRing Class Reference

#include <bulkio.h>

Collaboration diagram for XhciBulkRing:

Static Public Member Functions

static NTSTATUS Initialize (_In_ XhciTransferRing *Ring)
 
static VOID Enable (_In_ XhciTransferRing *Ring)
 
static VOID Disable (_In_ XhciTransferRing *Ring)
 
static VOID ReleaseParkedMapping (_In_ XhciTransferRing *Ring)
 
static NTSTATUS EnableForwardProgress (_In_ XhciTransferRing *Ring, _In_ ULONG MaxTransferSize)
 
static VOID Cleanup (_In_ XhciTransferRing *Ring)
 
static VOID ResumeRingFill (_In_ XhciTransferRing *Ring)
 
static VOID SuspendRingFill (_In_ XhciTransferRing *Ring)
 
static VOID OnPipeHalted (_In_ XhciTransferRing *Ring)
 
static VOID StoppedEventReceived (_In_ XhciTransferRing *Ring)
 
static VOID AllowReclaimOnCancel (_In_ XhciTransferRing *Ring)
 
static VOID ConsumePendingEvents (_In_ XhciTransferRing *Ring)
 
static VOID RecoverTransfers (_In_ XhciTransferRing *Ring)
 
static BOOLEAN DoorbellRungSinceFill (_In_ const XhciTransferRing *Ring)
 
static BOOLEAN HasQueuedWork (_In_ const XhciTransferRing *Ring)
 
static BOOLEAN IsLikelyDuplicate (_In_ const XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 
static BOOLEAN OnTransferEvent (_In_opt_ XhciTransferRing *Ring, _In_ XhciController *Controller, _In_ const XHCI_TRB *Event)
 
static VOID SegmentsArrived (_In_ XhciTransferRing *Ring, _In_ NTSTATUS Status)
 

Static Public Attributes

static EVT_WDF_IO_QUEUE_STATE ReadyNotification
 
static EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue
 
static EVT_WDF_DPC EvtCompletionDpc
 

Private Types

enum class  Outcome : ULONG {
  Ready , Completed , WaitSegments , WaitDma ,
  Failed
}
 

Static Private Member Functions

static VOID BuildTdsFromQueue (_In_ XhciTransferRing *Ring)
 
static VOID FillLoop (_In_ XhciTransferRing *Ring)
 
static VOID KickFill (_In_ XhciTransferRing *Ring)
 
static XhciBulkStage * NextTdSlot (_In_ XhciTransferRing *Ring)
 
static XhciBulkStage * AcquireStage (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
 
static VOID ReleaseStage (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static VOID PutScatterGather (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static VOID InitTransfer (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ WDFREQUEST Request)
 
static VOID ChooseMechanism (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
 
static NTSTATUS ArrangeBuffer (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
 
static VOID DropMdl (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
 
static VOID FreeTransferResources (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
 
static Outcome PrimeStage (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static NTSTATUS AcquireStageMdl (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static VOID SizeStage (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static VOID EstimateTrbs (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static BOOLEAN EstimateSegments (_In_ XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage, _Out_ PULONG Segments)
 
static BOOLEAN ParkOnSegments (_In_ XhciTransferRing *Ring)
 
static Outcome FailStage (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static Outcome EncodeStage (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static BOOLEAN BuildTd (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static BOOLEAN InsertLink (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage, _In_ BOOLEAN FirstOfTd)
 
static VOID UndoTd (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
 
static VOID CompleteAfterUncancel (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ USBD_STATUS Default, _In_ BOOLEAN FinishCanceled)
 
static VOID Complete (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ USBD_STATUS Default)
 
static VOID CompleteBatch (_In_ XhciTransferRing *Ring, _Inout_ PLIST_ENTRY Batch)
 
static VOID QueueCompletionDpc (_In_ XhciTransferRing *Ring)
 
static BOOLEAN OwnsRequests (_In_ const XhciTransferRing *Ring)
 
static BOOLEAN Ed1Event (_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 
static BOOLEAN Ed0Event (_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 
static BOOLEAN IsLiveStage (_In_ const XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage, _In_ ULONG64 EventData)
 
static BOOLEAN LookupStage (_In_ const XhciTransferRing *Ring, _In_ ULONG64 Address, _Outptr_result_maybenull_ XhciBulkStage **Stage, _Out_ PULONG Skipped)
 
static VOID HaltedEvent (_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage, _In_ ULONG Code, _In_ ULONG Bytes)
 
static VOID StoppedEvent (_In_ XhciTransferRing *Ring, _Inout_opt_ XhciBulkStage *Stage, _In_ ULONG Code, _In_ ULONG Bytes, _In_ ULONG Skipped)
 
static BOOLEAN LikelyDuplicate (_In_ const XhciTransferRing *Ring, _In_ ULONG64 Address, _Out_ PBOOLEAN PointsToNoOp)
 
static VOID Ed0Mismatch (_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 
static VOID StreamStopOrHalt (_In_ XhciTransferRing *Ring)
 
static VOID StreamStopOrHaltOnce (_In_ XhciTransferRing *Ring, _In_ ULONG Flag)
 

Private Attributes

BOOLEAN m_ImmediateData
 
BOOLEAN m_DpcRunning
 
ULONG m_Flags
 
ULONG m_MaxPendingStages
 
ULONG m_PendingStages
 
ULONG m_OutstandingEvents
 
ULONG m_SegmentWaits
 
volatile LONG m_FillAgain
 
volatile LONG m_FillWanted
 
volatile LONG m_SegmentWait
 
volatile LONG m_ForwardProgressBusy
 
LIST_ENTRY m_Pending
 
LIST_ENTRY m_WaitingForCancel
 
LIST_ENTRY m_Completion
 
XhciBulkStage m_Stages [StageSlots]
 

Static Private Attributes

static const ULONG StageSlots = 6
 
static EVT_WDF_REQUEST_CANCEL EvtRequestCancel
 
static DRIVER_LIST_CONTROL DmaCallback
 

Detailed Description

Bulk and interrupt ring state and the entry points the transfer ring calls for it.

Definition at line 87 of file bulkio.h.

Member Enumeration Documentation

◆ Outcome

Enumerator
Ready 
Completed 
WaitSegments 
WaitDma 
Failed 

Definition at line 166 of file bulkio.h.

Member Function Documentation

◆ AcquireStage()

static XhciBulkStage * XhciBulkRing::AcquireStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer 
)
staticprivate

Referenced by NextTdSlot().

◆ AcquireStageMdl()

NTSTATUS XhciBulkRing::AcquireStageMdl ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Definition at line 1397 of file bulkio.cpp.

1400{
1401 XhciBulkTransfer* Transfer = Stage->Transfer;
1402 PMDL Mdl = Transfer->Mdl;
1403 ULONG Offset = Transfer->BytesQueued;
1404 PUCHAR Start;
1405 ULONG Length;
1406 PMDL Partial;
1407
1408 while (Mdl != NULL && Offset >= MmGetMdlByteCount(Mdl))
1409 {
1411 Mdl = Mdl->Next;
1412 }
1413
1414 if (Mdl == NULL)
1415 {
1416 DPRINT1("Bulk DCI %lu stream %lu: MDL chain shorter than the transfer\n",
1417 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1419 }
1420
1421 if (Offset == 0)
1422 {
1423 Stage->Mdl = Mdl;
1424 return STATUS_SUCCESS;
1425 }
1426
1427 Start = static_cast<PUCHAR>(MmGetMdlVirtualAddress(Mdl)) + Offset;
1429
1430 Partial = IoAllocateMdl(Start, Length, FALSE, FALSE, NULL);
1431 if (Partial == NULL)
1432 {
1433 DPRINT1("Bulk DCI %lu stream %lu: partial MDL allocation failed\n",
1434 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1436 }
1437
1438 IoBuildPartialMdl(Mdl, Partial, Start, Length);
1439 Partial->Next = Mdl->Next;
1440 Stage->Mdl = Partial;
1441 Stage->FreeMdl = TRUE;
1442 return STATUS_SUCCESS;
1443}
static _Out_opt_ PULONGLONG Start
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define IoAllocateMdl
Definition: fxmdl.h:88
VOID NTAPI IoBuildPartialMdl(IN PMDL SourceMdl, IN PMDL TargetMdl, IN PVOID VirtualAddress, IN ULONG Length)
Definition: iomdl.c:96
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define STATUS_SUCCESS
Definition: shellext.h:65
ULONG BytesQueued
Definition: bulkio.h:80
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
#define MmGetMdlByteCount(_Mdl)
#define MmGetMdlVirtualAddress(_Mdl)

Referenced by PrimeStage().

◆ AllowReclaimOnCancel()

VOID XhciBulkRing::AllowReclaimOnCancel ( _In_ XhciTransferRing *  Ring)
static

Definition at line 680 of file bulkio.cpp.

682{
683 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
686
687 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
688 if (Bulk->m_Flags & XhciBulkCanceled)
689 {
690 /* QUIRK: the "OK to reclaim" flag stays clear when a cancel already happened */
691 XhciBulkMoveList(&Bulk->m_Completion, &Bulk->m_Pending);
692 Queue = TRUE;
693 }
694 else
695 {
696 Bulk->m_Flags |= XhciBulkOkToReclaim;
697 }
698 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
699
700 if (Queue)
701 QueueCompletionDpc(Ring);
702}
unsigned char BOOLEAN
Definition: actypes.h:127
static const ULONG XhciBulkOkToReclaim
Definition: bulkio.cpp:33
static VOID NTAPI XhciBulkMoveList(_Inout_ PLIST_ENTRY Destination, _Inout_ PLIST_ENTRY Source)
Definition: bulkio.cpp:204
static const ULONG XhciBulkCanceled
Definition: bulkio.cpp:32
static VOID QueueCompletionDpc(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:2213
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
_Must_inspect_result_ _In_ WDFDEVICE _In_ PIRP _In_ WDFQUEUE Queue
Definition: wdfdevice.h:2231
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

Referenced by XhciTransferRing::AllowReclaimOnCancel().

◆ ArrangeBuffer()

NTSTATUS XhciBulkRing::ArrangeBuffer ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer 
)
staticprivate

Definition at line 1207 of file bulkio.cpp.

1210{
1211 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1212 struct _URB_BULK_OR_INTERRUPT_TRANSFER* Urb = Transfer->Urb;
1213
1214 switch (Transfer->Mechanism)
1215 {
1216 case XhciBulkMechanism::Immediate:
1217 case XhciBulkMechanism::DoubleBuffer:
1218 if (Urb->TransferBuffer != NULL)
1219 {
1220 Transfer->Buffer = static_cast<PUCHAR>(Urb->TransferBuffer);
1221 }
1222 else if (Urb->TransferBufferMDL != NULL)
1223 {
1224 Transfer->Buffer = static_cast<PUCHAR>(
1226 }
1227
1228 if (Transfer->Buffer == NULL)
1229 {
1230 DPRINT1("Bulk DCI %lu stream %lu: no system address for the buffer\n",
1231 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1233 }
1234 return STATUS_SUCCESS;
1235
1236 case XhciBulkMechanism::Dma:
1237 if (Urb->TransferBufferMDL != NULL)
1238 {
1239 Transfer->Mdl = Urb->TransferBufferMDL;
1240 return STATUS_SUCCESS;
1241 }
1242
1243 Transfer->Mdl = IoAllocateMdl(Urb->TransferBuffer, Transfer->BytesTotal, FALSE, FALSE, NULL);
1244 if (Transfer->Mdl == NULL)
1245 {
1246 if (!(Urb->TransferFlags & USB3_URB_RESERVED_RESOURCES) ||
1247 Ring->m_ReservedMdl == NULL)
1248 {
1249 DPRINT1("Bulk DCI %lu stream %lu: MDL allocation failed\n",
1250 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1252 }
1253
1254 /* The reserved MDL serves one request at a time */
1255 if (InterlockedCompareExchange(&Bulk->m_ForwardProgressBusy, 1, 0) != 0)
1256 {
1257 DPRINT1("Bulk DCI %lu stream %lu: forward progress MDL already in use\n",
1258 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1260 }
1261
1262 Transfer->Mdl = Ring->m_ReservedMdl;
1263 Transfer->UsesReservedMdl = TRUE;
1264 MmInitializeMdl(Transfer->Mdl, Urb->TransferBuffer, Transfer->BytesTotal);
1265 }
1266
1267 MmBuildMdlForNonPagedPool(Transfer->Mdl);
1268 return STATUS_SUCCESS;
1269
1270 default:
1271 return STATUS_SUCCESS;
1272 }
1273}
#define USB3_URB_RESERVED_RESOURCES
Definition: hubreq.cpp:15
#define InterlockedCompareExchange
Definition: interlocked.h:119
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:423
@ NormalPagePriority
Definition: imports.h:54
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333
#define MmInitializeMdl(_MemoryDescriptorList, _BaseVa, _Length)
#define MmGetSystemAddressForMdlSafe(_Mdl, _Priority)

Referenced by NextTdSlot().

◆ BuildTd()

BOOLEAN XhciBulkRing::BuildTd ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Writes the TD of a stage and hands it to the controller. On failure the ring is put back as it was and the caller fails the stage.

Definition at line 1736 of file bulkio.cpp.

1739{
1740 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1741 XhciBulkTransfer* Transfer = Stage->Transfer;
1742 XhciDmaBuffer* PadBuffer = Ring->m_Controller->m_SplitPadBuffer;
1743 PSCATTER_GATHER_LIST SgList = Stage->SgList;
1744 ULONG PadBytes = XhciBulkPadSize(Ring, Stage->Size);
1745 BOOLEAN NoOps = XhciBulkNeedsNoOps(Ring);
1746 ULONG Packets = Ring->PacketCount(Stage->Size);
1747 ULONG Pending = Stage->BurstTrbBudget;
1748 ULONG Mapped = 0;
1749 ULONG Element = 0;
1750 ULONG64 ElementAddress = 0;
1751 ULONG ElementLeft = 0;
1752 XhciBulkStep Step = XhciBulkStep::Normal;
1753 PXHCI_TRB First = &Ring->m_Trbs[Ring->m_EnqueueIndex];
1754 volatile UCHAR* CycleByte;
1755 XHCI_TRB Trb;
1756 ULONG64 Value;
1757 ULONG Chunk;
1758 ULONG Index;
1759 BOOLEAN IsFirst;
1760 KIRQL OldIrql;
1761
1762 Stage->TrbsWritten = 0;
1763
1764 if (Ring->m_Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment) && !InsertLink(Ring, Stage, TRUE))
1765 {
1766 UndoTd(Ring, Stage);
1767 return FALSE;
1768 }
1769
1770 while (Step != XhciBulkStep::Done)
1771 {
1772 IsFirst = (&Ring->m_Trbs[Ring->m_EnqueueIndex] == First);
1773
1774 /* Keep each burst sized piece of the TD inside one segment (xHCI 4.11.7.1) */
1775 if (Pending + Ring->m_EnqueueIndex > Ring->m_LastIndex ||
1776 (NoOps && Step == XhciBulkStep::EventData &&
1777 Ring->m_EnqueueIndex + XhciBulkNoOpCount + 1 > Ring->m_LastIndex))
1778 {
1779 /* A failed insert fails the TD instead of retrying */
1780 if (!InsertLink(Ring, Stage, IsFirst))
1781 {
1782 UndoTd(Ring, Stage);
1783 return FALSE;
1784 }
1785 continue;
1786 }
1787
1788 RtlZeroMemory(&Trb, sizeof(Trb));
1789
1790 if (Step == XhciBulkStep::Normal)
1791 {
1792 Trb.Dword[3] = static_cast<ULONG>(XhciTrbType::Normal) << XHCI_TRB_TYPE_SHIFT;
1793
1794 switch (Transfer->Mechanism)
1795 {
1796 case XhciBulkMechanism::Immediate:
1797 RtlCopyMemory(&Trb.Dword[0], Stage->Buffer, Stage->Size);
1798 Trb.Dword[3] |= XHCI_TRB_IDT;
1799 Chunk = Stage->Size;
1800 Step = XhciBulkStep::EventData;
1801 break;
1802
1803 case XhciBulkMechanism::DoubleBuffer:
1804 if (!XhciBulkTransferIn(Transfer))
1805 RtlCopyMemory(Stage->DoubleBuffer->VirtualAddress, Stage->Buffer, Stage->Size);
1806 Trb.Dword[0] = Stage->DoubleBuffer->LogicalAddress.LowPart;
1807 Trb.Dword[1] = (ULONG)Stage->DoubleBuffer->LogicalAddress.HighPart;
1808 Chunk = Stage->Size;
1809 Step = XhciBulkStep::EventData;
1810 break;
1811
1812 case XhciBulkMechanism::Dma:
1813 if (ElementLeft == 0)
1814 {
1815 ElementAddress = (ULONG64)SgList->Elements[Element].Address.QuadPart;
1816 ElementLeft = SgList->Elements[Element].Length;
1817 Element++;
1818 }
1819
1820 /* A TRB buffer may not cross a 64 KB boundary (xHCI 6.4.1.1) */
1821 Chunk = min(ElementLeft, XhciBulkTrbBytesMax - (ULONG)(ElementAddress & 0xFFFF));
1822 Trb.Dword[0] = (ULONG)ElementAddress;
1823 Trb.Dword[1] = (ULONG)(ElementAddress >> 32);
1824 ElementAddress += Chunk;
1825 ElementLeft -= Chunk;
1826
1827 if (ElementLeft == 0 && Element >= SgList->NumberOfElements)
1828 Step = XhciBulkStep::EventData;
1829 break;
1830
1831 default:
1832 Chunk = 0;
1833 Step = XhciBulkStep::EventData;
1834 break;
1835 }
1836
1837 Mapped += Chunk;
1838 Trb.Dword[2] = Chunk |
1839 (Ring->TdSize(Packets, Mapped, Step == XhciBulkStep::EventData) << XHCI_TRB_TD_SIZE_SHIFT);
1840 Trb.Dword[3] |= XHCI_TRB_CHAIN;
1841 Pending--;
1842 }
1843 else if (Step == XhciBulkStep::Pad)
1844 {
1845 Trb.Dword[0] = PadBuffer->LogicalAddress.LowPart;
1846 Trb.Dword[1] = (ULONG)PadBuffer->LogicalAddress.HighPart;
1847 Trb.Dword[2] = PadBytes;
1848 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::Normal) << XHCI_TRB_TYPE_SHIFT) | XHCI_TRB_CHAIN;
1849 Pending--;
1850 PadBytes = 0;
1851 Step = XhciBulkStep::EventData;
1852 }
1853 else
1854 {
1855 Value = XhciBulkEventData(Ring, Stage);
1856 Trb.Dword[0] = (ULONG)Value;
1857 Trb.Dword[1] = (ULONG)(Value >> 32);
1858 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::EventData) << XHCI_TRB_TYPE_SHIFT) | XHCI_TRB_IOC;
1859 Step = XhciBulkStep::Done;
1860 }
1861
1862 Stage->TrbsWritten++;
1863
1864 if (Step == XhciBulkStep::EventData)
1865 {
1866 if (PadBytes != 0 && PadBuffer != NULL)
1867 {
1868 Trb.Dword[2] += 1 << XHCI_TRB_TD_SIZE_SHIFT;
1869 Step = XhciBulkStep::Pad;
1870
1871 /* The pad still needs a slot when the burst is used up */
1872 if (Pending == 0)
1873 Pending = 1;
1874 }
1875 else
1876 {
1877 /* xHCI 4.12.3: let a flow controlled ring reach the Event Data TRB */
1878 Trb.Dword[3] |= XHCI_TRB_ENT;
1879 Pending = 1;
1880 }
1881 }
1882 else if (Step == XhciBulkStep::Normal && Pending == 0)
1883 {
1884 Pending = (Stage->TrbsReserved > Stage->TrbsWritten) ?
1885 min(Stage->BurstTrbBudget, Stage->TrbsReserved - Stage->TrbsWritten) :
1886 Stage->BurstTrbBudget;
1887 }
1888
1889 /* The first slot stays invalid until the whole TD is written */
1890 Trb.Dword[3] |= IsFirst ? (Ring->m_Cycle ^ XHCI_TRB_CYCLE) : Ring->m_Cycle;
1891 Trb.Dword[2] |= Ring->m_InterrupterTarget << XHCI_TRB_INTERRUPTER_SHIFT;
1892
1893 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1894 Ring->m_EnqueueIndex++;
1895
1896 if (Step == XhciBulkStep::Done && NoOps)
1897 {
1898 for (Index = 0; Index < XhciBulkNoOpCount; Index++)
1899 {
1900 RtlZeroMemory(&Trb, sizeof(Trb));
1901 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::NoOp) << XHCI_TRB_TYPE_SHIFT) | Ring->m_Cycle;
1902 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1903 Ring->m_EnqueueIndex++;
1904 }
1905 }
1906 }
1907
1908 NT_ASSERT(Stage->TrbsWritten <= Stage->TrbsReserved);
1909
1910 /* Recycled segments are not cleared, so the slot after the TD must be */
1911 Stage->LastSegment = Ring->m_Segment;
1912 Stage->EndIndex = Ring->m_EnqueueIndex;
1913 RtlZeroMemory(&Ring->m_Trbs[Ring->m_EnqueueIndex], sizeof(XHCI_TRB));
1914
1915 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1916 Transfer->TdsQueued++;
1917 Transfer->BytesQueued += Stage->Size;
1918 Transfer->MappedOnce = TRUE;
1919 Bulk->m_PendingStages++;
1920 Stage->OnHardware = TRUE;
1921 Ring->m_DoorbellRung = TRUE;
1922 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1923
1924 /* A one byte register write publishes the TD after every store above */
1926 CycleByte = reinterpret_cast<volatile UCHAR*>(&First->Dword[3]);
1927 WRITE_REGISTER_UCHAR(const_cast<PUCHAR>(CycleByte), (UCHAR)(*CycleByte ^ XHCI_TRB_CYCLE));
1929
1930 Ring->RingDoorbell();
1931 return TRUE;
1932}
WCHAR First[]
Definition: FormatMessage.c:11
static BOOLEAN NTAPI XhciBulkNeedsNoOps(_In_ const XhciTransferRing *Ring)
Definition: bulkio.cpp:148
XhciBulkStep
Definition: bulkio.cpp:43
static ULONG64 NTAPI XhciBulkEventData(_In_ const XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage)
Definition: bulkio.cpp:333
static ULONG NTAPI XhciBulkPadSize(_In_ const XhciTransferRing *Ring, _In_ ULONG Size)
Definition: bulkio.cpp:161
static const ULONG XhciBulkNoOpCount
Definition: bulkio.cpp:21
static BOOLEAN NTAPI XhciBulkTransferIn(_In_ const XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:102
static const ULONG XhciBulkTrbBytesMax
Definition: bulkio.cpp:18
static VOID UndoTd(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1975
static BOOLEAN InsertLink(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage, _In_ BOOLEAN FirstOfTd)
Definition: bulkio.cpp:1936
@ Pending
Definition: fs_rec.h:186
if(dx< 0)
Definition: linetemp.h:194
unsigned __int64 ULONG64
Definition: imports.h:198
#define min(a, b)
Definition: monoChain.cc:55
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58
BOOLEAN MappedOnce
Definition: bulkio.h:66
XhciBulkMechanism Mechanism
Definition: bulkio.h:68
ULONG TdsQueued
Definition: bulkio.h:82
PHYSICAL_ADDRESS LogicalAddress
Definition: dmapool.h:17
ULONG Dword[4]
Definition: xhcihw.h:17
unsigned char UCHAR
Definition: typedefs.h:53
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
ULONG LowPart
Definition: typedefs.h:106
_In_ WDFCOLLECTION _In_ ULONG Index
WDF_EXTERN_C_START typedef _In_ WDFDEVICE _In_ WDFCONTEXT _In_ WDF_DMA_DIRECTION _In_ PSCATTER_GATHER_LIST SgList
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
struct _SCATTER_GATHER_LIST * PSCATTER_GATHER_LIST
Definition: iotypes.h:2219
#define NT_ASSERT
Definition: rtlfuncs.h:3334
#define XHCI_TRB_TYPE_SHIFT
Definition: xhcihw.h:23
#define XHCI_TRB_ENT
Definition: xhcihw.h:623
#define XHCI_TRB_TD_SIZE_SHIFT
Definition: xhcihw.h:622
#define XHCI_TRB_IDT
Definition: xhcihw.h:625
#define XHCI_TRB_INTERRUPTER_SHIFT
Definition: xhcihw.h:610
#define XHCI_TRB_IOC
Definition: xhcihw.h:624
#define XHCI_TRB_CYCLE
Definition: xhcihw.h:22
#define XHCI_TRB_CHAIN
Definition: xhcihw.h:609

Referenced by EncodeStage().

◆ BuildTdsFromQueue()

VOID XhciBulkRing::BuildTdsFromQueue ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 842 of file bulkio.cpp.

844{
845 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
847
849
850 for (;;)
851 {
852 FillLoop(Ring);
853
854 if (Ring->m_MapState != static_cast<LONG>(XhciMapState::PausedFill) ||
855 Bulk->m_FillWanted == 0)
856 {
857 break;
858 }
859
860 if (Ring->ChangeMapState(FALSE, XhciMapState::PausedFill, XhciMapState::Filling) != XhciMapState::PausedFill)
861 break;
862 }
863
865}
static VOID FillLoop(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:868
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
long LONG
Definition: pedump.c:60

Referenced by KickFill(), ResumeRingFill(), and SegmentsArrived().

◆ ChooseMechanism()

VOID XhciBulkRing::ChooseMechanism ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer 
)
staticprivate

Definition at line 1177 of file bulkio.cpp.

1180{
1181 if (Transfer->BytesTotal == 0)
1182 {
1183 Transfer->Mechanism = XhciBulkMechanism::NoData;
1184 return;
1185 }
1186
1187 if (Ring->m_Type.Bulk.m_ImmediateData && Transfer->BytesTotal <= XhciBulkImmediateBytes)
1188 {
1189 Transfer->Mechanism = XhciBulkMechanism::Immediate;
1190 return;
1191 }
1192
1193 if (!XhciBulkChainedMdl(Transfer) && Transfer->BytesTotal <= Ring->m_DoubleBufferSize)
1194 {
1195 Transfer->DoubleBuffer = Ring->BorrowBounceBuffer();
1196 if (Transfer->DoubleBuffer != NULL)
1197 {
1198 Transfer->Mechanism = XhciBulkMechanism::DoubleBuffer;
1199 return;
1200 }
1201 }
1202
1203 Transfer->Mechanism = XhciBulkMechanism::Dma;
1204}
static const ULONG XhciBulkImmediateBytes
Definition: bulkio.cpp:19
static BOOLEAN NTAPI XhciBulkChainedMdl(_In_ const XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:111

Referenced by NextTdSlot().

◆ Cleanup()

VOID XhciBulkRing::Cleanup ( _In_ XhciTransferRing *  Ring)
static

Definition at line 502 of file bulkio.cpp.

504{
505 BOOLEAN Owned;
507
508 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
509 Owned = OwnsRequests(Ring);
510 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
511
512 if (Owned)
513 {
514 DPRINT1("Bulk DCI %lu stream %lu cleaned up with requests still owned\n",
515 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
517 }
518}
static BOOLEAN OwnsRequests(_In_ const XhciTransferRing *Ring)

Referenced by XhciTransferRing::Cleanup().

◆ Complete()

static VOID XhciBulkRing::Complete ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer,
_In_ USBD_STATUS  Default 
)
staticprivate

Referenced by CompleteBatch(), and NextTdSlot().

◆ CompleteAfterUncancel()

static VOID XhciBulkRing::CompleteAfterUncancel ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer,
_In_ USBD_STATUS  Default,
_In_ BOOLEAN  FinishCanceled 
)
staticprivate

◆ CompleteBatch()

VOID XhciBulkRing::CompleteBatch ( _In_ XhciTransferRing *  Ring,
_Inout_ PLIST_ENTRY  Batch 
)
staticprivate

Definition at line 2096 of file bulkio.cpp.

2099{
2100 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2101 XhciBulkTransfer* Transfer;
2102 XhciBulkStage* Stage;
2103 LIST_ENTRY Canceled;
2104 LIST_ENTRY Finished;
2106 BOOLEAN OnHardware;
2108 KIRQL OldIrql;
2109
2110 InitializeListHead(&Canceled);
2111 InitializeListHead(&Finished);
2113
2114 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2115
2116 while (!IsListEmpty(Batch))
2117 {
2119 XhciClearListEntry(&Transfer->Link);
2120
2121 Stage = Transfer->Stage;
2122 if (Stage != NULL)
2123 {
2124 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2125 PutScatterGather(Ring, Stage);
2126 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2127
2128 OnHardware = Stage->OnHardware;
2129 ReleaseStage(Ring, Stage);
2130 if (OnHardware)
2131 {
2132 Transfer->TdsRetired++;
2133 Bulk->m_PendingStages--;
2134 }
2135 }
2136
2137 if (Transfer->CancelState == XhciBulkCancel::Done)
2138 {
2139 InsertTailList(&Canceled, &Transfer->Link);
2140 continue;
2141 }
2142
2143 if (Transfer->CancelState == XhciBulkCancel::Armed)
2144 {
2145 Status = WdfRequestUnmarkCancelable(Transfer->Request);
2146 if (!NT_SUCCESS(Status))
2147 {
2148 Transfer->CancelState = XhciBulkCancel::CancelRoutinePending;
2149 InsertTailList(&Bulk->m_WaitingForCancel, &Transfer->Link);
2150 continue;
2151 }
2152 Transfer->CancelState = XhciBulkCancel::Idle;
2153 }
2154
2155 if (Transfer->CompletionCode == static_cast<ULONG>(XhciCompletionCode::Success) ||
2156 Transfer->CompletionCode == static_cast<ULONG>(XhciCompletionCode::StoppedShortPacket))
2157 {
2158 InsertTailList(&Finished, &Transfer->Link);
2159 }
2160 else
2161 {
2162 InsertTailList(&Requeue, &Transfer->Link);
2163 }
2164 }
2165
2166 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2167
2168 while (!IsListEmpty(&Canceled))
2169 {
2170 Transfer = CONTAINING_RECORD(RemoveHeadList(&Canceled), XhciBulkTransfer, Link);
2171 XhciClearListEntry(&Transfer->Link);
2172
2173 if (Ring->m_StreamId != 0 && Transfer->CompletionCode == 0)
2174 Transfer->CompletionCode = Ring->m_Endpoint->StreamHaltedCode();
2175
2176 Complete(Ring, Transfer, USBD_STATUS_CANCELED);
2177 }
2178
2179 while (!IsListEmpty(&Finished))
2180 {
2181 Transfer = CONTAINING_RECORD(RemoveHeadList(&Finished), XhciBulkTransfer, Link);
2182 XhciClearListEntry(&Transfer->Link);
2183 Complete(Ring, Transfer, XhciBulkStatusNotSet);
2184 }
2185
2186 /* From the tail, so the oldest request ends up at the head of the queue */
2187 while (!IsListEmpty(&Requeue))
2188 {
2190 XhciClearListEntry(&Transfer->Link);
2191
2192 /* It resumes where the hardware stopped */
2193 Transfer->BytesQueued = Transfer->BytesTransferred;
2194
2195 if (Transfer->DoubleBuffer != NULL)
2196 {
2197 Ring->ReturnBounceBuffer(Transfer->DoubleBuffer);
2198 Transfer->DoubleBuffer = NULL;
2199 }
2200 DropMdl(Ring, Transfer);
2201
2202 Status = WdfRequestRequeue(Transfer->Request);
2203 if (!NT_SUCCESS(Status))
2204 {
2205 DPRINT1("Bulk DCI %lu stream %lu could not requeue request %p, 0x%08lx\n",
2206 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Transfer->Request, Status);
2207 Complete(Ring, Transfer, USBD_STATUS_CANCELED);
2208 }
2209 }
2210}
LONG NTSTATUS
Definition: precomp.h:26
static const USBD_STATUS XhciBulkStatusNotSet
Definition: bulkio.cpp:22
static VOID DropMdl(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:1276
static VOID Complete(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ USBD_STATUS Default)
static VOID PutScatterGather(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
static VOID ReleaseStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define RemoveTailList(ListHead)
Definition: env_spec_w32.h:975
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
Status
Definition: gdiplustypes.h:24
@ Batch
Definition: ntsecapi.h:291
ULONG TdsRetired
Definition: bulkio.h:81
WDFREQUEST Request
Definition: bulkio.h:70
XhciBulkStage * Stage
Definition: bulkio.h:83
XhciBulkCancel CancelState
Definition: bulkio.h:69
XhciDmaBuffer * DoubleBuffer
Definition: bulkio.h:77
ULONG BytesTransferred
Definition: bulkio.h:79
ULONG CompletionCode
Definition: bulkio.h:73
LIST_ENTRY Link
Definition: bulkio.h:64
Definition: typedefs.h:120
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
#define USBD_STATUS_CANCELED
Definition: usb.h:225
_In_ WDFREQUEST _In_ BOOLEAN Requeue
Definition: wdfrequest.h:1654
FORCEINLINE VOID NTAPI XhciClearListEntry(_Out_ PLIST_ENTRY Entry)
Definition: xhciutil.h:117

◆ ConsumePendingEvents()

VOID XhciBulkRing::ConsumePendingEvents ( _In_ XhciTransferRing *  Ring)
static

Definition at line 705 of file bulkio.cpp.

707{
708 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
709 BOOLEAN Acknowledge = FALSE;
711
712 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
713 if (Bulk->m_OutstandingEvents == 0)
714 Acknowledge = TRUE;
715 else
716 Bulk->m_Flags |= XhciBulkAckExpected;
717 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
718
719 if (Acknowledge)
720 Ring->m_Endpoint->OnExpectedEventsProcessed();
721}
static const ULONG XhciBulkAckExpected
Definition: bulkio.cpp:29

Referenced by XhciTransferRing::ConsumePendingEvents().

◆ Disable()

VOID XhciBulkRing::Disable ( _In_ XhciTransferRing *  Ring)
static

Definition at line 422 of file bulkio.cpp.

424{
426
428
429 InterlockedCompareExchange(&Ring->m_MapState,
430 static_cast<LONG>(XhciMapState::Halted),
431 static_cast<LONG>(XhciMapState::PausedFill));
432
433 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
434 if (OwnsRequests(Ring))
435 {
436 DPRINT1("Bulk DCI %lu stream %lu disabled while it still owns requests\n",
437 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
438 }
439 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
440}
static VOID ReleaseParkedMapping(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:443

◆ DoorbellRungSinceFill()

BOOLEAN XhciBulkRing::DoorbellRungSinceFill ( _In_ const XhciTransferRing *  Ring)
static

Definition at line 740 of file bulkio.cpp.

742{
743 return Ring->m_DoorbellRung;
744}

Referenced by XhciTransferRing::DoorbellRungSinceFill().

◆ DropMdl()

VOID XhciBulkRing::DropMdl ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer 
)
staticprivate

Definition at line 1276 of file bulkio.cpp.

1279{
1280 if (Transfer->Mdl == NULL)
1281 return;
1282
1283 if (Transfer->UsesReservedMdl)
1284 {
1285 Transfer->UsesReservedMdl = FALSE;
1286 InterlockedExchange(&Ring->m_Type.Bulk.m_ForwardProgressBusy, 0);
1287 }
1288 else if (Transfer->Mdl != Transfer->Urb->TransferBufferMDL)
1289 {
1290 IoFreeMdl(Transfer->Mdl);
1291 }
1292
1293 Transfer->Mdl = NULL;
1294}
#define InterlockedExchange
Definition: armddk.h:54
#define IoFreeMdl
Definition: fxmdl.h:89

Referenced by CompleteBatch(), and FreeTransferResources().

◆ Ed0Event()

BOOLEAN XhciBulkRing::Ed0Event ( _In_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
staticprivate

Definition at line 2431 of file bulkio.cpp.

2434{
2435 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2437 XhciBulkStage* Stage;
2438 ULONG Skipped;
2439 ULONG Bytes = 0;
2440 KIRQL OldIrql;
2441
2442 if (XhciBulkIsStoppedCode(Code) && Ring->m_Endpoint->ShouldDropStoppedEvent())
2443 return TRUE;
2444
2445 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2446
2447 if (!LookupStage(Ring, XhciTrbPointer(Event), &Stage, &Skipped))
2448 {
2449 if (Ring->m_StreamId == 0)
2450 Ed0Mismatch(Ring, Event);
2451 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2452 return FALSE;
2453 }
2454
2455 if (Stage != NULL)
2456 {
2457 Bytes = XhciBulkStageBytes(Stage, Event);
2458 if (Bytes > Stage->Size)
2459 {
2460 DPRINT1("Bulk DCI %lu stream %lu: %lu bytes found in a %lu byte stage\n",
2461 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Bytes, Stage->Size);
2462 Bytes = 0;
2463 }
2464 }
2465
2467 {
2468 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2469
2470 /* QUIRK: old controllers report a halt one past the last TRB; that event is dropped */
2471 if (Stage != NULL)
2472 HaltedEvent(Ring, Stage, Code, Bytes);
2473 else
2474 DPRINT("Bulk DCI %lu: halt reported at the enqueue pointer, dropped\n", Ring->m_Endpoint->Dci());
2475
2476 return TRUE;
2477 }
2478
2480 {
2481 StoppedEvent(Ring, Stage, Code, Bytes, Skipped);
2482 Bulk->m_Flags |= XhciBulkStoppedSeen;
2483 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2484
2485 Ring->m_Endpoint->OnStoppedEvent();
2486 return TRUE;
2487 }
2488
2489 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2490 DPRINT1("Bulk DCI %lu stream %lu: unexpected code %lu without Event Data\n",
2491 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Code);
2492 return FALSE;
2493}
static BOOLEAN NTAPI XhciBulkIsHaltedCode(_In_ ULONG Code)
Definition: bulkio.cpp:60
static ULONG NTAPI XhciBulkStageBytes(_In_ const XhciBulkStage *Stage, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:288
static BOOLEAN NTAPI XhciBulkIsStoppedCode(_In_ ULONG Code)
Definition: bulkio.cpp:82
static const ULONG XhciBulkStoppedSeen
Definition: bulkio.cpp:31
static VOID Ed0Mismatch(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
static VOID StoppedEvent(_In_ XhciTransferRing *Ring, _Inout_opt_ XhciBulkStage *Stage, _In_ ULONG Code, _In_ ULONG Bytes, _In_ ULONG Skipped)
static VOID HaltedEvent(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage, _In_ ULONG Code, _In_ ULONG Bytes)
Definition: bulkio.cpp:2541
static BOOLEAN LookupStage(_In_ const XhciTransferRing *Ring, _In_ ULONG64 Address, _Outptr_result_maybenull_ XhciBulkStage **Stage, _Out_ PULONG Skipped)
_Check_return_ _In_ DXGK_EVENT_TYPE _In_ ULONG Event
Definition: dispmprt.h:1287
_In_ UINT Bytes
Definition: mmcopy.h:9
#define DPRINT
Definition: sndvol32.h:73
_In_ UCHAR _In_ UCHAR _In_ ULONG Code
Definition: wdfdevice.h:1707
FORCEINLINE ULONG64 NTAPI XhciTrbPointer(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:60
FORCEINLINE ULONG NTAPI XhciTrbCompletionCode(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:42

Referenced by OnTransferEvent().

◆ Ed0Mismatch()

static VOID XhciBulkRing::Ed0Mismatch ( _In_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
staticprivate

Referenced by Ed0Event().

◆ Ed1Event()

BOOLEAN XhciBulkRing::Ed1Event ( _In_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
staticprivate

Definition at line 2317 of file bulkio.cpp.

2320{
2321 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2323 XhciBulkStage* Stage = XhciBulkStageFromEventData(Value);
2324 XhciBulkTransfer* Transfer;
2325 XhciBulkStage* Match;
2328 ULONG EndpointId = (Event->Dword[3] & XHCI_TRB_ENDPOINT_MASK) >> XHCI_TRB_ENDPOINT_SHIFT;
2329 BOOLEAN Acknowledge = FALSE;
2330 BOOLEAN Live;
2332 ULONG Skipped;
2333 KIRQL OldIrql;
2334
2335 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2336 Live = IsLiveStage(Ring, Stage, Value);
2337 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2338
2339 if (!Live)
2340 {
2341 /* A stale or unknown Event Data pointer is dropped, never dereferenced */
2342 if (Ring->m_StreamId == 0)
2343 {
2344 DPRINT1("Bulk DCI %lu: stale or unknown Event Data 0x%I64x code %lu, dropped\n",
2345 Ring->m_Endpoint->Dci(), Value, Code);
2346 }
2347
2348 KickFill(Ring);
2349 return (Ring->m_StreamId == 0);
2350 }
2351
2352 Transfer = Stage->Transfer;
2353
2354 if (EndpointId != Ring->m_Endpoint->Dci() || XhciTrbSlotId(Event) != Ring->m_Device->SlotId())
2355 {
2356 DPRINT1("Bulk event for slot %lu DCI %lu reached slot %lu DCI %lu\n",
2357 XhciTrbSlotId(Event), EndpointId, Ring->m_Device->SlotId(), Ring->m_Endpoint->Dci());
2358 }
2359
2360 if (Bytes > Stage->Size)
2361 {
2362 DPRINT1("Bulk DCI %lu stream %lu: %lu bytes reported for a %lu byte stage\n",
2363 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Bytes, Stage->Size);
2364 Bytes = 0;
2365 }
2366
2368 {
2369 DPRINT1("Bulk DCI %lu stream %lu: halted code %lu reported through Event Data\n",
2370 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Code);
2371 HaltedEvent(Ring, Stage, Code, Bytes);
2372 }
2373 else if (XhciBulkIsStoppedCode(Code))
2374 {
2375 /* QUIRK: the drop stopped event flag is not consulted for Event Data events */
2376 Address = (ULONG64)Stage->FirstSegment->LogicalAddress.QuadPart +
2377 (ULONG64)Stage->FirstIndex * sizeof(XHCI_TRB);
2378
2379 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2380 if (LookupStage(Ring, Address, &Match, &Skipped) && Match == Stage)
2381 StoppedEvent(Ring, Stage, Code, Bytes, Skipped);
2382 else
2384 Bulk->m_Flags |= XhciBulkStoppedSeen;
2385 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2386
2387 Ring->m_Endpoint->OnStoppedEvent();
2388 }
2389 else
2390 {
2391 /* Only a short packet or a fully queued request records the code, so a reclaim cannot finish a partial one as Success */
2392 if (Code == static_cast<ULONG>(XhciCompletionCode::ShortPacket) ||
2393 Transfer->BytesQueued == Transfer->BytesTotal)
2394 {
2395 Transfer->CompletionCode = Code;
2396 }
2397
2398 Transfer->BytesTransferred += Bytes;
2399 XhciBulkCopyIn(Transfer, Stage, Bytes);
2400 PutScatterGather(Ring, Stage);
2401
2402 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2403 ReleaseStage(Ring, Stage);
2404 Transfer->TdsRetired++;
2405
2406 if (Code == static_cast<ULONG>(XhciCompletionCode::ShortPacket) ||
2407 Transfer->BytesQueued == Transfer->BytesTotal)
2408 {
2410 }
2411
2412 Bulk->m_PendingStages--;
2413 if (Bulk->m_OutstandingEvents != 0)
2414 {
2415 Bulk->m_OutstandingEvents--;
2416 if (Bulk->m_OutstandingEvents == 0 && (Bulk->m_Flags & XhciBulkAckExpected))
2417 Acknowledge = TRUE;
2418 }
2419 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2420
2421 if (Acknowledge)
2422 Ring->m_Endpoint->OnExpectedEventsProcessed();
2423 }
2424
2425 /* A slot on the ring freed up */
2426 KickFill(Ring);
2427 return TRUE;
2428}
static XhciBulkStage *NTAPI XhciBulkStageFromEventData(_In_ ULONG64 Value)
Definition: bulkio.cpp:348
static VOID NTAPI XhciBulkCopyIn(_In_ const XhciBulkTransfer *Transfer, _In_ const XhciBulkStage *Stage, _In_ ULONG Bytes)
Definition: bulkio.cpp:188
static VOID KickFill(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:919
static VOID CompleteAfterUncancel(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ USBD_STATUS Default, _In_ BOOLEAN FinishCanceled)
static BOOLEAN IsLiveStage(_In_ const XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage, _In_ ULONG64 EventData)
#define Code
Definition: deflate.h:80
static WCHAR Address[46]
Definition: ping.c:68
ULONG BytesTotal
Definition: bulkio.h:78
#define XHCI_TRB_ENDPOINT_MASK
Definition: xhcihw.h:27
#define XHCI_TRB_ENDPOINT_SHIFT
Definition: xhcihw.h:26
#define XHCI_TRANSFER_EVENT_LENGTH_MASK
Definition: xhcihw.h:635
struct _XHCI_TRB XHCI_TRB
FORCEINLINE ULONG NTAPI XhciTrbSlotId(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:51

Referenced by OnTransferEvent().

◆ Enable()

VOID XhciBulkRing::Enable ( _In_ XhciTransferRing *  Ring)
static

Definition at line 401 of file bulkio.cpp.

403{
404 ULONG Burst;
405
406 NT_ASSERT(Ring->m_MaxStageSize >= XhciBulkMinStageSize);
407
408 if (Ring->m_Device->Speed() != UsbSuperSpeed)
409 return;
410
411 Burst = Ring->m_Endpoint->MaxPacketSize() * (Ring->m_Endpoint->MaxBurst() + 1);
412 if (Burst == 0 || (Ring->m_MaxStageSize % Burst) == 0)
413 return;
414
415 Ring->m_MaxStageSize -= Ring->m_MaxStageSize % Burst;
416 Ring->m_MapRegisterCount = (Ring->m_MaxStageSize + PAGE_SIZE - 1) / PAGE_SIZE;
417 DPRINT("Bulk DCI %lu stream %lu stage size cut to %lu\n",
418 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Ring->m_MaxStageSize);
419}
static const ULONG XhciBulkMinStageSize
Definition: bulkio.cpp:20
#define PAGE_SIZE
Definition: env_spec_w32.h:49
@ UsbSuperSpeed
Definition: usb200.h:45

Referenced by _IRQL_requires_max_().

◆ EnableForwardProgress()

NTSTATUS XhciBulkRing::EnableForwardProgress ( _In_ XhciTransferRing *  Ring,
_In_ ULONG  MaxTransferSize 
)
static

Definition at line 466 of file bulkio.cpp.

469{
471 ULONG PerBurst = XhciBulkWorstPages(Ring->m_Endpoint->MaxEsitPayload()) + 1;
472 ULONG PerSegment = Ring->m_SegmentSize / sizeof(XHCI_TRB) - 1;
473 ULONG Usable = PerSegment - (PerSegment % PerBurst);
474 ULONG Segments;
476
477 if (Usable == 0)
478 {
479 DPRINT1("Bulk DCI %lu: a burst of %lu TRBs does not fit a segment\n",
480 Ring->m_Endpoint->Dci(), PerBurst);
482 }
483
484 Segments = (Needed + Usable - 1) / Usable;
485 if (Segments == 0)
486 Segments = 1;
487
488 Status = Ring->EnsureFreeSegments(Segments, FALSE);
489 if (!NT_SUCCESS(Status))
490 {
491 DPRINT1("Bulk DCI %lu: %lu forward progress segments not available, 0x%08lx\n",
492 Ring->m_Endpoint->Dci(), Segments, Status);
493 return Status;
494 }
495
496 Ring->m_DoubleBufferSize = 0;
497 Ring->m_Type.Bulk.m_ImmediateData = FALSE;
498 return STATUS_SUCCESS;
499}
static ULONG NTAPI XhciBulkWorstPages(_In_ ULONG Bytes)
Definition: bulkio.cpp:122
_In_ ULONG const Usable
Definition: cdrom.h:1084
_In_ ULONG MaxTransferSize
Definition: pipe.h:72

◆ EncodeStage()

XhciBulkRing::Outcome XhciBulkRing::EncodeStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Definition at line 1661 of file bulkio.cpp.

1664{
1665 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1666 PDMA_ADAPTER Adapter;
1668 KIRQL OldIrql;
1669
1670 if (Stage->Transfer->Mechanism != XhciBulkMechanism::Dma)
1671 {
1672 if (!BuildTd(Ring, Stage))
1673 return FailStage(Ring, Stage);
1674 return Outcome::Ready;
1675 }
1676
1677 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
1678
1680 Status = Adapter->DmaOperations->GetScatterGatherList(Adapter,
1681 WdfDeviceWdmGetDeviceObject(Ring->m_Controller->m_Device),
1682 Stage->Mdl,
1683 MmGetMdlVirtualAddress(Stage->Mdl),
1684 Stage->Size,
1686 Stage,
1687 !XhciBulkTransferIn(Stage->Transfer));
1689
1690 if (!NT_SUCCESS(Status))
1691 {
1692 DPRINT1("Bulk DCI %lu stream %lu: GetScatterGatherList failed, 0x%08lx\n",
1693 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Status);
1694 return FailStage(Ring, Stage);
1695 }
1696
1697 /* Whichever of this context and the callback gets here second keeps mapping */
1698 if (InterlockedXor(&Bulk->m_FillAgain, 1) == 1)
1699 return Outcome::Ready;
1700
1701 return Outcome::WaitDma;
1702}
static BOOLEAN BuildTd(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1736
static DRIVER_LIST_CONTROL DmaCallback
Definition: bulkio.h:176
static Outcome FailStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1632
#define InterlockedXor
Definition: interlocked.h:281
struct _DMA_OPERATIONS * DmaOperations
Definition: iotypes.h:2310

Referenced by FillLoop().

◆ EstimateSegments()

BOOLEAN XhciBulkRing::EstimateSegments ( _In_ XhciTransferRing *  Ring,
_In_ const XhciBulkStage *  Stage,
_Out_ PULONG  Segments 
)
staticprivate

Definition at line 1588 of file bulkio.cpp.

1592{
1593 ULONG Available;
1594 ULONG Usable;
1595
1596 *Segments = 0;
1597
1598 if (Ring->m_Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment))
1599 {
1600 /* The TD always starts in a fresh segment */
1601 *Segments = 1;
1602 }
1603 else
1604 {
1605 Available = Ring->m_LastIndex - Ring->m_EnqueueIndex;
1606 Available -= Available % Stage->BurstTrbBudget;
1607
1608 if (Stage->TrbsReserved > Available)
1609 {
1610 Usable = Ring->m_LastIndex - (Ring->m_LastIndex % Stage->BurstTrbBudget);
1611
1612 /* One burst can need more TRBs than a segment holds */
1613 if (Usable == 0)
1614 {
1615 DPRINT1("Bulk DCI %lu stream %lu: a %lu TRB burst does not fit a segment\n",
1616 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Stage->BurstTrbBudget);
1617 return FALSE;
1618 }
1619
1620 *Segments = (Stage->TrbsReserved - Available + Usable - 1) / Usable;
1621 }
1622 }
1623
1624 if (XhciBulkNeedsNoOps(Ring))
1625 *Segments += 1;
1626
1627 return TRUE;
1628}

Referenced by PrimeStage().

◆ EstimateTrbs()

VOID XhciBulkRing::EstimateTrbs ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Definition at line 1502 of file bulkio.cpp.

1505{
1506 XhciBulkTransfer* Transfer = Stage->Transfer;
1507 ULONG Burst;
1508 ULONG Carry = 0;
1509 ULONG CarryTrbs = 0;
1510 ULONG Left;
1511 PMDL Mdl;
1512
1513 if (Transfer->Mechanism != XhciBulkMechanism::Dma)
1514 {
1515 /* One Normal and one Event Data TRB */
1516 Stage->TrbsReserved = 2;
1517 Stage->BurstTrbBudget = 2;
1518 }
1519 else
1520 {
1521 Burst = min(Ring->m_Endpoint->MaxEsitPayload(), Stage->Size);
1522 if (Burst == 0)
1523 Burst = 1;
1524
1525 Stage->BurstTrbBudget = XhciBulkWorstPages(Burst) + 1;
1526 Stage->TrbsReserved = 0;
1527
1528 if (!XhciBulkChainedMdl(Transfer))
1529 {
1530 Stage->TrbsReserved = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Stage->Mdl),
1531 Stage->Size);
1532 }
1533 else
1534 {
1535 /* QUIRK: per burst sized fragment estimate; a carried fragment is counted twice */
1536 for (Mdl = Stage->Mdl, Left = Stage->Size; Mdl != NULL && Left != 0; Mdl = Mdl->Next)
1537 {
1538 ULONG Chunk = min(Left, MmGetMdlByteCount(Mdl));
1539 ULONG Offset = 0;
1540
1541 Left -= Chunk;
1542 while (Offset < Chunk)
1543 {
1544 PUCHAR Va = static_cast<PUCHAR>(MmGetMdlVirtualAddress(Mdl)) + Offset;
1545 ULONG Piece = Chunk - Offset;
1546 ULONG Span;
1547
1548 if (Piece + Carry >= Burst)
1549 {
1550 Span = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Va, Burst - Carry) + CarryTrbs;
1551 Offset += Burst - Carry;
1552 Carry = 0;
1553 CarryTrbs = 0;
1554 }
1555 else
1556 {
1557 Span = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Va, Piece);
1558 Carry = Piece;
1559 CarryTrbs = Span;
1560 Offset = Chunk;
1561 }
1562
1563 Stage->TrbsReserved += Span;
1564
1565 if (Span >= Ring->m_LastIndex)
1566 {
1567 DPRINT1("Bulk DCI %lu stream %lu: a %lu TRB fragment needs a whole segment\n",
1568 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Span);
1569 }
1570
1571 if (Span > Stage->BurstTrbBudget)
1572 Stage->BurstTrbBudget = Span;
1573 }
1574 }
1575 }
1576
1577 Stage->TrbsReserved += 1;
1578 }
1579
1580 if (XhciBulkPadSize(Ring, Stage->Size) != 0)
1581 {
1582 Stage->BurstTrbBudget += 1;
1583 Stage->TrbsReserved += 1;
1584 }
1585}
#define ADDRESS_AND_SIZE_TO_SPAN_PAGES(_Va, _Size)

Referenced by PrimeStage().

◆ FailStage()

XhciBulkRing::Outcome XhciBulkRing::FailStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Drops a stage that cannot be mapped; completes its request when nothing of it is on the ring.

Definition at line 1632 of file bulkio.cpp.

1635{
1636 XhciBulkTransfer* Transfer = Stage->Transfer;
1638 KIRQL OldIrql;
1639
1640 PutScatterGather(Ring, Stage);
1641
1642 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1643 ReleaseStage(Ring, Stage);
1644
1645 if (Transfer->TdsQueued == Transfer->TdsRetired)
1646 {
1649 }
1650 else
1651 {
1652 Transfer->BytesQueued = Transfer->BytesTotal;
1654 }
1655
1656 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1657 return Result;
1658}
#define USBD_STATUS_INSUFFICIENT_RESOURCES
Definition: usb.h:215
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409

Referenced by EncodeStage(), and PrimeStage().

◆ FillLoop()

VOID XhciBulkRing::FillLoop ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 868 of file bulkio.cpp.

870{
871 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
872 XhciBulkStage* Stage;
874 BOOLEAN Pause = FALSE;
875
876 for (;;)
877 {
878 InterlockedExchange(&Bulk->m_FillWanted, 0);
879
880 Stage = NextTdSlot(Ring);
881 if (Stage == NULL)
882 {
883 Pause = TRUE;
884 break;
885 }
886
887 Result = PrimeStage(Ring, Stage);
889 continue;
891 break;
892 if (Result == Outcome::Failed)
893 {
894 Pause = TRUE;
895 break;
896 }
897
898 Result = EncodeStage(Ring, Stage);
900 continue;
902 break;
903 if (Result == Outcome::Failed)
904 {
905 Pause = TRUE;
906 break;
907 }
908
909 /* Also completes a stop that raced in */
910 if (Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::Filling) != XhciMapState::Filling)
911 break;
912 }
913
914 if (Pause)
915 Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::PausedFill);
916}
static XhciBulkStage * NextTdSlot(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:929
static Outcome EncodeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1661
static Outcome PrimeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1317

Referenced by BuildTdsFromQueue().

◆ FreeTransferResources()

VOID XhciBulkRing::FreeTransferResources ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer 
)
staticprivate

Definition at line 1297 of file bulkio.cpp.

1300{
1301 NT_ASSERT(Transfer->Stage == NULL);
1302
1303 if (Transfer->DoubleBuffer != NULL)
1304 {
1305 Ring->ReturnBounceBuffer(Transfer->DoubleBuffer);
1306 Transfer->DoubleBuffer = NULL;
1307 }
1308
1309 DropMdl(Ring, Transfer);
1310 Transfer->Buffer = NULL;
1311 Transfer->Initialized = 0;
1312}

◆ HaltedEvent()

VOID XhciBulkRing::HaltedEvent ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage,
_In_ ULONG  Code,
_In_ ULONG  Bytes 
)
staticprivate

Definition at line 2541 of file bulkio.cpp.

2546{
2547 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2548 XhciBulkTransfer* Transfer = Stage->Transfer;
2549 BOOLEAN Acknowledge = FALSE;
2550 KIRQL OldIrql;
2551
2552 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2553 Bulk->m_Flags |= XhciBulkHalted;
2554 Bulk->m_OutstandingEvents = 1;
2555 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2556
2557 /* The machine must see the halt before the client sees the failed request */
2558 Ring->m_Endpoint->OnHaltedCompletionCode(Code, TRUE);
2559
2560 Transfer->CompletionCode = Code;
2561 Transfer->BytesTransferred += Bytes;
2562 XhciBulkCopyIn(Transfer, Stage, Bytes);
2563 PutScatterGather(Ring, Stage);
2564
2565 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2566 ReleaseStage(Ring, Stage);
2567 Transfer->TdsRetired++;
2569 Bulk->m_PendingStages--;
2570 if (Bulk->m_OutstandingEvents != 0)
2571 Bulk->m_OutstandingEvents--;
2572 if (Bulk->m_Flags & XhciBulkAckExpected)
2573 Acknowledge = TRUE;
2574 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2575
2576 if (Acknowledge)
2577 Ring->m_Endpoint->OnExpectedEventsProcessed();
2578}
static const ULONG XhciBulkHalted
Definition: bulkio.cpp:30

Referenced by Ed0Event(), and Ed1Event().

◆ HasQueuedWork()

BOOLEAN XhciBulkRing::HasQueuedWork ( _In_ const XhciTransferRing *  Ring)
static

Definition at line 747 of file bulkio.cpp.

749{
750 PKSPIN_LOCK Lock = const_cast<PKSPIN_LOCK>(&Ring->m_Lock);
753
755 Pending = !IsListEmpty(&Ring->m_Type.Bulk.m_Pending);
757
758 return Pending;
759}
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127

Referenced by XhciTransferRing::HasQueuedWork().

◆ Initialize()

NTSTATUS XhciBulkRing::Initialize ( _In_ XhciTransferRing *  Ring)
static

Definition at line 357 of file bulkio.cpp.

359{
360 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
361 XhciController* Controller = Ring->m_Controller;
362 ULONG Index;
363
364 RtlZeroMemory(Bulk, sizeof(*Bulk));
365 InitializeListHead(&Bulk->m_Pending);
366 InitializeListHead(&Bulk->m_WaitingForCancel);
367 InitializeListHead(&Bulk->m_Completion);
368
369 for (Index = 0; Index < StageSlots; Index++)
370 {
371 XhciBulkStage* Stage = &Bulk->m_Stages[Index];
372
373 Stage->Signature = XhciBulkStageTag;
374 Stage->Ring = Ring;
375 InitializeListHead(&Stage->FreeSegments);
376 InitializeListHead(&Stage->UsedSegments);
377 }
378
379 Bulk->m_ImmediateData = !Controller->HasErrata(XhciErrata::XferNoInlineData) &&
380 Ring->m_Endpoint->MaxPacketSize() >= XhciBulkImmediateBytes &&
381 !XhciBulkEndpointIn(Ring);
382
383 if (Controller->HasErrata(XhciErrata::XferOneAsyncTdAtATime) ||
384 Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment))
385 {
386 Bulk->m_MaxPendingStages = 1;
387 }
388 else
389 {
390 Bulk->m_MaxPendingStages = XhciBulkPendingStagesMax;
391 }
392
393 /* A TD has to fit one segment, less the Link, Event Data and pad slots */
394 if (Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment))
395 Ring->m_MaxStageSize = (Ring->m_SegmentSize / sizeof(XHCI_TRB) - 4) * PAGE_SIZE;
396
397 return STATUS_SUCCESS;
398}
static const ULONG XhciBulkPendingStagesMax
Definition: bulkio.cpp:16
static BOOLEAN NTAPI XhciBulkEndpointIn(_In_ const XhciTransferRing *Ring)
Definition: bulkio.cpp:93
static const ULONG XhciBulkStageTag
Definition: bulkio.cpp:13
static const ULONG StageSlots
Definition: bulkio.h:164
_Must_inspect_result_ _In_ WDFDEVICE _In_ PUCX_CONTROLLER_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ UCXCONTROLLER * Controller

Referenced by _IRQL_requires_().

◆ InitTransfer()

VOID XhciBulkRing::InitTransfer ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkTransfer *  Transfer,
_In_ WDFREQUEST  Request 
)
staticprivate

Definition at line 1139 of file bulkio.cpp.

1143{
1146
1147 /* A requeued request is already set up; keep its progress instead of starting over */
1148 if (Transfer->Initialized == XhciBulkTransferTag)
1149 {
1150 NT_ASSERT(Transfer->CancelState == XhciBulkCancel::Idle);
1151 NT_ASSERT(Transfer->Status == STATUS_PENDING);
1152 NT_ASSERT(!XhciIsListEntryLinked(&Transfer->Link));
1153 NT_ASSERT(Transfer->TdsQueued == Transfer->TdsRetired);
1154 return;
1155 }
1156
1158 WdfRequestGetParameters(Request, &Parameters);
1159 Urb = static_cast<struct _URB_BULK_OR_INTERRUPT_TRANSFER*>(Parameters.Parameters.Others.Arg1);
1160
1161 RtlZeroMemory(Transfer, sizeof(*Transfer));
1162 XhciClearListEntry(&Transfer->Link);
1163 Transfer->Initialized = XhciBulkTransferTag;
1164 Transfer->Request = Request;
1165 Transfer->Urb = Urb;
1166 Transfer->Ring = Ring;
1167 Transfer->CancelState = XhciBulkCancel::Idle;
1168 Transfer->Status = STATUS_PENDING;
1169 Transfer->Mechanism = XhciBulkMechanism::NoData;
1170 Transfer->BytesTotal = Urb->TransferBufferLength;
1171
1172 /* QUIRK: the length reads 0 until completion, as the USB 2.0 stack does */
1173 Urb->TransferBufferLength = 0;
1174}
static const ULONG XhciBulkTransferTag
Definition: bulkio.cpp:14
_In_ HANDLE _In_ CONST PDXGKMDT_OPM_GET_INFO_PARAMETERS Parameters
Definition: dispmprt.h:321
#define STATUS_PENDING
Definition: telnetd.h:14
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request
FORCEINLINE VOID WDF_REQUEST_PARAMETERS_INIT(_Out_ PWDF_REQUEST_PARAMETERS Parameters)
Definition: wdfrequest.h:211
FORCEINLINE BOOLEAN NTAPI XhciIsListEntryLinked(_In_ const LIST_ENTRY *Entry)
Definition: xhciutil.h:127

Referenced by NextTdSlot().

◆ InsertLink()

BOOLEAN XhciBulkRing::InsertLink ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage,
_In_ BOOLEAN  FirstOfTd 
)
staticprivate

Ends the current segment with a Link TRB into the next reserved one.

Definition at line 1936 of file bulkio.cpp.

1940{
1942 XHCI_TRB Trb;
1943 KIRQL OldIrql;
1944
1945 if (IsListEmpty(&Stage->FreeSegments))
1946 {
1947 DPRINT1("Bulk DCI %lu stream %lu: no reserved segment left for a Link TRB\n",
1948 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1949 return FALSE;
1950 }
1951
1952 Next = CONTAINING_RECORD(RemoveHeadList(&Stage->FreeSegments), XhciDmaBuffer, Link);
1953 XhciClearListEntry(&Next->Link);
1954
1955 /* Chained even ahead of the pad TRB */
1956 Ring->BuildLinkTrb(&Trb, FirstOfTd, TRUE);
1957 Trb.Dword[0] = Next->LogicalAddress.LowPart;
1958 Trb.Dword[1] = (ULONG)Next->LogicalAddress.HighPart;
1959 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1960
1961 /* The ring never toggles its cycle state: it is an endless forward chain of segments */
1962 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1963 InsertTailList(&Stage->UsedSegments, &Ring->m_Segment->Link);
1964 Ring->m_Segment = Next;
1965 Ring->m_Trbs = static_cast<PXHCI_TRB>(Next->VirtualAddress);
1966 Ring->m_EnqueueIndex = 0;
1967 Stage->LastSegment = Next;
1968 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1969
1970 return TRUE;
1971}
PACPI_METHOD_ARGUMENT Next
Definition: slotdev.cpp:96

Referenced by BuildTd().

◆ IsLikelyDuplicate()

BOOLEAN XhciBulkRing::IsLikelyDuplicate ( _In_ const XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
static

Definition at line 762 of file bulkio.cpp.

765{
766 PKSPIN_LOCK Lock = const_cast<PKSPIN_LOCK>(&Ring->m_Lock);
768 BOOLEAN Likely;
770
772 Likely = LikelyDuplicate(Ring, XhciTrbPointer(Event), &NoOp);
774
775 return Likely;
776}
static BOOLEAN LikelyDuplicate(_In_ const XhciTransferRing *Ring, _In_ ULONG64 Address, _Out_ PBOOLEAN PointsToNoOp)

Referenced by XhciTransferRing::IsLikelyDuplicate().

◆ IsLiveStage()

static BOOLEAN XhciBulkRing::IsLiveStage ( _In_ const XhciTransferRing *  Ring,
_In_ const XhciBulkStage *  Stage,
_In_ ULONG64  EventData 
)
staticprivate

Referenced by Ed1Event().

◆ KickFill()

VOID XhciBulkRing::KickFill ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 919 of file bulkio.cpp.

921{
922 InterlockedExchange(&Ring->m_Type.Bulk.m_FillWanted, 1);
923
924 if (Ring->ChangeMapState(FALSE, XhciMapState::PausedFill, XhciMapState::Filling) == XhciMapState::PausedFill)
925 BuildTdsFromQueue(Ring);
926}
static VOID BuildTdsFromQueue(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:842

Referenced by Ed1Event().

◆ LikelyDuplicate()

static BOOLEAN XhciBulkRing::LikelyDuplicate ( _In_ const XhciTransferRing *  Ring,
_In_ ULONG64  Address,
_Out_ PBOOLEAN  PointsToNoOp 
)
staticprivate

Referenced by IsLikelyDuplicate().

◆ LookupStage()

static BOOLEAN XhciBulkRing::LookupStage ( _In_ const XhciTransferRing *  Ring,
_In_ ULONG64  Address,
_Outptr_result_maybenull_ XhciBulkStage **  Stage,
_Out_ PULONG  Skipped 
)
staticprivate

Referenced by Ed0Event(), and Ed1Event().

◆ NextTdSlot()

XhciBulkStage * XhciBulkRing::NextTdSlot ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 929 of file bulkio.cpp.

931{
932 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
933 XhciBulkTransfer* Transfer;
934 XhciBulkStage* Stage;
935 WDFREQUEST Request;
939
940 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
941
942 if (Bulk->m_PendingStages >= Bulk->m_MaxPendingStages)
943 {
944 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
945 return NULL;
946 }
947
948 if (!IsListEmpty(&Bulk->m_Pending))
949 {
950 Transfer = CONTAINING_RECORD(Bulk->m_Pending.Blink, XhciBulkTransfer, Link);
951
952 /* A zero length request has not mapped yet even though its byte count is met */
953 if (Transfer->BytesQueued < Transfer->BytesTotal || !Transfer->MappedOnce)
954 {
955 if (Bulk->m_SegmentWaits != XhciBulkSegmentWaitLimit)
956 {
957 Stage = AcquireStage(Ring, Transfer);
958 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
959 return Stage;
960 }
961
962 if (Transfer->TdsQueued != Transfer->TdsRetired)
963 {
964 /* QUIRK: completes later with the partial length and the hardware status */
965 Transfer->BytesQueued = Transfer->BytesTotal;
966 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
967 return NULL;
968 }
969
970 DPRINT1("Bulk DCI %lu stream %lu gave up waiting for segments\n",
971 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
973
974 /* Reset the count so the next split request waits again */
975 Bulk->m_SegmentWaits = 0;
976 }
977 }
978
979 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
980
981 for (;;)
982 {
983 Status = WdfIoQueueRetrieveNextRequest(Ring->m_Queue, &Request);
984 if (!NT_SUCCESS(Status))
985 return NULL;
986
987 if (XhciGetRequestData(Request) == NULL)
988 {
989 DPRINT1("Bulk request %p has no driver context\n", Request);
990 WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
991 continue;
992 }
993
994 Transfer = &XhciGetRequestData(Request)->Bulk;
995 InitTransfer(Ring, Transfer, Request);
996 Transfer->MappedOnce = FALSE;
997 ChooseMechanism(Ring, Transfer);
998
999 Status = ArrangeBuffer(Ring, Transfer);
1000 if (!NT_SUCCESS(Status))
1001 {
1002 DPRINT1("Bulk DCI %lu stream %lu request %p has no usable buffer, 0x%08lx\n",
1003 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Request, Status);
1005 continue;
1006 }
1007
1008 Transfer->CancelState = XhciBulkCancel::Armed;
1009 Status = WdfRequestMarkCancelableEx(Request, EvtRequestCancel);
1010 if (!NT_SUCCESS(Status))
1011 {
1012 DPRINT1("Bulk DCI %lu stream %lu request %p canceled before mapping, 0x%08lx\n",
1013 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Request, Status);
1014 Transfer->CancelState = XhciBulkCancel::Done;
1015 Complete(Ring, Transfer, USBD_STATUS_CANCELED);
1016 continue;
1017 }
1018
1019 break;
1020 }
1021
1022 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1023 Idle = (Bulk->m_PendingStages == 0);
1024 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1025
1026 /* Every stage on the ring shares one event ring so its events stay in order */
1027 if (Idle)
1028 Ring->UpdateInterrupterTarget(XhciTransferRing::UrbProcessorIndex((PURB)Transfer->Urb));
1029
1030 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1031 Stage = AcquireStage(Ring, Transfer);
1032 InsertTailList(&Bulk->m_Pending, &Transfer->Link);
1033 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1034
1035 return Stage;
1036}
static const ULONG XhciBulkSegmentWaitLimit
Definition: bulkio.cpp:17
static VOID InitTransfer(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ WDFREQUEST Request)
Definition: bulkio.cpp:1139
static NTSTATUS ArrangeBuffer(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:1207
static VOID ChooseMechanism(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:1177
static XhciBulkStage * AcquireStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
static ULONG UrbProcessorIndex(_In_ PURB Urb)
Definition: xferring.cpp:1168
struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb
Definition: bulkio.h:71
Definition: usb.h:565
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
_In_ WDFREQUEST _In_ PFN_WDF_REQUEST_CANCEL EvtRequestCancel
Definition: wdfrequest.h:730

Referenced by FillLoop().

◆ OnPipeHalted()

VOID XhciBulkRing::OnPipeHalted ( _In_ XhciTransferRing *  Ring)
static

Definition at line 666 of file bulkio.cpp.

668{
670}
static VOID StreamStopOrHaltOnce(_In_ XhciTransferRing *Ring, _In_ ULONG Flag)
Definition: bulkio.cpp:646

Referenced by XhciTransferRing::OnPipeHalted().

◆ OnTransferEvent()

BOOLEAN XhciBulkRing::OnTransferEvent ( _In_opt_ XhciTransferRing *  Ring,
_In_ XhciController *  Controller,
_In_ const XHCI_TRB *  Event 
)
static

The ring is always known; the NULL ring form is kept only for callers without one.

Definition at line 779 of file bulkio.cpp.

783{
785
786 if (Ring == NULL)
787 {
788 DPRINT1("Bulk transfer event 0x%I64x without a ring, dropped\n", XhciTrbPointer(Event));
789 return FALSE;
790 }
791
792 if (Event->Dword[3] & XHCI_TRANSFER_EVENT_ED)
793 return Ed1Event(Ring, Event);
794
795 return Ed0Event(Ring, Event);
796}
static BOOLEAN Ed0Event(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:2431
static BOOLEAN Ed1Event(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:2317
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
#define XHCI_TRANSFER_EVENT_ED
Definition: xhcihw.h:321

Referenced by XhciTransferRing::OnTransferEvent().

◆ OwnsRequests()

static BOOLEAN XhciBulkRing::OwnsRequests ( _In_ const XhciTransferRing *  Ring)
staticprivate

Referenced by Cleanup(), and Disable().

◆ ParkOnSegments()

BOOLEAN XhciBulkRing::ParkOnSegments ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 1382 of file bulkio.cpp.

1384{
1385 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1386 LONG Previous;
1387
1390 return TRUE;
1391
1392 InterlockedExchange(&Bulk->m_SegmentWait, XhciBulkWaitIdle);
1393 return FALSE;
1394}
static const LONG XhciBulkWaitParked
Definition: bulkio.cpp:38
static const LONG XhciBulkWaitIdle
Definition: bulkio.cpp:37
Previous

Referenced by PrimeStage().

◆ PrimeStage()

XhciBulkRing::Outcome XhciBulkRing::PrimeStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Definition at line 1317 of file bulkio.cpp.

1320{
1321 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1322 XhciBulkTransfer* Transfer = Stage->Transfer;
1323 ULONG Segments;
1325 KIRQL OldIrql;
1326
1327 switch (Transfer->Mechanism)
1328 {
1329 case XhciBulkMechanism::Immediate:
1330 Stage->Buffer = Transfer->Buffer + Transfer->BytesQueued;
1331 break;
1332
1333 case XhciBulkMechanism::DoubleBuffer:
1334 Stage->Buffer = Transfer->Buffer + Transfer->BytesQueued;
1335 Stage->DoubleBuffer = Transfer->DoubleBuffer;
1336 break;
1337
1338 case XhciBulkMechanism::Dma:
1339 if (!NT_SUCCESS(AcquireStageMdl(Ring, Stage)))
1340 return FailStage(Ring, Stage);
1341 break;
1342
1343 default:
1344 break;
1345 }
1346
1347 SizeStage(Ring, Stage);
1348 EstimateTrbs(Ring, Stage);
1349
1350 if (!EstimateSegments(Ring, Stage, &Segments))
1351 return FailStage(Ring, Stage);
1352
1353 if (Segments == 0)
1354 return Outcome::Ready;
1355
1356 Status = Ring->TakeSegments(Segments, &Stage->FreeSegments);
1357 if (Status == STATUS_PENDING)
1358 {
1359 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1360 ReleaseStage(Ring, Stage);
1361 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1362
1363 if (ParkOnSegments(Ring))
1364 return Outcome::WaitSegments;
1365
1366 /* The segments already arrived; map the request again from the top */
1367 return Outcome::Completed;
1368 }
1369
1370 if (!NT_SUCCESS(Status))
1371 {
1372 DPRINT1("Bulk DCI %lu stream %lu: %lu segments not available, 0x%08lx\n",
1373 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Segments, Status);
1374 return FailStage(Ring, Stage);
1375 }
1376
1377 Bulk->m_SegmentWaits = 0;
1378 return Outcome::Ready;
1379}
static VOID EstimateTrbs(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1502
static BOOLEAN EstimateSegments(_In_ XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage, _Out_ PULONG Segments)
Definition: bulkio.cpp:1588
static VOID SizeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1446
static BOOLEAN ParkOnSegments(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:1382
static NTSTATUS AcquireStageMdl(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1397
PUCHAR Buffer
Definition: bulkio.h:76

Referenced by FillLoop().

◆ PutScatterGather()

static VOID XhciBulkRing::PutScatterGather ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

◆ QueueCompletionDpc()

VOID XhciBulkRing::QueueCompletionDpc ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 2213 of file bulkio.cpp.

2215{
2216 WdfDpcEnqueue(Ring->m_CompletionDpc);
2217}

Referenced by AllowReclaimOnCancel(), and RecoverTransfers().

◆ RecoverTransfers()

VOID XhciBulkRing::RecoverTransfers ( _In_ XhciTransferRing *  Ring)
static

Definition at line 724 of file bulkio.cpp.

726{
727 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
729
730 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
731 XhciBulkMoveList(&Bulk->m_Completion, &Bulk->m_Pending);
732 Bulk->m_Flags |= XhciBulkReclaimAck;
733 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
734
735 /* Only the DPC can tell that nothing is owned anymore */
736 QueueCompletionDpc(Ring);
737}
static const ULONG XhciBulkReclaimAck
Definition: bulkio.cpp:34

Referenced by XhciTransferRing::RecoverTransfers().

◆ ReleaseParkedMapping()

VOID XhciBulkRing::ReleaseParkedMapping ( _In_ XhciTransferRing *  Ring)
static

Lets a mapping loop parked on a segment wait go, so a disable never waits on it.

Definition at line 443 of file bulkio.cpp.

445{
446 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
447
448 /* A loop parked on a segment wait only resumes from a PASSIVE work item; let it go */
451 {
452 DPRINT1("Bulk DCI %lu stream %lu disabled while waiting for segments\n",
453 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
454
455 if (Ring->ChangeMapState(FALSE, XhciMapState::Halting, XhciMapState::Halted) !=
456 XhciMapState::Halting)
457 {
458 InterlockedCompareExchange(&Ring->m_MapState,
459 static_cast<LONG>(XhciMapState::PausedFill),
460 static_cast<LONG>(XhciMapState::Filling));
461 }
462 }
463}
static const LONG XhciBulkWaitAbandoned
Definition: bulkio.cpp:40

Referenced by Disable().

◆ ReleaseStage()

static VOID XhciBulkRing::ReleaseStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

◆ ResumeRingFill()

VOID XhciBulkRing::ResumeRingFill ( _In_ XhciTransferRing *  Ring)
static

Definition at line 606 of file bulkio.cpp.

608{
609 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
612
613 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
614 Bulk->m_Flags = 0;
615 Bulk->m_OutstandingEvents = 0;
616 Ring->m_DoorbellRung = FALSE;
617 NT_ASSERT(Bulk->m_PendingStages == 0);
618 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
619
620 Previous = Ring->ChangeMapState(TRUE, XhciMapState::Halted, XhciMapState::Filling);
621 if (Previous == XhciMapState::Halted)
622 {
623 BuildTdsFromQueue(Ring);
624 return;
625 }
626
627 DPRINT1("Bulk DCI %lu stream %lu started mapping from map state %ld\n",
628 Ring->m_Endpoint->Dci(), Ring->m_StreamId, static_cast<LONG>(Previous));
629}
XhciMapState
Definition: xferring.h:19

Referenced by XhciTransferRing::ResumeRingFill().

◆ SegmentsArrived()

VOID XhciBulkRing::SegmentsArrived ( _In_ XhciTransferRing *  Ring,
_In_ NTSTATUS  Status 
)
static

Common buffer callback for asynchronous segment growth.

Definition at line 799 of file bulkio.cpp.

802{
803 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
804
805 if (!NT_SUCCESS(Status))
806 {
807 DPRINT1("Bulk DCI %lu stream %lu segment growth failed, 0x%08lx\n",
808 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Status);
809 }
810
811 for (;;)
812 {
813 /* The loop already left: resume it here, whatever the map state */
816 {
817 Bulk->m_SegmentWaits++;
818 BuildTdsFromQueue(Ring);
819 return;
820 }
821
822 /* The ring was disabled while waiting */
825 {
826 return;
827 }
828
829 /* The loop has not left yet; it sees this and retries the stage itself */
832 {
833 Bulk->m_SegmentWaits++;
834 return;
835 }
836 }
837}
static const LONG XhciBulkWaitArrived
Definition: bulkio.cpp:39

◆ SizeStage()

VOID XhciBulkRing::SizeStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Definition at line 1446 of file bulkio.cpp.

1449{
1450 XhciBulkTransfer* Transfer = Stage->Transfer;
1451 ULONG Remaining = Transfer->BytesTotal - Transfer->BytesQueued;
1452 ULONG Limit = Ring->m_MaxStageSize;
1453 ULONG Registers = 0;
1454 PDMA_ADAPTER Adapter;
1456 PMDL Mdl;
1457 ULONG Left;
1458
1459 if (Transfer->Mechanism != XhciBulkMechanism::Dma)
1460 {
1461 Stage->Size = Remaining;
1462 return;
1463 }
1464
1465 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
1466 if (Adapter->Version >= DEVICE_DESCRIPTION_VERSION3 &&
1467 Adapter->DmaOperations->Size > FIELD_OFFSET(DMA_OPERATIONS, GetDmaTransferInfo) &&
1468 Adapter->DmaOperations->GetDmaTransferInfo != NULL)
1469 {
1470 RtlZeroMemory(&Info, sizeof(Info));
1472 if (NT_SUCCESS(Adapter->DmaOperations->GetDmaTransferInfo(Adapter,
1473 Stage->Mdl,
1474 0,
1475 Remaining,
1476 !XhciBulkTransferIn(Transfer),
1477 &Info)))
1478 {
1479 Registers = Info.V1.MapRegisterCount;
1480 }
1481 }
1482
1483 if (Registers == 0)
1484 {
1485 /* Without the HAL query count the pages the chain spans */
1486 for (Mdl = Stage->Mdl, Left = Remaining; Mdl != NULL && Left != 0; Mdl = Mdl->Next)
1487 {
1488 ULONG Chunk = min(Left, MmGetMdlByteCount(Mdl));
1489
1491 Left -= Chunk;
1492 }
1493 }
1494
1495 if (Registers > Ring->m_MapRegisterCount && Ring->m_MapRegisterCount > 1)
1496 Limit = min(Limit, (Ring->m_MapRegisterCount - 1) * PAGE_SIZE);
1497
1498 Stage->Size = min(Remaining, Limit);
1499}
PUCHAR Limit
Definition: desccheck.cpp:2230
USHORT Version
Definition: iotypes.h:2308
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
#define DMA_TRANSFER_INFO_VERSION1
Definition: iotypes.h:2116
#define DEVICE_DESCRIPTION_VERSION3
Definition: iotypes.h:2066

Referenced by PrimeStage().

◆ StoppedEvent()

static VOID XhciBulkRing::StoppedEvent ( _In_ XhciTransferRing *  Ring,
_Inout_opt_ XhciBulkStage *  Stage,
_In_ ULONG  Code,
_In_ ULONG  Bytes,
_In_ ULONG  Skipped 
)
staticprivate

Referenced by Ed0Event(), and Ed1Event().

◆ StoppedEventReceived()

VOID XhciBulkRing::StoppedEventReceived ( _In_ XhciTransferRing *  Ring)
static

Definition at line 673 of file bulkio.cpp.

Referenced by XhciTransferRing::StoppedEventReceived().

◆ StreamStopOrHalt()

static VOID XhciBulkRing::StreamStopOrHalt ( _In_ XhciTransferRing *  Ring)
staticprivate

Referenced by StreamStopOrHaltOnce().

◆ StreamStopOrHaltOnce()

VOID XhciBulkRing::StreamStopOrHaltOnce ( _In_ XhciTransferRing *  Ring,
_In_ ULONG  Flag 
)
staticprivate

Definition at line 646 of file bulkio.cpp.

649{
650 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
652
653 if (Ring->m_StreamId == 0)
654 return;
655
656 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
657 if (!(Bulk->m_Flags & Flag))
658 {
659 StreamStopOrHalt(Ring);
660 Bulk->m_Flags |= Flag;
661 }
662 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
663}
static VOID StreamStopOrHalt(_In_ XhciTransferRing *Ring)
Definition: xml2sdb.h:103

Referenced by OnPipeHalted(), and StoppedEventReceived().

◆ SuspendRingFill()

VOID XhciBulkRing::SuspendRingFill ( _In_ XhciTransferRing *  Ring)
static

Definition at line 632 of file bulkio.cpp.

634{
636
637 Previous = Ring->ChangeMapState(TRUE, XhciMapState::Halted, XhciMapState::Halting);
638
639 /* QUIRK: a loop parked on a segment wait acknowledges only when the segments arrive */
640 if (Previous == XhciMapState::PausedFill)
641 Ring->ChangeMapState(FALSE, XhciMapState::Halting, XhciMapState::Halted);
642}

Referenced by XhciTransferRing::SuspendRingFill().

◆ UndoTd()

VOID XhciBulkRing::UndoTd ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciBulkStage *  Stage 
)
staticprivate

Rewinds the ring to where a TD that could not be finished started.

Definition at line 1975 of file bulkio.cpp.

1978{
1979 KIRQL OldIrql;
1980
1981 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1982
1983 if (Ring->m_Segment != Stage->FirstSegment)
1984 {
1985 RemoveEntryList(&Stage->FirstSegment->Link);
1986 XhciClearListEntry(&Stage->FirstSegment->Link);
1987 InsertTailList(&Stage->FreeSegments, &Ring->m_Segment->Link);
1988 Ring->m_Segment = Stage->FirstSegment;
1989 Ring->m_Trbs = static_cast<PXHCI_TRB>(Stage->FirstSegment->VirtualAddress);
1990 }
1991
1992 /* The first slot never became valid, so the controller cannot be past it */
1993 Ring->m_EnqueueIndex = Stage->FirstIndex;
1994 RtlZeroMemory(&Ring->m_Trbs[Stage->FirstIndex], sizeof(XHCI_TRB));
1995 Stage->LastSegment = Stage->FirstSegment;
1996 Stage->EndIndex = Stage->FirstIndex;
1997
1998 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1999}
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986

Referenced by BuildTd().

Member Data Documentation

◆ DmaCallback

VOID NTAPI XhciBulkRing::DmaCallback
staticprivate

Definition at line 176 of file bulkio.h.

Referenced by EncodeStage().

◆ EvtCompletionDpc

VOID NTAPI XhciBulkRing::EvtCompletionDpc
static

Definition at line 115 of file bulkio.h.

Referenced by _IRQL_requires_().

◆ EvtIoCanceledOnQueue

VOID NTAPI XhciBulkRing::EvtIoCanceledOnQueue
static

Definition at line 114 of file bulkio.h.

Referenced by _IRQL_requires_().

◆ EvtRequestCancel

VOID NTAPI XhciBulkRing::EvtRequestCancel
staticprivate

Definition at line 175 of file bulkio.h.

◆ m_Completion

LIST_ENTRY XhciBulkRing::m_Completion
private

Definition at line 356 of file bulkio.h.

◆ m_DpcRunning

BOOLEAN XhciBulkRing::m_DpcRunning
private

Definition at line 344 of file bulkio.h.

◆ m_FillAgain

volatile LONG XhciBulkRing::m_FillAgain
private

Interlocked DMA callback handoff

Definition at line 350 of file bulkio.h.

◆ m_FillWanted

volatile LONG XhciBulkRing::m_FillWanted
private

Interlocked

Definition at line 351 of file bulkio.h.

◆ m_Flags

ULONG XhciBulkRing::m_Flags
private

Definition at line 345 of file bulkio.h.

◆ m_ForwardProgressBusy

volatile LONG XhciBulkRing::m_ForwardProgressBusy
private

Definition at line 353 of file bulkio.h.

◆ m_ImmediateData

BOOLEAN XhciBulkRing::m_ImmediateData
private

Set at initialization and forward progress

Definition at line 343 of file bulkio.h.

◆ m_MaxPendingStages

ULONG XhciBulkRing::m_MaxPendingStages
private

Definition at line 346 of file bulkio.h.

◆ m_OutstandingEvents

ULONG XhciBulkRing::m_OutstandingEvents
private

Definition at line 348 of file bulkio.h.

◆ m_Pending

LIST_ENTRY XhciBulkRing::m_Pending
private

Definition at line 354 of file bulkio.h.

◆ m_PendingStages

ULONG XhciBulkRing::m_PendingStages
private

Definition at line 347 of file bulkio.h.

◆ m_SegmentWait

volatile LONG XhciBulkRing::m_SegmentWait
private

Interlocked segment callback handoff

Definition at line 352 of file bulkio.h.

◆ m_SegmentWaits

ULONG XhciBulkRing::m_SegmentWaits
private

Mapping context only

Definition at line 349 of file bulkio.h.

◆ m_Stages

XhciBulkStage XhciBulkRing::m_Stages[StageSlots]
private

Definition at line 357 of file bulkio.h.

◆ m_WaitingForCancel

LIST_ENTRY XhciBulkRing::m_WaitingForCancel
private

Definition at line 355 of file bulkio.h.

◆ ReadyNotification

VOID NTAPI XhciBulkRing::ReadyNotification
static

Definition at line 113 of file bulkio.h.

Referenced by _IRQL_requires_().

◆ StageSlots

const ULONG XhciBulkRing::StageSlots = 6
staticprivate

Five stages on the hardware plus the one being prepared.

Definition at line 164 of file bulkio.h.

Referenced by Initialize().


The documentation for this class was generated from the following files: