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
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
153     GetAlignment(
154         VOID
155         )
156     {
157         return m_CommonBufferAlignment;
158     }
159 
160     __inline
161     WDFDMAENABLER
162     GetHandle(
163         VOID
164         )
165     {
166         return (WDFDMAENABLER) GetObjectHandle();
167     }
168 
169     __inline
170     WDFDEVICE
171     GetDeviceHandle(
172         VOID
173         )
174     {
175 
176         return m_DeviceBase->GetHandle();
177     }
178 
179     __inline
180     size_t
181     GetMaxSGElements(
182         VOID
183         )
184     {
185         return m_MaxSGElements;
186     }
187 
188     __inline
189     VOID
190     SetMaxSGElements(
191         __in size_t MaximumSGElements
192         )
193     {
194         m_MaxSGElements = (ULONG) MaximumSGElements;
195     }
196 
197     __inline
198     WDF_DMA_PROFILE
199     GetProfile(
200         VOID
201         )
202     {
203         return m_Profile;
204     }
205 
206     __inline
207     BOOLEAN
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
228     IsBusMaster(
229         VOID
230         )
231     {
232         return m_IsBusMaster;
233     }
234 
235     __inline
236     BOOLEAN
237     IsPacketBased(
238         )
239     {
240         return m_IsScatterGather ? FALSE : TRUE ;
241     }
242 
243     __inline
244     FxDmaDescription*
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*
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*
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
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
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