Sync with trunk r58740.
[reactos.git] / drivers / bus / pcix / device.c
1 /*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/device.c
5 * PURPOSE: Device Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 /* FUNCTIONS ******************************************************************/
18
19 VOID
20 NTAPI
21 Device_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)
22 {
23 PPCI_COMMON_HEADER PciData;
24 PIO_RESOURCE_DESCRIPTOR IoDescriptor;
25 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
26 PPCI_FUNCTION_RESOURCES Resources;
27 PULONG BarArray;
28 ULONG Bar, BarMask, i;
29
30 /* Get variables from context */
31 PciData = Context->Current;
32 Resources = Context->PdoExtension->Resources;
33
34 /* Loop all the PCI BARs */
35 BarArray = PciData->u.type0.BaseAddresses;
36 for (i = 0; i <= PCI_TYPE0_ADDRESSES; i++)
37 {
38 /* Get the resource descriptor and limit descriptor for this BAR */
39 CmDescriptor = &Resources->Current[i];
40 IoDescriptor = &Resources->Limit[i];
41
42 /* Build the resource descriptor based on the limit descriptor */
43 CmDescriptor->Type = IoDescriptor->Type;
44 if (CmDescriptor->Type == CmResourceTypeNull) continue;
45 CmDescriptor->Flags = IoDescriptor->Flags;
46 CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition;
47 CmDescriptor->u.Generic.Start.HighPart = 0;
48 CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length;
49
50 /* Read the actual BAR value */
51 Bar = BarArray[i];
52
53 /* Check which BAR is being processed now */
54 if (i != PCI_TYPE0_ADDRESSES)
55 {
56 /* Check if this is an I/O BAR */
57 if (Bar & PCI_ADDRESS_IO_SPACE)
58 {
59 /* Use the right mask to get the I/O port base address */
60 ASSERT(CmDescriptor->Type == CmResourceTypePort);
61 BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
62 }
63 else
64 {
65 /* It's a RAM BAR, use the right mask to get the base address */
66 ASSERT(CmDescriptor->Type == CmResourceTypeMemory);
67 BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
68
69 /* Check if it's a 64-bit BAR */
70 if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
71 {
72 /* The next BAR value is actually the high 32-bits */
73 CmDescriptor->u.Memory.Start.HighPart = BarArray[i + 1];
74 }
75 else if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
76 {
77 /* Legacy BAR, don't read more than 20 bits of the address */
78 BarMask = 0xFFFF0;
79 }
80 }
81 }
82 else
83 {
84 /* Actually a ROM BAR, so read the correct register */
85 Bar = PciData->u.type0.ROMBaseAddress;
86
87 /* Apply the correct mask for ROM BARs */
88 BarMask = PCI_ADDRESS_ROM_ADDRESS_MASK;
89
90 /* Make sure it's enabled */
91 if (!(Bar & PCI_ROMADDRESS_ENABLED))
92 {
93 /* If it isn't, then a descriptor won't be built for it */
94 CmDescriptor->Type = CmResourceTypeNull;
95 continue;
96 }
97 }
98
99 /* Now we have the right mask, read the actual address from the BAR */
100 Bar &= BarMask;
101 CmDescriptor->u.Memory.Start.LowPart = Bar;
102
103 /* And check for invalid BAR addresses */
104 if (!(CmDescriptor->u.Memory.Start.HighPart | Bar))
105 {
106 /* Skip these descriptors */
107 CmDescriptor->Type = CmResourceTypeNull;
108 DPRINT1("Invalid BAR\n");
109 }
110 }
111
112 /* Also save the sub-IDs that came directly from the PCI header */
113 Context->PdoExtension->SubsystemVendorId = PciData->u.type0.SubVendorID;
114 Context->PdoExtension->SubsystemId = PciData->u.type0.SubSystemID;
115 }
116
117 VOID
118 NTAPI
119 Device_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
120 {
121 PPCI_COMMON_HEADER Current, PciData;
122 PPCI_PDO_EXTENSION PdoExtension;
123 PULONG BarArray;
124 PIO_RESOURCE_DESCRIPTOR Limit;
125 ULONG i;
126
127 /* Get pointers from the context */
128 PdoExtension = Context->PdoExtension;
129 Current = Context->Current;
130 PciData = Context->PciData;
131
132 /* And get the array of bARs */
133 BarArray = PciData->u.type0.BaseAddresses;
134
135 /* First, check for IDE controllers that are not in native mode */
136 if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
137 (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) &&
138 (PdoExtension->ProgIf & 5) != 5)
139 {
140 /* They should not be using any non-legacy resources */
141 BarArray[0] = 0;
142 BarArray[1] = 0;
143 BarArray[2] = 0;
144 BarArray[3] = 0;
145 }
146 else if ((PdoExtension->VendorId == 0x5333) &&
147 ((PdoExtension->DeviceId == 0x88F0) ||
148 (PdoExtension->DeviceId == 0x8880)))
149 {
150 /*
151 * The problem is caused by the S3 Vision 968/868 video controller which
152 * is used on the Diamond Stealth 64 Video 3000 series, Number Nine 9FX
153 * motion 771, and other popular video cards, all containing a memory bug.
154 * The 968/868 claims to require 32 MB of memory, but it actually decodes
155 * 64 MB of memory.
156 */
157 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
158 {
159 /* Find its 32MB RAM BAR */
160 if (BarArray[i] == 0xFE000000)
161 {
162 /* Increase it to 64MB to make sure nobody touches the buffer */
163 BarArray[i] = 0xFC000000;
164 DPRINT1("PCI - Adjusted broken S3 requirement from 32MB to 64MB\n");
165 }
166 }
167 }
168
169 /* Check for Cirrus Logic GD5430/5440 cards */
170 if ((PdoExtension->VendorId == 0x1013) && (PdoExtension->DeviceId == 0xA0))
171 {
172 /* Check for the I/O port requirement */
173 if (BarArray[1] == 0xFC01)
174 {
175 /* Check for completely bogus BAR */
176 if (Current->u.type0.BaseAddresses[1] == 1)
177 {
178 /* Ignore it */
179 BarArray[1] = 0;
180 DPRINT1("PCI - Ignored Cirrus GD54xx broken IO requirement (400 ports)\n");
181 }
182 else
183 {
184 /* Otherwise, this BAR seems okay */
185 DPRINT1("PCI - Cirrus GD54xx 400 port IO requirement has a valid setting (%08x)\n",
186 Current->u.type0.BaseAddresses[1]);
187 }
188 }
189 else if (BarArray[1])
190 {
191 /* Strange, the I/O BAR was not found as expected (or at all) */
192 DPRINT1("PCI - Warning Cirrus Adapter 101300a0 has unexpected resource requirement (%08x)\n",
193 BarArray[1]);
194 }
195 }
196
197 /* Finally, process all the limit descriptors */
198 Limit = PdoExtension->Resources->Limit;
199 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
200 {
201 /* And build them based on the BARs */
202 if (PciCreateIoDescriptorFromBarLimit(&Limit[i], &BarArray[i], FALSE))
203 {
204 /* This function returns TRUE if the BAR was 64-bit, handle this */
205 ASSERT((i + 1) < PCI_TYPE0_ADDRESSES);
206 i++;
207 Limit[i].Type = CmResourceTypeNull;
208 }
209 }
210
211 /* Create the last descriptor based on the ROM address */
212 PciCreateIoDescriptorFromBarLimit(&Limit[i],
213 &PciData->u.type0.ROMBaseAddress,
214 TRUE);
215 }
216
217 VOID
218 NTAPI
219 Device_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)
220 {
221 PPCI_COMMON_HEADER PciData;
222 PPCI_PDO_EXTENSION PdoExtension;
223 PULONG BarArray;
224 ULONG i = 0;
225
226 /* Get pointers from context data */
227 PdoExtension = Context->PdoExtension;
228 PciData = Context->PciData;
229
230 /* Get the array of BARs */
231 BarArray = PciData->u.type0.BaseAddresses;
232
233 /* Check for IDE controllers that are not in native mode */
234 if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
235 (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) &&
236 (PdoExtension->ProgIf & 5) != 5)
237 {
238 /* These controllers only use legacy resources */
239 i = 4;
240 }
241
242 /* Set all the bits on, which will allow us to recover the limit data */
243 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) BarArray[i] = 0xFFFFFFFF;
244
245 /* Do the same for the PCI ROM BAR */
246 PciData->u.type0.ROMBaseAddress = PCI_ADDRESS_ROM_ADDRESS_MASK;
247 }
248
249 VOID
250 NTAPI
251 Device_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)
252 {
253 /* Nothing to do for devices */
254 return;
255 }
256
257 VOID
258 NTAPI
259 Device_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context,
260 IN PPCI_COMMON_HEADER PciData,
261 IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)
262 {
263 /* Not yet implemented */
264 UNIMPLEMENTED_DBGBREAK();
265 }
266
267 VOID
268 NTAPI
269 Device_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension,
270 IN PPCI_COMMON_HEADER PciData)
271 {
272 /* Not yet implemented */
273 UNIMPLEMENTED_DBGBREAK();
274 }
275
276 VOID
277 NTAPI
278 Device_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension,
279 IN PPCI_COMMON_HEADER PciData)
280 {
281 /* Not yet implemented */
282 UNIMPLEMENTED_DBGBREAK();
283 }
284
285 /* EOF */