ReactOS 0.4.16-dev-2633-g8dc9e50
svw_pata.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ATA Bus Driver
3 * LICENSE: BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause)
4 * PURPOSE: ServerWorks/Broadcom ATA controller minidriver
5 * COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8/*
9 * Adapted from the FreeBSD ata-serverworks driver
10 * Copyright (c) 1998-2008 Søren Schmidt <sos@FreeBSD.org>
11 */
12
13/* INCLUDES *******************************************************************/
14
15#include "pciidex.h"
16
17/* GLOBALS ********************************************************************/
18
19#define PCI_DEV_OSB4_IDE 0x0211
20#define PCI_DEV_CSB5_IDE 0x0212
21#define PCI_DEV_CSB6_IDE 0x0213
22#define PCI_DEV_CSB6_IDE_THIRD 0x0217
23#define PCI_DEV_HT1000_IDE 0x0214
24
25#define PCI_DEV_OSB4_BRIDGE 0x0210
26
27#define SVW_REG_PIO_TIMING 0x40
28#define SVW_REG_DMA_TIMING 0x44
29#define SVW_REG_PIO_MODE 0x4A // CSB5 and later
30#define SVW_REG_UDMA_ENABLE 0x54
31#define SVW_REG_UDMA_MODE 0x56
32#define SVW_REG_UDMA_CONTROL 0x5A // Absent on ATI
33
34#define SVW_UDMA_CTRL_MODE_MASK 0x03
35#define SVW_UDMA_CTRL_DISABLE 0x40
36
37#define SVW_UDMA_CTRL_MODE_UDMA4 0x02
38#define SVW_UDMA_CTRL_MODE_UDMA5 0x03
39
40static const struct
41{
44} SvwPioTimings[] =
45{
46 { 0x5D, 600 }, // 0
47 { 0x47, 390 }, // 1
48 { 0x34, 270 }, // 2
49 { 0x22, 180 }, // 3
50 { 0x20, 120 }, // 4
51};
52
53static const struct
54{
58{
59 { 0x77, 480 }, // 0
60 { 0x21, 150 }, // 1
61 { 0x20, 120 }, // 2
62};
63
64/* FUNCTIONS ******************************************************************/
65
66static
67VOID
71{
72 ULONG Mode;
73
74 /* PIO speed */
75 for (Mode = Device->PioMode; Mode > PIO_MODE(0); Mode--)
76 {
77 if (!(Device->SupportedModes & (1 << Mode)))
78 continue;
79
80 if (SvwPioTimings[Mode].CycleTime >= Device->MinPioCycleTime)
81 break;
82 }
83 if (Mode != Device->PioMode)
84 INFO("CH %lu: Downgrade PIO speed from %lu to %lu\n", Channel, Device->PioMode, Mode);
85 Device->PioMode = Mode;
86
87 /* UDMA works independently of any PIO mode */
88 if (Device->DmaMode == PIO_MODE(0) || Device->DmaMode >= UDMA_MODE(0))
89 return;
90
91 /* DMA speed */
92 for (Mode = Device->DmaMode; Mode > PIO_MODE(0); Mode--)
93 {
94 if (!(Device->SupportedModes & ~PIO_ALL & (1 << Mode)))
95 continue;
96
97 ASSERT((1 << Mode) & MWDMA_ALL);
98
99 if (SvwMwDmaTimings[Mode - MWDMA_MODE(0)].CycleTime >= Device->MinMwDmaCycleTime)
100 break;
101 }
102 if (Mode != Device->DmaMode)
103 {
104 if (Mode == PIO_MODE(0))
105 WARN("CH %lu: Too slow device '%s', disabling DMA\n", Channel, Device->FriendlyName);
106 else
107 INFO("CH %lu: Downgrade DMA speed from %lu to %lu\n", Channel, Device->DmaMode, Mode);
108 }
109 Device->DmaMode = Mode;
110}
111
112VOID
114 _In_ PATA_CONTROLLER Controller,
117{
118 USHORT PioModeReg, UdmaModeReg;
119 UCHAR UdmaEnableReg;
120 ULONG i, PioTimReg, DmaTimReg;
121
122 if (Controller->Pci.DeviceID != PCI_DEV_OSB4_IDE)
123 PioModeReg = PciRead16(Controller, SVW_REG_PIO_MODE);
124 else
125 PioModeReg = 0;
126
127 PioTimReg = PciRead32(Controller, SVW_REG_PIO_TIMING);
128 DmaTimReg = PciRead32(Controller, SVW_REG_DMA_TIMING);
129 UdmaEnableReg = PciRead8(Controller, SVW_REG_UDMA_ENABLE);
130 UdmaModeReg = PciRead16(Controller, SVW_REG_UDMA_MODE);
131
132 INFO("CH %lu: Config (before)\n"
133 "DMA Timing %08lX\n"
134 "PIO Timing %08lX\n"
135 "PIO Mode %04X\n"
136 "UDMA Mode %04X\n",
137 "UDMA Enable %02X\n",
138 Channel,
139 DmaTimReg,
140 PioTimReg,
141 PioModeReg,
142 UdmaModeReg,
143 UdmaEnableReg);
144
145 for (i = 0; i < MAX_IDE_DEVICE; ++i)
146 {
148 const ULONG DeviceIndex = (Channel << 1) + i; // 0 1 2 3
149 const ULONG Shift = (DeviceIndex ^ 1) << 3; // 8 0 24 16
150
151 UdmaModeReg &= ~(0x0F << (DeviceIndex << 2));
152 UdmaEnableReg &= ~(0x01 << DeviceIndex);
153
154 if (!Device)
155 continue;
156
157 /* Make sure that the selected PIO and DMA speeds match the cycle time */
159
160 /* UDMA timings */
161 if (Device->DmaMode >= UDMA_MODE(0))
162 {
163 ULONG ModeIndex = Device->DmaMode - UDMA_MODE(0);
164
165 UdmaModeReg |= ModeIndex << (DeviceIndex << 2);
166 UdmaEnableReg |= 1 << DeviceIndex;
167
168 DmaTimReg &= ~(0xFF << Shift);
169 DmaTimReg |= SvwMwDmaTimings[2].Value << Shift;
170 }
171 /* DMA timings */
172 else if (Device->DmaMode != PIO_MODE(0))
173 {
174 ULONG ModeIndex = Device->DmaMode - MWDMA_MODE(0);
175
176 DmaTimReg &= ~(0xFF << Shift);
177 DmaTimReg |= SvwMwDmaTimings[ModeIndex].Value << Shift;
178 }
179
180 /* PIO timings */
181 PioModeReg &= ~(0x0F << (DeviceIndex << 2));
182 PioModeReg |= Device->PioMode << (DeviceIndex << 2);
183
184 PioTimReg &= ~(0xFF << Shift);
185 PioTimReg |= SvwPioTimings[Device->PioMode].Value << Shift;
186 }
187
188 PciWrite32(Controller, SVW_REG_PIO_TIMING, PioTimReg);
189
190 if (Controller->Pci.DeviceID != PCI_DEV_OSB4_IDE)
191 PciWrite16(Controller, SVW_REG_PIO_MODE, PioModeReg);
192
193 PciWrite32(Controller, SVW_REG_DMA_TIMING, DmaTimReg);
194 PciWrite16(Controller, SVW_REG_UDMA_MODE, UdmaModeReg);
195 PciWrite8(Controller, SVW_REG_UDMA_ENABLE, UdmaEnableReg);
196
197 INFO("CH %lu: Config (after)\n"
198 "DMA Timing %08lX\n"
199 "PIO Timing %08lX\n"
200 "PIO Mode %04X\n"
201 "UDMA Mode %04X\n",
202 "UDMA Enable %02X\n",
203 Channel,
204 DmaTimReg,
205 PioTimReg,
206 PioModeReg,
207 UdmaModeReg,
208 UdmaEnableReg);
209}
210
211CODE_SEG("PAGE")
214 _In_ PATA_CONTROLLER Controller,
216{
217 UCHAR UdmaModeReg;
218
219 PAGED_CODE();
220
221 UdmaModeReg = PciRead8(Controller, SVW_REG_UDMA_MODE + Channel);
222
223 /* Check mode settings, see if UDMA3 or higher mode is active */
224 return ((UdmaModeReg & 0x07) > 2) || ((UdmaModeReg & 0x70) > 0x20);
225}
226
227static
234{
235 ULONG Value;
236
238
239 if (PciConfig->VendorID != PCI_VEN_SERVERWORKS ||
240 PciConfig->DeviceID != PCI_DEV_OSB4_BRIDGE)
241 {
242 return FALSE;
243 }
244
246 BusNumber,
248 &Value,
249 0x64,
250 sizeof(Value));
251 Value &= ~0x00002000; // Disable 600ns interrupt mask
252 Value |= 0x00004000; // Enable UDMA/33 support
254 BusNumber,
256 &Value,
257 0x64,
258 sizeof(Value));
259 return TRUE;
260}
261
262static
263VOID
265 _In_ PATA_CONTROLLER Controller)
266{
267 if (Controller->Pci.DeviceID == PCI_DEV_OSB4_IDE)
268 {
270 }
271 else
272 {
273 PCHANNEL_DATA_COMMON ChanData = Controller->Channels[0];
274 UCHAR UdmaCtrlReg = PciRead8(Controller, SVW_REG_UDMA_CONTROL);
275
277 if (ChanData->TransferModeSupported & UDMA_MODE5)
278 UdmaCtrlReg |= SVW_UDMA_CTRL_MODE_UDMA5;
279 else
280 UdmaCtrlReg |= SVW_UDMA_CTRL_MODE_UDMA4;
281
282 PciWrite8(Controller, SVW_REG_UDMA_CONTROL, UdmaCtrlReg);
283 }
284}
285
286CODE_SEG("PAGE")
289 _Inout_ PATA_CONTROLLER Controller)
290{
292 ULONG i, SupportedMode;
293 BOOLEAN No64KDma = FALSE;
294
295 PAGED_CODE();
296 ASSERT(Controller->Pci.VendorID == PCI_VEN_SERVERWORKS);
297
298 switch (Controller->Pci.DeviceID)
299 {
300 case PCI_DEV_OSB4_IDE:
301 /* UDMA is supported but its use is discouraged */
302 SupportedMode = PIO_ALL | MWDMA_ALL;
303
304 No64KDma = TRUE;
305 break;
306
307 case PCI_DEV_CSB5_IDE:
308 if (Controller->Pci.RevisionID < 0x92)
309 SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 4);
310 else
311 SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
312 Controller->Flags |= CTRL_FLAG_DMA_INTERRUPT;
313 break;
314
316 SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 4);
317 Controller->MaxChannels = 1;
318 break;
319
320 case PCI_DEV_CSB6_IDE:
321 SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
322 break;
323
325 SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
326 Controller->MaxChannels = 1;
327 No64KDma = TRUE;
328 break;
329
330 default:
331 return STATUS_NO_MATCH;
332 }
333
334 Status = PciIdeCreateChannelData(Controller, 0);
335 if (!NT_SUCCESS(Status))
336 return Status;
337
338 Controller->Start = SvwPataControllerStart;
339
340 for (i = 0; i < Controller->MaxChannels; ++i)
341 {
342 PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
343
344 if (No64KDma)
345 ChanData->MaximumTransferLength = PCIIDE_PRD_LIMIT - 0x4000;
346
347 ChanData->SetTransferMode = SvwSetTransferMode;
348 ChanData->TransferModeSupported = SupportedMode;
349
350 /* Check for 80-conductor cable */
351 if ((ChanData->TransferModeSupported & UDMA_80C_ALL) && !SvwHasUdmaCable(Controller, i))
352 {
353 INFO("CH %lu: BIOS hasn't selected mode faster than UDMA 2, "
354 "assume 40-conductor cable\n",
355 ChanData->Channel);
356 ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
357 }
358 }
359
360 return STATUS_SUCCESS;
361}
#define PAGED_CODE()
#define CODE_SEG(...)
unsigned char BOOLEAN
Definition: actypes.h:127
#define MWDMA_ALL
Definition: ata_user.h:27
#define PIO_MODE(n)
Definition: ata_user.h:36
#define MWDMA_MODE(n)
Definition: ata_user.h:38
#define PIO_ALL
Definition: ata_user.h:19
#define UDMA_MODE(n)
Definition: ata_user.h:39
LONG NTSTATUS
Definition: precomp.h:26
#define WARN(fmt,...)
Definition: precomp.h:61
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
PDEVICE_LIST DeviceList
Definition: utils.c:27
#define INFO
Definition: debug.h:89
Status
Definition: gdiplustypes.h:25
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
ULONG NTAPI HalSetBusDataByOffset(IN BUS_DATA_TYPE BusDataType, IN ULONG BusNumber, IN ULONG SlotNumber, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length)
Definition: bus.c:123
ULONG NTAPI HalGetBusDataByOffset(IN BUS_DATA_TYPE BusDataType, IN ULONG BusNumber, IN ULONG SlotNumber, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length)
Definition: bus.c:73
_In_ ULONG Mode
Definition: hubbusif.h:303
#define MAX_IDE_DEVICE
Definition: ide.h:32
#define UDMA_MODE5
Definition: ide.h:296
#define ASSERT(a)
Definition: mode.c:44
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
#define STATUS_NO_MATCH
Definition: ntstatus.h:873
#define UDMA_MODES(MinMode, MaxMode)
Definition: pata.h:49
#define PCIIDE_PRD_LIMIT
Definition: pata.h:215
#define UDMA_80C_ALL
Definition: pata.h:41
#define PCI_VEN_SERVERWORKS
Definition: pata.h:16
NTSTATUS PciIdeCreateChannelData(_In_ PATA_CONTROLLER Controller, _In_ ULONG HwExtensionSize)
BOOLEAN PciFindDevice(_In_ __callback PATA_PCI_MATCH_FN MatchFunction, _In_ PVOID Context)
Definition: pciidex.c:13
FORCEINLINE UCHAR PciRead8(_In_ PATA_CONTROLLER Controller, _In_ ULONG ConfigDataOffset)
Definition: pciidex.h:847
_In_ ULONG _In_ PCI_SLOT_NUMBER PciSlot
Definition: pciidex.h:66
_In_ ULONG Channel
Definition: pciidex.h:74
FORCEINLINE VOID PciWrite16(_In_ PATA_CONTROLLER Controller, _In_ ULONG ConfigDataOffset, _In_ USHORT Value)
Definition: pciidex.h:893
FORCEINLINE VOID PciWrite8(_In_ PATA_CONTROLLER Controller, _In_ ULONG ConfigDataOffset, _In_ UCHAR Value)
Definition: pciidex.h:883
_In_ ULONG BusNumber
Definition: pciidex.h:65
FORCEINLINE VOID PciWrite32(_In_ PATA_CONTROLLER Controller, _In_ ULONG ConfigDataOffset, _In_ ULONG Value)
Definition: pciidex.h:903
FORCEINLINE USHORT PciRead16(_In_ PATA_CONTROLLER Controller, _In_ ULONG ConfigDataOffset)
Definition: pciidex.h:859
#define CTRL_FLAG_DMA_INTERRUPT
Definition: pciidex.h:230
CHANNEL_SET_MODE_EX SvwSetTransferMode
Definition: pciidex.h:813
_In_ ULONG _In_ PCI_SLOT_NUMBER _In_ PPCI_COMMON_HEADER PciConfig
Definition: pciidex.h:67
FORCEINLINE ULONG PciRead32(_In_ PATA_CONTROLLER Controller, _In_ ULONG ConfigDataOffset)
Definition: pciidex.h:871
unsigned short USHORT
Definition: pedump.c:61
@ PCIConfiguration
Definition: miniport.h:93
#define STATUS_SUCCESS
Definition: shellext.h:65
_In_ PVOID Context
Definition: storport.h:2269
ULONG TransferModeSupported
Definition: pciidex.h:250
union _PCI_SLOT_NUMBER::@4410 u
#define PCI_DEV_CSB5_IDE
Definition: svw_pata.c:20
UCHAR Value
Definition: svw_pata.c:42
#define PCI_DEV_HT1000_IDE
Definition: svw_pata.c:23
#define SVW_UDMA_CTRL_MODE_UDMA4
Definition: svw_pata.c:37
#define PCI_DEV_CSB6_IDE
Definition: svw_pata.c:21
static VOID SvwPataControllerStart(_In_ PATA_CONTROLLER Controller)
Definition: svw_pata.c:264
#define PCI_DEV_OSB4_IDE
Definition: svw_pata.c:19
#define SVW_UDMA_CTRL_DISABLE
Definition: svw_pata.c:35
static const struct @1175 SvwMwDmaTimings[]
#define SVW_UDMA_CTRL_MODE_UDMA5
Definition: svw_pata.c:38
static const struct @1174 SvwPioTimings[]
#define SVW_REG_UDMA_CONTROL
Definition: svw_pata.c:32
#define SVW_REG_UDMA_MODE
Definition: svw_pata.c:31
static BOOLEAN SvwOsb4PciBridgeInit(_In_ PVOID Context, _In_ ULONG BusNumber, _In_ PCI_SLOT_NUMBER PciSlot, _In_ PPCI_COMMON_HEADER PciConfig)
Definition: svw_pata.c:229
#define SVW_REG_DMA_TIMING
Definition: svw_pata.c:28
BOOLEAN SvwHasUdmaCable(_In_ PATA_CONTROLLER Controller, _In_ ULONG Channel)
Definition: svw_pata.c:213
NTSTATUS SvwPataGetControllerProperties(_Inout_ PATA_CONTROLLER Controller)
Definition: svw_pata.c:288
#define SVW_REG_UDMA_ENABLE
Definition: svw_pata.c:30
#define PCI_DEV_CSB6_IDE_THIRD
Definition: svw_pata.c:22
#define PCI_DEV_OSB4_BRIDGE
Definition: svw_pata.c:25
#define SVW_REG_PIO_TIMING
Definition: svw_pata.c:27
#define SVW_UDMA_CTRL_MODE_MASK
Definition: svw_pata.c:34
ULONG CycleTime
Definition: svw_pata.c:43
static VOID SvwChooseDeviceSpeed(_In_ ULONG Channel, _In_ PCHANNEL_DEVICE_CONFIG Device)
Definition: svw_pata.c:68
#define SVW_REG_PIO_MODE
Definition: svw_pata.c:29
unsigned char UCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE Device
Definition: wdfchildlist.h:474
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_In_ ULONG Shift
Definition: rtlfuncs.h:2698