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