1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxDmaEnabler.hpp 8 9 Abstract: 10 11 WDF DMA Enabler support 12 13 Environment: 14 15 Kernel mode only. 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #ifndef __FX_DMA_ENABLER_HPP__ 25 #define __FX_DMA_ENABLER_HPP__ 26 27 #include "fxdmaenablercallbacks.hpp" 28 29 // 30 // Dma Description structure 31 // 32 typedef struct _FxDmaDescription { 33 34 DEVICE_DESCRIPTION DeviceDescription; 35 36 PDMA_ADAPTER AdapterObject; 37 38 // 39 // The size of a preallocated lookaside list for this DMA adapter 40 // 41 size_t PreallocatedSGListSize; 42 43 size_t MaximumFragmentLength; 44 45 ULONG NumberOfMapRegisters; 46 47 } FxDmaDescription; 48 49 enum FxDuplexDmaDescriptionType { 50 FxDuplexDmaDescriptionTypeRead = 0, 51 FxDuplexDmaDescriptionTypeWrite, 52 FxDuplexDmaDescriptionTypeMax, 53 }; 54 55 // 56 // Make sure the two enums which match to the channels in the enabler match 57 // corresponding values. 58 // 59 60 C_ASSERT(((ULONG) FxDuplexDmaDescriptionTypeRead) == ((ULONG) WdfDmaDirectionReadFromDevice)); 61 C_ASSERT(((ULONG) FxDuplexDmaDescriptionTypeWrite) == ((ULONG) WdfDmaDirectionWriteToDevice)); 62 63 // 64 // Declare the FxDmaEnabler class 65 // 66 class FxDmaEnabler : public FxNonPagedObject { 67 68 friend class FxDmaTransactionBase; 69 friend class FxDmaPacketTransaction; 70 friend class FxDmaScatterGatherTransaction; 71 friend class FxDmaSystemTransaction; 72 73 public: 74 75 FxDmaEnabler( 76 __in PFX_DRIVER_GLOBALS FxDriverGlobals 77 ); 78 79 ~FxDmaEnabler(); 80 81 virtual 82 BOOLEAN 83 Dispose( 84 VOID 85 ); 86 87 _Must_inspect_result_ 88 NTSTATUS 89 Initialize( 90 __in PWDF_DMA_ENABLER_CONFIG Config, 91 __inout FxDeviceBase *Device 92 ); 93 94 _Must_inspect_result_ 95 NTSTATUS 96 ConfigureSystemAdapter( 97 __in PWDF_DMA_SYSTEM_PROFILE_CONFIG Config, 98 __in WDF_DMA_DIRECTION ConfigDirection 99 ); 100 101 VOID 102 AllocateCommonBuffer( 103 __in size_t Length, 104 __deref_out_opt PVOID * BufferVA, 105 __out PHYSICAL_ADDRESS * BufferPA 106 ); 107 108 VOID 109 FreeCommonBuffer( 110 __in size_t Length, 111 __in PVOID BufferVA, 112 __in PHYSICAL_ADDRESS BufferPA 113 ); 114 115 _Must_inspect_result_ 116 NTSTATUS 117 PowerUp( 118 VOID 119 ); 120 121 _Must_inspect_result_ 122 NTSTATUS 123 PowerDown( 124 VOID 125 ); 126 127 VOID 128 RevokeResources( 129 VOID 130 ); 131 132 VOID 133 InitializeTransferContext( 134 __out PVOID Context, 135 __in WDF_DMA_DIRECTION Direction 136 ); 137 138 __inline 139 size_t GetMaximumLength(VOID)140 GetMaximumLength( 141 VOID 142 ) 143 { 144 // 145 // This value is same for all the channels and equal to the value 146 // provided in the DMA_ENABLER_CONFIG. 147 // 148 return GetReadDmaDescription()->DeviceDescription.MaximumLength; 149 } 150 151 __inline 152 size_t GetAlignment(VOID)153 GetAlignment( 154 VOID 155 ) 156 { 157 return m_CommonBufferAlignment; 158 } 159 160 __inline 161 WDFDMAENABLER GetHandle(VOID)162 GetHandle( 163 VOID 164 ) 165 { 166 return (WDFDMAENABLER) GetObjectHandle(); 167 } 168 169 __inline 170 WDFDEVICE GetDeviceHandle(VOID)171 GetDeviceHandle( 172 VOID 173 ) 174 { 175 176 return m_DeviceBase->GetHandle(); 177 } 178 179 __inline 180 size_t GetMaxSGElements(VOID)181 GetMaxSGElements( 182 VOID 183 ) 184 { 185 return m_MaxSGElements; 186 } 187 188 __inline 189 VOID SetMaxSGElements(__in size_t MaximumSGElements)190 SetMaxSGElements( 191 __in size_t MaximumSGElements 192 ) 193 { 194 m_MaxSGElements = (ULONG) MaximumSGElements; 195 } 196 197 __inline 198 WDF_DMA_PROFILE GetProfile(VOID)199 GetProfile( 200 VOID 201 ) 202 { 203 return m_Profile; 204 } 205 206 __inline 207 BOOLEAN SupportsChainedMdls(VOID)208 SupportsChainedMdls( 209 VOID 210 ) 211 { 212 // 213 // The only case where we don't support chained MDLS is DMAV2 214 // with packet mode. 215 // 216 217 if ((UsesDmaV3() == false) && 218 (m_IsBusMaster == TRUE) && 219 (m_IsScatterGather == FALSE)) { 220 return false; 221 } else { 222 return true; 223 } 224 } 225 226 __inline 227 BOOLEAN IsBusMaster(VOID)228 IsBusMaster( 229 VOID 230 ) 231 { 232 return m_IsBusMaster; 233 } 234 235 __inline 236 BOOLEAN IsPacketBased()237 IsPacketBased( 238 ) 239 { 240 return m_IsScatterGather ? FALSE : TRUE ; 241 } 242 243 __inline 244 FxDmaDescription* GetDmaDescription(__in WDF_DMA_DIRECTION Direction)245 GetDmaDescription( 246 __in WDF_DMA_DIRECTION Direction 247 ) 248 { 249 if (m_IsDuplexTransfer) { 250 return &m_DuplexAdapterInfo[Direction]; 251 } 252 else { 253 return &m_SimplexAdapterInfo; 254 } 255 } 256 257 258 __inline 259 FxDmaDescription* GetWriteDmaDescription(VOID)260 GetWriteDmaDescription( 261 VOID 262 ) 263 { 264 if (m_IsDuplexTransfer) { 265 return &m_DuplexAdapterInfo[FxDuplexDmaDescriptionTypeWrite]; 266 } else { 267 return &m_SimplexAdapterInfo; 268 } 269 } 270 271 __inline 272 FxDmaDescription* GetReadDmaDescription(VOID)273 GetReadDmaDescription( 274 VOID 275 ) 276 { 277 if (m_IsDuplexTransfer) { 278 return &m_DuplexAdapterInfo[FxDuplexDmaDescriptionTypeRead]; 279 } else { 280 return &m_SimplexAdapterInfo; 281 } 282 } 283 284 BOOLEAN UsesDmaV3(VOID)285 UsesDmaV3( 286 VOID 287 ) 288 { 289 FxDmaDescription* description; 290 291 // 292 // It doesn't matter which direction we use below. Direction is 293 // ignored for the simplex enabler, and will be the same for both 294 // channels in a duplex enabler. 295 // 296 297 description = GetDmaDescription(WdfDmaDirectionReadFromDevice); 298 299 return description->DeviceDescription.Version == DEVICE_DESCRIPTION_VERSION3; 300 } 301 302 USHORT GetTransferContextSize(VOID)303 GetTransferContextSize( 304 VOID 305 ) 306 { 307 return UsesDmaV3() ? DMA_TRANSFER_CONTEXT_SIZE_V1 : 0; 308 } 309 310 public: 311 // 312 // Link into list of FxDmaEnabler pointers maintained by the pnp package. 313 // 314 FxTransactionedEntry m_TransactionLink; 315 316 protected: 317 318 PDEVICE_OBJECT m_FDO; 319 320 PDEVICE_OBJECT m_PDO; 321 322 union { 323 // 324 // Used if the dma profile is not duplex. Common for both read & write. 325 // All the information specific to the channel are stored in the struct. 326 // 327 FxDmaDescription m_SimplexAdapterInfo; 328 329 // 330 // Used if the dma profile is duplex. 331 // 332 FxDmaDescription m_DuplexAdapterInfo[FxDuplexDmaDescriptionTypeMax]; 333 }; 334 335 // 336 // The profile of the DMA enabler. 337 // 338 WDF_DMA_PROFILE m_Profile; 339 340 // 341 // Whether the enabler object is added to the device enabler list. 342 // 343 BOOLEAN m_IsAdded : 1; 344 345 // 346 // Whether the DMA enabler has been configured with DMA resources & has its 347 // adapters. 348 // 349 BOOLEAN m_IsConfigured : 1; 350 351 // 352 // The DMA profile broken out into individual flags. 353 // 354 BOOLEAN m_IsBusMaster : 1; 355 356 BOOLEAN m_IsScatterGather : 1; 357 358 BOOLEAN m_IsDuplexTransfer : 1; 359 360 // 361 // Has the preallocated scatter gather list (single list or lookaside, 362 // depending on profile) been allocated. Indicates initialization state 363 // of m_SGList below. 364 // 365 BOOLEAN m_IsSGListAllocated: 1; 366 367 // 368 // This value is larger of aligment value returned by HAL(which is always 1) 369 // and the alignment value set on the device by WdfDeviceSetAlignmentRequirement. 370 // 371 ULONG m_CommonBufferAlignment; 372 373 // 374 // The maximum DMA transfer the enabler should support (saved from the enabler 375 // config) 376 // 377 ULONG m_MaximumLength; 378 379 ULONG m_MaxSGElements; 380 381 // 382 // The size of the preallocated SGList entries, in bytes. This is for entries 383 // on the lookaside list or the single entry list. 384 // 385 size_t m_SGListSize; 386 387 // 388 // Storage for scatter gather lists. Whether the lookaside or the single entry 389 // the size in bytes is described by m_SGListSize 390 // 391 // The m_IsSGListAllocated bit above indicates whether we've 392 // initialized this structure or not. 393 // 394 union { 395 396 // 397 // For the scatter gather profile we have a lookaside list of SGLists 398 // We allocate these dynamically because (a) we can be mapping 399 // multiple transactions in parallel and (b) the number of map registers 400 // for SG DMA may be very large and we don't necessarily need one per 401 // transaction at all times 402 // 403 // For duplex channels, the entry size is larger of read & write channels. 404 // 405 struct { 406 NPAGED_LOOKASIDE_LIST Lookaside; 407 } ScatterGatherProfile; 408 409 // 410 // A single SGList for use with system DMA transfers. We can use a single 411 // list because (a) there is only one system DMA transaction being mapped 412 // at any given time (for this adapter) and (b) we don't use the physical 413 // addresses or give them to the driver so they don't need to be preserved 414 // very long (the list is only so the HAL has enough scratch space to tell 415 // the HAL DMA extension which PA's comprise the transfer) 416 // 417 struct { 418 PSCATTER_GATHER_LIST List; 419 } SystemProfile; 420 421 // 422 // NOTE: there is no preallocated entry for packet based bus mastering DMA 423 // because we could be mapping multiple transactions in parallel but 424 // the size of the SGList is static and can be allocated on the stack 425 // 426 427 } m_SGList; 428 429 private: 430 // 431 // Power-related callbacks. 432 // 433 FxEvtDmaEnablerFillCallback m_EvtDmaEnablerFill; 434 FxEvtDmaEnablerFlushCallback m_EvtDmaEnablerFlush; 435 FxEvtDmaEnablerEnableCallback m_EvtDmaEnablerEnable; 436 FxEvtDmaEnablerDisableCallback m_EvtDmaEnablerDisable; 437 FxEvtDmaEnablerSelfManagedIoStartCallback m_EvtDmaEnablerSelfManagedIoStart; 438 FxEvtDmaEnablerSelfManagedIoStopCallback m_EvtDmaEnablerSelfManagedIoStop; 439 440 // 441 // Note that these fields form an informal state engine. 442 // 443 BOOLEAN m_DmaEnablerFillFailed; 444 BOOLEAN m_DmaEnablerEnableFailed; 445 BOOLEAN m_DmaEnablerSelfManagedIoStartFailed; 446 447 _Must_inspect_result_ 448 NTSTATUS 449 ConfigureBusMasterAdapters( 450 __in PDEVICE_DESCRIPTION DeviceDescription, 451 __in PWDF_DMA_ENABLER_CONFIG Config 452 ); 453 454 _Must_inspect_result_ 455 NTSTATUS 456 ConfigureDmaAdapter( 457 __in PDEVICE_DESCRIPTION DeviceDescription, 458 __in WDF_DMA_DIRECTION ConfigDirection 459 ); 460 461 _Must_inspect_result_ 462 NTSTATUS 463 InitializeResources( 464 __inout FxDmaDescription *AdapterInfo 465 ); 466 467 VOID 468 ReleaseResources( 469 VOID 470 ); 471 472 VOID 473 FreeResources( 474 __inout FxDmaDescription *AdapterInfo 475 ); 476 477 }; // end of class 478 479 #endif // _FXDMAENABLER_HPP_ 480