ReactOS 0.4.16-dev-2633-g8dc9e50
dev_timings.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ATA Port Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: ATA PIO and DMA timings support
5 * COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
6 *
7 * REFERENCES: For more details refer to the
8 * "Intel ICH0~ICH5 Programmer's Reference Manual (PRM) 298600-004":
9 * "Determining a Drive's Transfer Rate Capabilities"
10 */
11
12/* INCLUDES *******************************************************************/
13
14#include "atapi.h"
15
16/* GLOBALS ********************************************************************/
17
18static const ULONG AtapModeToCycleTime[] =
19{
20 /* 0 1 2 3 4 PIO_MODE */
21 600, 383, 240, 180, 120,
22
23 /* 0 1 2 SWDMA_MODE */
24 960, 480, 240,
25
26 /* 0 1 2 MWDMA_MODE */
27 480, 150, 120,
28
29 /* 0 1 2 3 4 5 6 UDMA_MODE */
30 120, 80, 60, 45, 30, 20, 15
31};
32
33/* FUNCTIONS ******************************************************************/
34
35static
36VOID
39 _In_ ULONG AllowedModesMask)
40{
41 PIDENTIFY_DEVICE_DATA IdentifyData = &DevExt->IdentifyDeviceData;
42 ULONG SupportedMode, BestMode, CurrentMode, CycleTime;
43
44 /* Find the best possible PIO mode */
45 if (IdentifyData->TranslationFieldsValid & 0x2)
46 {
47 /* PIO 3-4 */
48 SupportedMode = IdentifyData->AdvancedPIOModes & 0x3;
49 SupportedMode <<= PIO_MODE(3);
50
51 /* The device is assumed to have PIO 0-2 */
52 SupportedMode |= PIO_MODE0 | PIO_MODE1 | PIO_MODE2;
53
54 SupportedMode &= AllowedModesMask;
55
56 if (IdentifyData->Capabilities.IordySupported)
57 CycleTime = IdentifyData->MinimumPIOCycleTimeIORDY;
58 else
59 CycleTime = IdentifyData->MinimumPIOCycleTime;
60
61 /*
62 * Any device that supports PIO 3 or above
63 * should support word 67 and word 68, but be defensive.
64 */
65 if (CycleTime == 0)
66 {
67 WARN("Device '%s' returned zero cycle time\n", DevExt->FriendlyName);
68 NT_VERIFY(_BitScanReverse(&BestMode, SupportedMode));
69
70 /* Fall back to the default value */
73 }
74 }
75 else
76 {
77 /* PIO 0-4 (maximum supported mode) */
78 SupportedMode = IdentifyData->ObsoleteWords51[0] >> 8;
79 if (SupportedMode > PIO_MODE(4))
80 SupportedMode = PIO_MODE(0);
81
82 /* Convert the maximum mode to a mask */
83 SupportedMode = (1 << (SupportedMode + 1)) - 1;
84 SupportedMode &= AllowedModesMask;
85
86 NT_VERIFY(_BitScanReverse(&BestMode, SupportedMode));
87
90 }
91 DevExt->TransferModeSupportedBitmap |= SupportedMode;
92 DevExt->MinimumPioCycleTime = CycleTime;
93
94 /*
95 * Since there is no way to obtain the current PIO mode from identify data
96 * we just look for the fastest supported mode.
97 */
98 NT_VERIFY(_BitScanReverse(&BestMode, SupportedMode));
99 CurrentMode = BestMode;
100 DevExt->TransferModeCurrentBitmap |= 1 << CurrentMode;
101}
102
103static
104VOID
107 _In_ ULONG AllowedModesMask)
108{
109 PIDENTIFY_DEVICE_DATA IdentifyData = &DevExt->IdentifyDeviceData;
110 ULONG SupportedMode, BestMode, CurrentMode, CycleTime;
111
113
114 /* Find the current active SWDMA mode */
115 CurrentMode = ((IdentifyData->ObsoleteWord62 & 0xFF00) >> 16) & 0x7;
116 if (CurrentMode != 0)
117 {
118 NT_VERIFY(_BitScanReverse(&CurrentMode, CurrentMode));
119 CurrentMode += SWDMA_MODE(0);
120
121 DevExt->TransferModeCurrentBitmap |= 1 << CurrentMode;
122 }
123
124 /* Find the best possible SWDMA mode */
125 SupportedMode = (IdentifyData->ObsoleteWord62 & 0x00FF) & 0x7;
126 SupportedMode <<= SWDMA_MODE(0);
127 SupportedMode &= AllowedModesMask;
128 if (SupportedMode != 0)
129 {
130 DevExt->TransferModeSupportedBitmap |= SupportedMode;
131
132 NT_VERIFY(_BitScanReverse(&BestMode, SupportedMode));
133
135 CycleTime = AtapModeToCycleTime[BestMode];
136 }
137
138 DevExt->MinimumSingleWordDmaCycleTime = CycleTime;
139}
140
141static
142VOID
145 _In_ ULONG AllowedModesMask)
146{
147 PIDENTIFY_DEVICE_DATA IdentifyData = &DevExt->IdentifyDeviceData;
148 ULONG SupportedMode, BestMode, CurrentMode, CycleTime;
149
151
152 /* Find the current active MWDMA mode */
153 CurrentMode = IdentifyData->MultiWordDMAActive & 0x7;
154 if (CurrentMode != 0)
155 {
156 NT_VERIFY(_BitScanReverse(&CurrentMode, CurrentMode));
157 CurrentMode += MWDMA_MODE(0);
158
159 DevExt->TransferModeCurrentBitmap |= 1 << CurrentMode;
160 }
161
162 /* Find the best possible MWDMA mode */
163 SupportedMode = IdentifyData->MultiWordDMASupport & 0x7;
164 SupportedMode <<= MWDMA_MODE(0);
165 SupportedMode &= AllowedModesMask;
166 if (SupportedMode != 0)
167 {
168 DevExt->TransferModeSupportedBitmap |= SupportedMode;
169
170 NT_VERIFY(_BitScanReverse(&BestMode, SupportedMode));
171
172 /* Prefer the minimum cycle time, if words 64-70 are valid */
173 if ((IdentifyData->TranslationFieldsValid & 0x2) &&
174 (IdentifyData->MinimumMWXferCycleTime != 0) &&
175 (IdentifyData->RecommendedMWXferCycleTime != 0))
176 {
177 CycleTime = IdentifyData->MinimumMWXferCycleTime;
178 }
179 else
180 {
182 CycleTime = AtapModeToCycleTime[BestMode];
183 }
184 }
185
186 DevExt->MinimumMultiWordDmaCycleTime = CycleTime;
187}
188
189static
190VOID
193 _In_ ULONG AllowedModesMask)
194{
195 PIDENTIFY_DEVICE_DATA IdentifyData = &DevExt->IdentifyDeviceData;
196 ULONG SupportedMode, BestMode, CurrentMode, CycleTime;
197
199
200 /* Word 88 is not valid */
201 if (!(IdentifyData->TranslationFieldsValid & 0x4))
202 goto Exit;
203
204 /* Find the current active UDMA mode */
205 CurrentMode = IdentifyData->UltraDMAActive & 0x7F;
206 if (CurrentMode != 0)
207 {
208 NT_VERIFY(_BitScanReverse(&CurrentMode, CurrentMode));
209 CurrentMode += UDMA_MODE(0);
210
211 DevExt->TransferModeCurrentBitmap |= 1 << CurrentMode;
212 }
213
214 /* Find the best possible UDMA mode */
215 SupportedMode = IdentifyData->UltraDMASupport & 0x7F;
216 SupportedMode <<= UDMA_MODE(0);
217 SupportedMode &= AllowedModesMask;
218 if (SupportedMode != 0)
219 {
220 DevExt->TransferModeSupportedBitmap |= SupportedMode;
221
222 NT_VERIFY(_BitScanReverse(&BestMode, SupportedMode));
223
225 CycleTime = AtapModeToCycleTime[BestMode];
226 }
227
228Exit:
229 DevExt->MinimumUltraDmaCycleTime = CycleTime;
230}
231
232static
233VOID
235 _In_ PATAPORT_PORT_DATA PortData,
237{
238 INFO("CH %lu: Device %u '%s'\n"
239 "Cycle time UDMA[%ld] MWDMA[%ld] SWDMA[%ld] PIO[%ld]\n"
240 "Supported modes 0x%08lX\n"
241 "Active modes 0x%08lX\n"
242 "Selected modes 0x%08lX\n"
243 "IOREADY %u\n",
244 PortData->PortNumber,
245 DevExt->Device.AtaScsiAddress.TargetId,
246 DevExt->FriendlyName,
247 (LONG)DevExt->MinimumUltraDmaCycleTime,
248 (LONG)DevExt->MinimumMultiWordDmaCycleTime,
249 (LONG)DevExt->MinimumSingleWordDmaCycleTime,
250 (LONG)DevExt->MinimumPioCycleTime,
251 DevExt->TransferModeSupportedBitmap,
252 DevExt->TransferModeCurrentBitmap,
253 DevExt->TransferModeSelectedBitmap,
254 DevExt->IdentifyDeviceData.Capabilities.IordySupported);
255}
256
257VOID
259 _In_ PATAPORT_PORT_DATA PortData,
260 _In_ BOOLEAN ForceCompatibleTimings)
261{
263 ULONG i;
266
267 if (ForceCompatibleTimings)
268 {
269 for (i = 0; i < ATA_MAX_DEVICE; ++i)
270 {
271 /* Fake device presence */
272 DeviceList[i] = &Config[i];
273
274 /* Disable DMA and select compatible timings */
275 Config[i].SupportedModes = PIO_MODE0;
276 Config[i].CurrentModes = PIO_MODE0;
277 Config[i].MinPioCycleTime = AtapModeToCycleTime[PIO_MODE(0)];
278 Config[i].MinSwDmaCycleTime = AtapModeToCycleTime[SWDMA_MODE(0)];
279 Config[i].MinMwDmaCycleTime = AtapModeToCycleTime[MWDMA_MODE(0)];
280 Config[i].IsFixedDisk = TRUE;
281 Config[i].IoReadySupported = FALSE;
282 Config[i].IsNewDevice = FALSE;
283 Config[i].FriendlyName = "";
284 }
285
286 /* Call the chipset driver */
287 PortData->SetTransferMode(PortData->ChannelContext, DeviceList);
288 return;
289 }
290
291 ChanExt = CONTAINING_RECORD(PortData, ATAPORT_CHANNEL_EXTENSION, PortData);
292
293 for (i = 0; i < ATA_MAX_DEVICE; ++i)
294 {
296 ULONG AllowedModesMask;
297
298 DevExt = AtaFdoFindDeviceByPath(ChanExt,
299 AtaMarshallScsiAddress(PortData->PortNumber, i, 0),
300 NULL);
301 if (!DevExt)
302 continue;
303
304 DevExt->TransferModeCurrentBitmap = 0;
305 DevExt->TransferModeSupportedBitmap = 0;
306
307 AllowedModesMask = DevExt->TransferModeUserAllowedMask;
308 AllowedModesMask &= DevExt->TransferModeAllowedMask;
309 /* Mode cannot be slower than PIO0 */
310 AllowedModesMask |= PIO_MODE0;
311
312 AtaTimQueryPioModeSupport(DevExt, AllowedModesMask);
313 AtaTimQuerySwDmaModeSupport(DevExt, AllowedModesMask);
314 AtaTimQueryMwDmaModeSupport(DevExt, AllowedModesMask);
315 AtaTimQueryUDmaModeSupport(DevExt, AllowedModesMask);
316
317 DeviceList[i] = &Config[i];
318 Config[i].CurrentModes = DevExt->TransferModeCurrentBitmap;
319 Config[i].SupportedModes = DevExt->TransferModeSupportedBitmap;
320 Config[i].MinPioCycleTime = DevExt->MinimumPioCycleTime;
321 Config[i].MinSwDmaCycleTime = DevExt->MinimumSingleWordDmaCycleTime;
322 Config[i].MinMwDmaCycleTime = DevExt->MinimumMultiWordDmaCycleTime;
323 Config[i].IsFixedDisk = !IS_ATAPI(&DevExt->Device);
324 Config[i].IoReadySupported = !!DevExt->IdentifyDeviceData.Capabilities.IordySupported;
325 Config[i].IsNewDevice = !(DevExt->Device.DeviceFlags & DEVICE_PNP_STARTED);
326 Config[i].FriendlyName = DevExt->FriendlyName;
327 }
328
329 /* Call the chipset driver */
330 PortData->SetTransferMode(PortData->ChannelContext, DeviceList);
331
332 /* Save the result */
333 for (i = 0; i < ATA_MAX_DEVICE; ++i)
334 {
335 PCHANNEL_DEVICE_CONFIG DeviceConfig = DeviceList[i];
337
338 if (!DeviceConfig)
339 continue;
340
341 DevExt = AtaFdoFindDeviceByPath(ChanExt,
342 AtaMarshallScsiAddress(PortData->PortNumber, i, 0),
343 NULL);
344 ASSERT(DevExt);
345
346 DevExt->TransferModeSelectedBitmap = 1 << DeviceConfig->PioMode;
347 if (DeviceConfig->DmaMode != PIO_MODE(0))
348 {
349 DevExt->TransferModeSelectedBitmap |= 1 << DeviceConfig->DmaMode;
350 }
351
352 AtaTimDumpTimingInfo(PortData, DevExt);
353 }
354}
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
unsigned char BOOLEAN
Definition: actypes.h:127
#define IDE_ACPI_TIMING_MODE_NOT_SUPPORTED
Definition: ata_shared.h:42
#define ATA_MAX_DEVICE
Definition: ata_shared.h:15
#define PIO_MODE(n)
Definition: ata_user.h:36
#define MWDMA_MODE(n)
Definition: ata_user.h:38
#define SWDMA_MODE(n)
Definition: ata_user.h:37
#define UDMA_MODE(n)
Definition: ata_user.h:39
FORCEINLINE ATA_SCSI_ADDRESS AtaMarshallScsiAddress(_In_ ULONG PathId, _In_ ULONG TargetId, _In_ ULONG Lun)
Definition: atapi.h:585
DECLSPEC_NOINLINE_FROM_PAGED PATAPORT_DEVICE_EXTENSION AtaFdoFindDeviceByPath(_In_ PATAPORT_CHANNEL_EXTENSION ChanExt, _In_ ATA_SCSI_ADDRESS AtaScsiAddress, _In_ PVOID ReferenceTag)
Definition: fdo.c:614
#define DEVICE_PNP_STARTED
Definition: atapi.h:92
#define IS_ATAPI(Device)
Definition: atapi.h:176
#define WARN(fmt,...)
Definition: precomp.h:61
static VOID AtaTimQueryPioModeSupport(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG AllowedModesMask)
Definition: dev_timings.c:37
static VOID AtaTimDumpTimingInfo(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_timings.c:234
static const ULONG AtapModeToCycleTime[]
Definition: dev_timings.c:18
static VOID AtaTimQuerySwDmaModeSupport(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG AllowedModesMask)
Definition: dev_timings.c:105
static VOID AtaTimQueryUDmaModeSupport(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG AllowedModesMask)
Definition: dev_timings.c:191
static VOID AtaTimQueryMwDmaModeSupport(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG AllowedModesMask)
Definition: dev_timings.c:143
VOID AtaPortSelectTimings(_In_ PATAPORT_PORT_DATA PortData, _In_ BOOLEAN ForceCompatibleTimings)
Definition: dev_timings.c:258
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
PDEVICE_LIST DeviceList
Definition: utils.c:27
#define INFO
Definition: debug.h:89
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define PIO_MODE0
Definition: ide.h:277
#define PIO_MODE2
Definition: ide.h:279
#define PIO_MODE1
Definition: ide.h:278
#define ASSERT(a)
Definition: mode.c:44
#define _In_
Definition: no_sal2.h:158
long LONG
Definition: pedump.c:60
unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask)
Definition: intrin_arm.h:180
static void Exit(void)
Definition: sock.c:1330
ULONG TransferModeSelectedBitmap
Definition: atapi.h:527
ULONG TransferModeCurrentBitmap
Definition: atapi.h:509
IDENTIFY_DEVICE_DATA IdentifyDeviceData
Definition: atapi.h:474
ULONG TransferModeSupportedBitmap
Definition: atapi.h:518
ULONG MinimumSingleWordDmaCycleTime
Definition: atapi.h:543
ATAPORT_IO_CONTEXT Device
Definition: atapi.h:457
ULONG MinimumMultiWordDmaCycleTime
Definition: atapi.h:544
ULONG TransferModeAllowedMask
Definition: atapi.h:533
ULONG TransferModeUserAllowedMask
Definition: atapi.h:503
ULONG DeviceFlags
Definition: atapi.h:81
USHORT RecommendedMWXferCycleTime
Definition: ata.h:67
USHORT ObsoleteWord62
Definition: ata.h:61
USHORT MultiWordDMASupport
Definition: ata.h:62
USHORT MultiWordDMAActive
Definition: ata.h:63
USHORT ObsoleteWords51[2]
Definition: ata.h:45
USHORT MinimumMWXferCycleTime
Definition: ata.h:66
USHORT TranslationFieldsValid
Definition: ata.h:46
USHORT UltraDMAActive
Definition: ata.h:236
USHORT MinimumPIOCycleTime
Definition: ata.h:68
struct _IDENTIFY_DEVICE_DATA::@2045 Capabilities
USHORT UltraDMASupport
Definition: ata.h:235
USHORT AdvancedPIOModes
Definition: ata.h:64
USHORT MinimumPIOCycleTimeIORDY
Definition: ata.h:69
ULONG CycleTime
Definition: svw_pata.c:43
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG Config
Definition: wdfchildlist.h:476
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3304