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