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