xref: /reactos/drivers/bus/pcix/pci/ppbridge.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/pci/ppbridge.c
5  * PURPOSE:         PCI-to-PCI Bridge Support
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 ULONG
19 NTAPI
PciBridgeIoBase(IN PPCI_COMMON_HEADER PciData)20 PciBridgeIoBase(IN PPCI_COMMON_HEADER PciData)
21 {
22     BOOLEAN Is32Bit;
23     ULONG Base, IoBase;
24     ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
25 
26     /* Get the base */
27     Base = PciData->u.type1.IOLimit;
28 
29     /* Low bit specifies 32-bit address, top bits specify the base */
30     Is32Bit = (Base & 0xF) == 1;
31     IoBase = (Base & 0xF0) << 8;
32 
33     /* Is it 32-bit? */
34     if (Is32Bit)
35     {
36         /* Read the upper 16-bits from the other register */
37         IoBase |= PciData->u.type1.IOBaseUpper16 << 16;
38         ASSERT(PciData->u.type1.IOLimit & 0x1);
39     }
40 
41     /* Return the base address */
42     return IoBase;
43 }
44 
45 ULONG
46 NTAPI
PciBridgeIoLimit(IN PPCI_COMMON_HEADER PciData)47 PciBridgeIoLimit(IN PPCI_COMMON_HEADER PciData)
48 {
49     BOOLEAN Is32Bit;
50     ULONG Limit, IoLimit;
51     ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
52 
53     /* Get the limit */
54     Limit = PciData->u.type1.IOLimit;
55 
56     /* Low bit specifies 32-bit address, top bits specify the limit */
57     Is32Bit = (Limit & 0xF) == 1;
58     IoLimit = (Limit & 0xF0) << 8;
59 
60     /* Is it 32-bit? */
61     if (Is32Bit)
62     {
63         /* Read the upper 16-bits from the other register */
64         IoLimit |= PciData->u.type1.IOLimitUpper16 << 16;
65         ASSERT(PciData->u.type1.IOBase & 0x1);
66     }
67 
68     /* Return the I/O limit */
69     return IoLimit | 0xFFF;
70 }
71 
72 ULONG
73 NTAPI
PciBridgeMemoryBase(IN PPCI_COMMON_HEADER PciData)74 PciBridgeMemoryBase(IN PPCI_COMMON_HEADER PciData)
75 {
76     ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
77 
78     /* Return the memory base */
79     return (PciData->u.type1.MemoryBase << 16);
80 }
81 
82 ULONG
83 NTAPI
PciBridgeMemoryLimit(IN PPCI_COMMON_HEADER PciData)84 PciBridgeMemoryLimit(IN PPCI_COMMON_HEADER PciData)
85 {
86     ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
87 
88     /* Return the memory limit */
89     return (PciData->u.type1.MemoryLimit << 16) | 0xFFFFF;
90 }
91 
92 PHYSICAL_ADDRESS
93 NTAPI
PciBridgePrefetchMemoryBase(IN PPCI_COMMON_HEADER PciData)94 PciBridgePrefetchMemoryBase(IN PPCI_COMMON_HEADER PciData)
95 {
96     BOOLEAN Is64Bit;
97     LARGE_INTEGER Base;
98     USHORT PrefetchBase;
99     ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
100 
101     /* Get the base */
102     PrefetchBase = PciData->u.type1.PrefetchBase;
103 
104     /* Low bit specifies 64-bit address, top bits specify the base */
105     Is64Bit = (PrefetchBase & 0xF) == 1;
106     Base.LowPart = ((PrefetchBase & 0xFFF0) << 16);
107 
108     /* Is it 64-bit? */
109     if (Is64Bit)
110     {
111         /* Read the upper 32-bits from the other register */
112         Base.HighPart = PciData->u.type1.PrefetchBaseUpper32;
113     }
114 
115     /* Return the base */
116     return Base;
117 }
118 
119 PHYSICAL_ADDRESS
120 NTAPI
PciBridgePrefetchMemoryLimit(IN PPCI_COMMON_HEADER PciData)121 PciBridgePrefetchMemoryLimit(IN PPCI_COMMON_HEADER PciData)
122 {
123     BOOLEAN Is64Bit;
124     LARGE_INTEGER Limit;
125     USHORT PrefetchLimit;
126     ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
127 
128     /* Get the base */
129     PrefetchLimit = PciData->u.type1.PrefetchLimit;
130 
131     /* Low bit specifies 64-bit address, top bits specify the limit */
132     Is64Bit = (PrefetchLimit & 0xF) == 1;
133     Limit.LowPart = (PrefetchLimit << 16) | 0xFFFFF;
134 
135     /* Is it 64-bit? */
136     if (Is64Bit)
137     {
138         /* Read the upper 32-bits from the other register */
139         Limit.HighPart = PciData->u.type1.PrefetchLimitUpper32;
140     }
141 
142     /* Return the limit */
143     return Limit;
144 }
145 
146 ULONG
147 NTAPI
PciBridgeMemoryWorstCaseAlignment(IN ULONG Length)148 PciBridgeMemoryWorstCaseAlignment(IN ULONG Length)
149 {
150     ULONG Alignment;
151     ASSERT(Length != 0);
152 
153     /* Start with highest alignment (2^31) */
154     Alignment = 0x80000000;
155 
156     /* Keep dividing until we reach the correct power of two */
157     while (!(Length & Alignment)) Alignment >>= 1;
158 
159     /* Return the alignment */
160     return Alignment;
161 }
162 
163 BOOLEAN
164 NTAPI
PciBridgeIsPositiveDecode(IN PPCI_PDO_EXTENSION PdoExtension)165 PciBridgeIsPositiveDecode(IN PPCI_PDO_EXTENSION PdoExtension)
166 {
167     /* Undocumented ACPI Method PDEC to get positive decode settings */
168     return PciIsSlotPresentInParentMethod(PdoExtension, 'CEDP');
169 }
170 
171 BOOLEAN
172 NTAPI
PciBridgeIsSubtractiveDecode(IN PPCI_CONFIGURATOR_CONTEXT Context)173 PciBridgeIsSubtractiveDecode(IN PPCI_CONFIGURATOR_CONTEXT Context)
174 {
175     PPCI_COMMON_HEADER Current, PciData;
176     PPCI_PDO_EXTENSION PdoExtension;
177 
178     /* Get pointers from context */
179     Current = Context->Current;
180     PciData = Context->PciData;
181     PdoExtension = Context->PdoExtension;
182 
183     /* Only valid for PCI-to-PCI bridges */
184     ASSERT((Current->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
185            (Current->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));
186 
187     /* Check for hacks first, then check the ProgIf of the bridge */
188     if (!(PdoExtension->HackFlags & PCI_HACK_SUBTRACTIVE_DECODE) &&
189          (Current->ProgIf != 1) &&
190          ((PciData->u.type1.IOLimit & 0xF0) == 0xF0))
191     {
192         /* A subtractive decode bridge would have a ProgIf 1, and no I/O limit */
193         DPRINT("Subtractive decode does not seem to be enabled\n");
194         return FALSE;
195     }
196 
197     /*
198      * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
199      * i820, i840, i845 Chipsets) that have subtractive decode broken.
200      */
201     if (((PdoExtension->VendorId == 0x8086) &&
202          ((PdoExtension->DeviceId == 0x2418) ||
203           (PdoExtension->DeviceId == 0x2428) ||
204           (PdoExtension->DeviceId == 0x244E) ||
205           (PdoExtension->DeviceId == 0x2448))) ||
206         (PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
207     {
208         /* Check if the ACPI BIOS says positive decode should be enabled */
209         if (PciBridgeIsPositiveDecode(PdoExtension))
210         {
211             /* Obey ACPI */
212             DPRINT1("Putting bridge in positive decode because of PDEC\n");
213             return FALSE;
214         }
215     }
216 
217     /* If we found subtractive decode, we'll need a resource update later */
218     DPRINT1("PCI : Subtractive decode on 0x%x\n", Current->u.type1.SecondaryBus);
219     PdoExtension->UpdateHardware = TRUE;
220     return TRUE;
221 }
222 
223 VOID
224 NTAPI
PPBridge_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)225 PPBridge_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)
226 {
227     NTSTATUS Status;
228     PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
229     PIO_RESOURCE_DESCRIPTOR IoDescriptor;
230     PPCI_FUNCTION_RESOURCES Resources;
231     PCI_COMMON_HEADER BiosData;
232     PPCI_COMMON_HEADER Current;
233     PPCI_COMMON_CONFIG SavedConfig;
234     ULONG i, Bar, BarMask;
235     PULONG BarArray;
236     PHYSICAL_ADDRESS Limit, Base, Length;
237     BOOLEAN HaveIoLimit, CheckAlignment;
238     PPCI_PDO_EXTENSION PdoExtension;
239 
240     /* Get the pointers from the extension */
241     PdoExtension = Context->PdoExtension;
242     Resources = PdoExtension->Resources;
243     Current = Context->Current;
244 
245     /* Check if decodes are disabled */
246     if (!(Context->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)))
247     {
248         /* Well, we're going to need them from somewhere, use the registry data */
249         Status = PciGetBiosConfig(PdoExtension, &BiosData);
250         if (NT_SUCCESS(Status)) Current = &BiosData;
251     }
252 
253     /* Scan all current and limit descriptors for each BAR needed */
254     BarArray = Current->u.type1.BaseAddresses;
255     for (i = 0; i < 6; i++)
256     {
257         /* Get the current resource descriptor, and the limit requirement */
258         CmDescriptor = &Resources->Current[i];
259         IoDescriptor = &Resources->Limit[i];
260 
261         /* Copy descriptor data, skipping null descriptors */
262         CmDescriptor->Type = IoDescriptor->Type;
263         if (CmDescriptor->Type == CmResourceTypeNull) continue;
264         CmDescriptor->Flags = IoDescriptor->Flags;
265         CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition;
266 
267         /* Initialize the high-parts to zero, since most stuff is 32-bit only */
268         Base.QuadPart = Limit.QuadPart = Length.QuadPart = 0;
269 
270         /* Check if we're handling PCI BARs, or the ROM BAR */
271         if ((i < PCI_TYPE1_ADDRESSES) || (i == 5))
272         {
273             /* Is this the ROM BAR? */
274             if (i == 5)
275             {
276                 /* Read the correct bar, with the appropriate mask */
277                 Bar = Current->u.type1.ROMBaseAddress;
278                 BarMask = PCI_ADDRESS_ROM_ADDRESS_MASK;
279 
280                 /* Decode the base address, and write down the length */
281                 Base.LowPart = Bar & BarMask;
282                 DPRINT1("ROM BAR Base: %lx\n", Base.LowPart);
283                 CmDescriptor->u.Memory.Length = IoDescriptor->u.Memory.Length;
284             }
285             else
286             {
287                 /* Otherwise, get the BAR from the array */
288                 Bar = BarArray[i];
289 
290                 /* Is this an I/O BAR? */
291                 if (Bar & PCI_ADDRESS_IO_SPACE)
292                 {
293                     /* Set the correct mask */
294                     ASSERT(CmDescriptor->Type == CmResourceTypePort);
295                     BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
296                 }
297                 else
298                 {
299                     /* This is a memory BAR, set the correct base */
300                     ASSERT(CmDescriptor->Type == CmResourceTypeMemory);
301                     BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
302 
303                     /* IS this a 64-bit BAR? */
304                     if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
305                     {
306                         /* Read the next 32-bits as well, ie, the next BAR */
307                         Base.HighPart = BarArray[i + 1];
308                     }
309                 }
310 
311                 /* Decode the base address, and write down the length */
312                 Base.LowPart = Bar & BarMask;
313                 DPRINT1("BAR Base: %lx\n", Base.LowPart);
314                 CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length;
315             }
316         }
317         else
318         {
319             /* Reset loop conditions */
320             HaveIoLimit = FALSE;
321             CheckAlignment = FALSE;
322 
323             /* Check which descriptor is being parsed */
324             if (i == 2)
325             {
326                 /* I/O Port Requirements */
327                 Base.LowPart = PciBridgeIoBase(Current);
328                 Limit.LowPart = PciBridgeIoLimit(Current);
329                 DPRINT1("Bridge I/O Base and Limit: %lx %lx\n",
330                          Base.LowPart, Limit.LowPart);
331 
332                 /* Do we have any I/O Port data? */
333                 if (!(Base.LowPart) && (Current->u.type1.IOLimit))
334                 {
335                     /* There's a limit */
336                     HaveIoLimit = TRUE;
337                 }
338             }
339             else if (i == 3)
340             {
341                 /* Memory requirements */
342                 Base.LowPart = PciBridgeMemoryBase(Current);
343                 Limit.LowPart = PciBridgeMemoryLimit(Current);
344 
345                 /* These should always be there, so check their alignment */
346                 DPRINT1("Bridge MEM Base and Limit: %lx %lx\n",
347                          Base.LowPart, Limit.LowPart);
348                 CheckAlignment = TRUE;
349             }
350             else if (i == 4)
351             {
352                 /* This should only be present for prefetch memory */
353                 ASSERT(CmDescriptor->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE);
354                 Base = PciBridgePrefetchMemoryBase(Current);
355                 Limit = PciBridgePrefetchMemoryLimit(Current);
356 
357                 /* If it's there, check the alignment */
358                 DPRINT1("Bridge Prefetch MEM Base and Limit: %I64x %I64x\n", Base, Limit);
359                 CheckAlignment = TRUE;
360             }
361 
362             /* Check for invalid base address */
363             if (Base.QuadPart >= Limit.QuadPart)
364             {
365                 /* Assume the descriptor is bogus */
366                 CmDescriptor->Type = CmResourceTypeNull;
367                 IoDescriptor->Type = CmResourceTypeNull;
368                 continue;
369             }
370 
371             /* Check if there's no memory, and no I/O port either */
372             if (!(Base.LowPart) && !(HaveIoLimit))
373             {
374                 /* This seems like a bogus requirement, ignore it */
375                 CmDescriptor->Type = CmResourceTypeNull;
376                 continue;
377             }
378 
379             /* Set the length to be the limit - the base; should always be 32-bit */
380             Length.QuadPart = Limit.LowPart - Base.LowPart + 1;
381             ASSERT(Length.HighPart == 0);
382             CmDescriptor->u.Generic.Length = Length.LowPart;
383 
384             /* Check if alignment should be set */
385             if (CheckAlignment)
386             {
387                 /* Compute the required alignment for this length */
388                 ASSERT(CmDescriptor->u.Memory.Length > 0);
389                 IoDescriptor->u.Memory.Alignment =
390                     PciBridgeMemoryWorstCaseAlignment(CmDescriptor->u.Memory.Length);
391             }
392         }
393 
394         /* Now set the base address */
395         CmDescriptor->u.Generic.Start.LowPart = Base.LowPart;
396     }
397 
398     /* Save PCI settings into the PDO extension for easy access later */
399     PdoExtension->Dependent.type1.PrimaryBus = Current->u.type1.PrimaryBus;
400     PdoExtension->Dependent.type1.SecondaryBus = Current->u.type1.SecondaryBus;
401     PdoExtension->Dependent.type1.SubordinateBus = Current->u.type1.SubordinateBus;
402 
403     /* Check for subtractive decode bridges */
404     if (PdoExtension->Dependent.type1.SubtractiveDecode)
405     {
406         /* Check if legacy VGA decodes are enabled */
407         DPRINT1("Subtractive decode bridge\n");
408         if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
409         {
410             /* Save this setting for later */
411             DPRINT1("VGA Bridge\n");
412             PdoExtension->Dependent.type1.VgaBitSet = TRUE;
413         }
414 
415         /* Legacy ISA decoding is not compatible with subtractive decode */
416         ASSERT(PdoExtension->Dependent.type1.IsaBitSet == FALSE);
417     }
418     else
419     {
420         /* Check if legacy VGA decodes are enabled */
421         if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
422         {
423             /* Save this setting for later */
424             DPRINT1("VGA Bridge\n");
425             PdoExtension->Dependent.type1.VgaBitSet = TRUE;
426 
427             /* And on positive decode, we'll also need extra resources locked */
428             PdoExtension->AdditionalResourceCount = 4;
429         }
430 
431         /* Check if legacy ISA decoding is enabled */
432         if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_ISA)
433         {
434             /* Save this setting for later */
435             DPRINT1("ISA Bridge\n");
436             PdoExtension->Dependent.type1.IsaBitSet = TRUE;
437         }
438     }
439 
440     /*
441      * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
442      * i820, i840, i845 Chipsets) that have subtractive decode broken.
443      */
444     if (((PdoExtension->VendorId == 0x8086) &&
445          ((PdoExtension->DeviceId == 0x2418) ||
446           (PdoExtension->DeviceId == 0x2428) ||
447           (PdoExtension->DeviceId == 0x244E) ||
448           (PdoExtension->DeviceId == 0x2448))) ||
449         (PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
450     {
451         /* Check if subtractive decode is actually enabled */
452         if (PdoExtension->Dependent.type1.SubtractiveDecode)
453         {
454             /* We're going to need a copy of the configuration for later use */
455             DPRINT1("apply config save hack to ICH subtractive decode\n");
456             SavedConfig = ExAllocatePoolWithTag(0, PCI_COMMON_HDR_LENGTH, 'PciP');
457             PdoExtension->ParentFdoExtension->PreservedConfig = SavedConfig;
458             if (SavedConfig) RtlCopyMemory(SavedConfig, Current, PCI_COMMON_HDR_LENGTH);
459         }
460     }
461 }
462 
463 VOID
464 NTAPI
PPBridge_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)465 PPBridge_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
466 {
467     PIO_RESOURCE_DESCRIPTOR Limit;
468     PULONG BarArray;
469     PHYSICAL_ADDRESS MemoryLimit;
470     ULONG i;
471     PPCI_COMMON_HEADER Working;
472     PPCI_PDO_EXTENSION PdoExtension;
473 
474     /* Get the pointers from the context */
475     Working = Context->PciData;
476     PdoExtension = Context->PdoExtension;
477 
478     /* Scan the BARs into the limit descriptors */
479     BarArray = Working->u.type1.BaseAddresses;
480     Limit = PdoExtension->Resources->Limit;
481 
482     /* First of all, loop all the BARs */
483     for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
484     {
485         /* Create a descriptor for their limits */
486         if (PciCreateIoDescriptorFromBarLimit(&Limit[i], &BarArray[i], FALSE))
487         {
488             /* This was a 64-bit descriptor, make sure there's space */
489             ASSERT((i + 1) < PCI_TYPE1_ADDRESSES);
490 
491             /* Skip the next descriptor since this one is double sized */
492             i++;
493             Limit[i].Type = CmResourceTypeNull;
494         }
495     }
496 
497     /* Check if this is a subtractive decode bridge */
498     if (PciBridgeIsSubtractiveDecode(Context))
499     {
500         /* This bridge is subtractive */
501         PdoExtension->Dependent.type1.SubtractiveDecode = TRUE;
502 
503         /* Subtractive bridges cannot use legacy ISA or VGA functionality */
504         PdoExtension->Dependent.type1.IsaBitSet = FALSE;
505         PdoExtension->Dependent.type1.VgaBitSet = FALSE;
506     }
507 
508     /* For normal decode bridges, we'll need to find the bridge limits too */
509     if (!PdoExtension->Dependent.type1.SubtractiveDecode)
510     {
511         /* Loop the descriptors that are left, to store the bridge limits */
512         for (i = PCI_TYPE1_ADDRESSES; i < 5; i++)
513         {
514             /* No 64-bit memory addresses, and set the address to 0 to begin */
515             MemoryLimit.HighPart = 0;
516             (&Limit[i])->u.Port.MinimumAddress.QuadPart = 0;
517 
518             /* Are we getting the I/O limit? */
519             if (i == 2)
520             {
521                 /* There should be one, get it */
522                 ASSERT(Working->u.type1.IOLimit != 0);
523                 ASSERT((Working->u.type1.IOLimit & 0x0E) == 0);
524                 MemoryLimit.LowPart = PciBridgeIoLimit(Working);
525 
526                 /* Build a descriptor for this limit */
527                 (&Limit[i])->Type = CmResourceTypePort;
528                 (&Limit[i])->Flags = CM_RESOURCE_PORT_WINDOW_DECODE |
529                                      CM_RESOURCE_PORT_POSITIVE_DECODE;
530                 (&Limit[i])->u.Port.Alignment = 0x1000;
531                 (&Limit[i])->u.Port.MinimumAddress.QuadPart = 0;
532                 (&Limit[i])->u.Port.MaximumAddress = MemoryLimit;
533                 (&Limit[i])->u.Port.Length = 0;
534             }
535             else if (i == 3)
536             {
537                 /* There should be a valid memory limit, get it */
538                 ASSERT((Working->u.type1.MemoryLimit & 0xF) == 0);
539                 MemoryLimit.LowPart = PciBridgeMemoryLimit(Working);
540 
541                 /* Build the descriptor for it */
542                 (&Limit[i])->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
543                 (&Limit[i])->Type = CmResourceTypeMemory;
544                 (&Limit[i])->u.Memory.Alignment = 0x100000;
545                 (&Limit[i])->u.Memory.MinimumAddress.QuadPart = 0;
546                 (&Limit[i])->u.Memory.MaximumAddress = MemoryLimit;
547                 (&Limit[i])->u.Memory.Length = 0;
548             }
549             else if (Working->u.type1.PrefetchLimit)
550             {
551                 /* Get the prefetch memory limit, if there is one */
552                 MemoryLimit = PciBridgePrefetchMemoryLimit(Working);
553 
554                 /* Write out the descriptor for it */
555                 (&Limit[i])->Flags = CM_RESOURCE_MEMORY_PREFETCHABLE;
556                 (&Limit[i])->Type = CmResourceTypeMemory;
557                 (&Limit[i])->u.Memory.Alignment = 0x100000;
558                 (&Limit[i])->u.Memory.MinimumAddress.QuadPart = 0;
559                 (&Limit[i])->u.Memory.MaximumAddress = MemoryLimit;
560                 (&Limit[i])->u.Memory.Length = 0;
561             }
562             else
563             {
564                 /* Blank descriptor */
565                 (&Limit[i])->Type = CmResourceTypeNull;
566             }
567         }
568     }
569 
570     /* Does the ROM have its own BAR? */
571     if (Working->u.type1.ROMBaseAddress & PCI_ROMADDRESS_ENABLED)
572     {
573         /* Build a limit for it as well */
574         PciCreateIoDescriptorFromBarLimit(&Limit[i],
575                                           &Working->u.type1.ROMBaseAddress,
576                                           TRUE);
577     }
578 }
579 
580 VOID
581 NTAPI
PPBridge_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)582 PPBridge_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)
583 {
584     PPCI_COMMON_HEADER PciData, Current;
585 
586     /* Get pointers from context */
587     PciData = Context->PciData;
588     Current = Context->Current;
589 
590     /*
591      * Write FFh everywhere so that the PCI bridge ignores what it can't handle.
592      * Based on the bits that were ignored (still 0), this is how we can tell
593      * what the limit is.
594      */
595     RtlFillMemory(PciData->u.type1.BaseAddresses,
596                   FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.CapabilitiesPtr) -
597                   FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BaseAddresses),
598                   0xFF);
599 
600     /* Copy the saved settings from the current context into the PCI header */
601     PciData->u.type1.PrimaryBus = Current->u.type1.PrimaryBus;
602     PciData->u.type1.SecondaryBus = Current->u.type1.SecondaryBus;
603     PciData->u.type1.SubordinateBus = Current->u.type1.SubordinateBus;
604     PciData->u.type1.SecondaryLatency = Current->u.type1.SecondaryLatency;
605 
606     /* No I/O limit or base. The bottom base bit specifies that FIXME */
607     PciData->u.type1.IOBaseUpper16 = 0xFFFE;
608     PciData->u.type1.IOLimitUpper16 = 0xFFFF;
609 
610     /* Save secondary status before it gets cleared */
611     Context->SecondaryStatus = Current->u.type1.SecondaryStatus;
612 
613     /* Clear secondary status */
614     Current->u.type1.SecondaryStatus = 0;
615     PciData->u.type1.SecondaryStatus = 0;
616 }
617 
618 VOID
619 NTAPI
PPBridge_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)620 PPBridge_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)
621 {
622     /* Copy back the secondary status register */
623     Context->Current->u.type1.SecondaryStatus = Context->SecondaryStatus;
624 }
625 
626 VOID
627 NTAPI
PPBridge_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context,IN PPCI_COMMON_HEADER PciData,IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)628 PPBridge_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context,
629                                           IN PPCI_COMMON_HEADER PciData,
630                                           IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)
631 {
632 
633     UNREFERENCED_PARAMETER(Context);
634 
635     /* Does this bridge have VGA decodes on it? */
636     if (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
637     {
638         /* Build a private descriptor with 3 entries */
639         IoDescriptor->Type = CmResourceTypeDevicePrivate;
640         IoDescriptor->u.DevicePrivate.Data[0] = 3;
641         IoDescriptor->u.DevicePrivate.Data[1] = 3;
642 
643         /* First, the VGA range at 0xA0000 */
644         IoDescriptor[1].Type = CmResourceTypeMemory;
645         IoDescriptor[1].Flags = CM_RESOURCE_MEMORY_READ_WRITE;
646         IoDescriptor[1].u.Port.Length = 0x20000;
647         IoDescriptor[1].u.Port.Alignment = 1;
648         IoDescriptor[1].u.Port.MinimumAddress.QuadPart = 0xA0000;
649         IoDescriptor[1].u.Port.MaximumAddress.QuadPart = 0xBFFFF;
650 
651         /* Then, the VGA registers at 0x3B0 */
652         IoDescriptor[2].Type = CmResourceTypePort;
653         IoDescriptor[2].Flags = CM_RESOURCE_PORT_POSITIVE_DECODE |
654                                 CM_RESOURCE_PORT_10_BIT_DECODE;
655         IoDescriptor[2].u.Port.Length = 12;
656         IoDescriptor[2].u.Port.Alignment = 1;
657         IoDescriptor[2].u.Port.MinimumAddress.QuadPart = 0x3B0;
658         IoDescriptor[2].u.Port.MaximumAddress.QuadPart = 0x3BB;
659 
660         /* And finally the VGA registers at 0x3C0 */
661         IoDescriptor[3].Type = CmResourceTypePort;
662         IoDescriptor[3].Flags = CM_RESOURCE_PORT_POSITIVE_DECODE |
663                                 CM_RESOURCE_PORT_10_BIT_DECODE;
664         IoDescriptor[3].u.Port.Length = 32;
665         IoDescriptor[3].u.Port.Alignment = 1;
666         IoDescriptor[3].u.Port.MinimumAddress.QuadPart = 0x3C0;
667         IoDescriptor[3].u.Port.MaximumAddress.QuadPart = 0x3DF;
668     }
669 }
670 
671 VOID
672 NTAPI
PPBridge_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData)673 PPBridge_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension,
674                      IN PPCI_COMMON_HEADER PciData)
675 {
676     UNREFERENCED_PARAMETER(PdoExtension);
677     UNREFERENCED_PARAMETER(PciData);
678     UNIMPLEMENTED_DBGBREAK();
679 }
680 
681 VOID
682 NTAPI
PPBridge_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData)683 PPBridge_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension,
684                                 IN PPCI_COMMON_HEADER PciData)
685 {
686     //BOOLEAN IoActive;
687     PPCI_FDO_EXTENSION FdoExtension;
688     PPCI_FUNCTION_RESOURCES PciResources;
689     ULONG i;
690 
691     /* Check if I/O Decodes are enabled */
692     //IoActive = (PciData->u.type1.IOBase & 0xF) == 1;
693 
694     /*
695      * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
696      * i820, i840, i845 Chipsets) that don't have subtractive decode broken.
697      * If they do have broken subtractive support, or if they are not ICH bridges,
698      * then check if the bridge supports subtractive decode at all.
699      */
700     if ((((PdoExtension->VendorId == 0x8086) &&
701          ((PdoExtension->DeviceId == 0x2418) ||
702           (PdoExtension->DeviceId == 0x2428) ||
703           (PdoExtension->DeviceId == 0x244E) ||
704           (PdoExtension->DeviceId == 0x2448))) &&
705          (!(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE) ||
706          (PdoExtension->Dependent.type1.SubtractiveDecode == FALSE))) ||
707         (PdoExtension->Dependent.type1.SubtractiveDecode == FALSE))
708     {
709         /* No resources are needed on a subtractive decode bridge */
710         PciData->u.type1.MemoryBase = 0xFFFF;
711         PciData->u.type1.PrefetchBase = 0xFFFF;
712         PciData->u.type1.IOBase = 0xFF;
713         PciData->u.type1.IOLimit = 0;
714         PciData->u.type1.MemoryLimit = 0;
715         PciData->u.type1.PrefetchLimit = 0;
716         PciData->u.type1.PrefetchBaseUpper32 = 0;
717         PciData->u.type1.PrefetchLimitUpper32 = 0;
718         PciData->u.type1.IOBaseUpper16 = 0;
719         PciData->u.type1.IOLimitUpper16 = 0;
720     }
721     else
722     {
723         /*
724          * Otherwise, get the FDO to read the old PCI configuration header that
725          * had been saved by the hack in PPBridge_SaveCurrentSettings.
726          */
727         FdoExtension = PdoExtension->ParentFdoExtension;
728         ASSERT(PdoExtension->Resources == NULL);
729 
730         /* Read the PCI header data and use that here */
731         PciData->u.type1.IOBase = FdoExtension->PreservedConfig->u.type1.IOBase;
732         PciData->u.type1.IOLimit = FdoExtension->PreservedConfig->u.type1.IOLimit;
733         PciData->u.type1.MemoryBase = FdoExtension->PreservedConfig->u.type1.MemoryBase;
734         PciData->u.type1.MemoryLimit = FdoExtension->PreservedConfig->u.type1.MemoryLimit;
735         PciData->u.type1.PrefetchBase = FdoExtension->PreservedConfig->u.type1.PrefetchBase;
736         PciData->u.type1.PrefetchLimit = FdoExtension->PreservedConfig->u.type1.PrefetchLimit;
737         PciData->u.type1.PrefetchBaseUpper32 = FdoExtension->PreservedConfig->u.type1.PrefetchBaseUpper32;
738         PciData->u.type1.PrefetchLimitUpper32 = FdoExtension->PreservedConfig->u.type1.PrefetchLimitUpper32;
739         PciData->u.type1.IOBaseUpper16 = FdoExtension->PreservedConfig->u.type1.IOBaseUpper16;
740         PciData->u.type1.IOLimitUpper16 = FdoExtension->PreservedConfig->u.type1.IOLimitUpper16;
741     }
742 
743     /* Loop bus resources */
744     PciResources = PdoExtension->Resources;
745     if (PciResources)
746     {
747         /* Loop each resource type (the BARs, ROM BAR and Prefetch) */
748         for (i = 0; i < 6; i++)
749         {
750             UNIMPLEMENTED;
751         }
752     }
753 
754     /* Copy the bus number data */
755     PciData->u.type1.PrimaryBus = PdoExtension->Dependent.type1.PrimaryBus;
756     PciData->u.type1.SecondaryBus = PdoExtension->Dependent.type1.SecondaryBus;
757     PciData->u.type1.SubordinateBus = PdoExtension->Dependent.type1.SubordinateBus;
758 
759     /* Copy the decode flags */
760     if (PdoExtension->Dependent.type1.IsaBitSet)
761     {
762         PciData->u.type1.BridgeControl |= PCI_ENABLE_BRIDGE_ISA;
763     }
764 
765     if (PdoExtension->Dependent.type1.VgaBitSet)
766     {
767         PciData->u.type1.BridgeControl |= PCI_ENABLE_BRIDGE_VGA;
768     }
769 }
770 
771 /* EOF */
772