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