[PCIX] Preperation for initial PCIX Arbiters to be enabled (#9479)

* [PCIX] Use the bridge's parent bus in the IRQ translator constructor

* [PCIX] Stop the limit descriptor scan from running off the array

* [PCIX] Build a real resource requirements list for each function

* [PCIX] Skip the right descriptors when draining a device-private group

* [PCIX] Record assigned resources against the BAR they satisfy

* [PCIX] Program device BARs with their arbitrated addresses

---------

Co-authored-by: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito@reactos.org>
This commit is contained in:
Justin Miller
2026-09-03 00:17:15 -07:00
committed by GitHub
parent b3729be87e
commit b82fc1e2b3
3 changed files with 183 additions and 44 deletions

View File

@@ -81,13 +81,13 @@ tranirq_Constructor(IN PVOID DeviceExtension,
}
else
{
/* It's not, so we have to get the root bus' bus number instead */
#if 0 // when have PDO commit
ParentBus = FdoExtension->PhysicalDeviceObject->DeviceExtension->ParentFdoExtension->BaseBus;
/* It's not, so the translator is rooted on the bus the bridge sits on */
PPCI_PDO_EXTENSION PdoExtension = FdoExtension->PhysicalDeviceObject->DeviceExtension;
ASSERT_PDO(PdoExtension);
ParentBus = PdoExtension->ParentFdoExtension->BaseBus;
ParentInterface = PCIBus;
DPRINT1(" Is bridge FDO, parent bus %x, secondary bus %x\n",
ParentBus, BaseBus);
#endif
}
/* Now call the legacy HAL interface to get the correct translator */

View File

@@ -283,10 +283,73 @@ NTAPI
Device_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_HEADER PciData)
{
UNREFERENCED_PARAMETER(PdoExtension);
UNREFERENCED_PARAMETER(PciData);
/* Not yet implemented */
UNIMPLEMENTED_DBGBREAK();
PPCI_FUNCTION_RESOURCES Resources;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
PULONG BarArray;
ULONG Bar, BarMask, i;
Resources = PdoExtension->Resources;
if (!Resources)
return;
/* Write each BAR back with the address that was arbitrated for it */
BarArray = PciData->u.type0.BaseAddresses;
for (i = 0; i <= PCI_TYPE0_ADDRESSES; i++)
{
CmDescriptor = &Resources->Current[i];
if (i < PCI_TYPE0_ADDRESSES)
{
/* A BAR the function does not implement reads back as zero */
Bar = BarArray[i];
if (!(Bar & ~PCI_ADDRESS_IO_SPACE)) continue;
/* Work out which bits of this BAR are the address */
if (Bar & PCI_ADDRESS_IO_SPACE)
{
BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
}
else
{
BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
/* A legacy BAR only decodes the low 20 bits of the address */
if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
{
BarMask = 0xFFFF0;
}
}
BarArray[i] = (Bar & ~BarMask) |
(CmDescriptor->u.Memory.Start.LowPart & BarMask);
/* A 64-bit BAR keeps the high half of its address in the next one */
if (!(Bar & PCI_ADDRESS_IO_SPACE) &&
((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT))
{
ASSERT((i + 1) < PCI_TYPE0_ADDRESSES);
BarArray[i + 1] = CmDescriptor->u.Memory.Start.HighPart;
i++;
}
}
else
{
/* The ROM BAR decodes only while its enable bit is set */
Bar = PciData->u.type0.ROMBaseAddress;
if (CmDescriptor->Type == CmResourceTypeNull)
{
PciData->u.type0.ROMBaseAddress = Bar & ~PCI_ROMADDRESS_ENABLED;
}
else
{
PciData->u.type0.ROMBaseAddress =
(Bar & ~PCI_ADDRESS_ROM_ADDRESS_MASK) |
(CmDescriptor->u.Memory.Start.LowPart &
PCI_ADDRESS_ROM_ADDRESS_MASK) |
PCI_ROMADDRESS_ENABLED;
}
}
}
}
/* EOF */

View File

@@ -56,11 +56,12 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
IN PCM_RESOURCE_LIST ResourceList)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, InterruptResource;
PCM_PARTIAL_RESOURCE_DESCRIPTOR BaseResource, CurrentDescriptor;
PCM_PARTIAL_RESOURCE_DESCRIPTOR PreviousDescriptor;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentDescriptor;
CM_PARTIAL_RESOURCE_DESCRIPTOR ResourceArray[7];
ULONG BarIndex;
PCM_FULL_RESOURCE_DESCRIPTOR FullList;
BOOLEAN DrainPartial, RangeChange;
BOOLEAN RangeChange;
ULONG DrainPartial;
ULONG i, j;
PPCI_FUNCTION_RESOURCES PciResources;
PAGED_CODE();
@@ -72,6 +73,11 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
Partial = NULL;
InterruptResource = NULL;
RangeChange = FALSE;
BarIndex = 0;
/* The limits say which BARs this function implements, so the walk below
* can tell which BAR each assigned descriptor belongs to */
PciResources = PdoExtension->Resources;
/* Check if there's not actually any resources */
if (!(ResourceList) || !(ResourceList->Count))
@@ -91,8 +97,7 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
for (i = 0; i < ResourceList->Count; i++)
{
/* Initialize loop variables */
DrainPartial = FALSE;
BaseResource = NULL;
DrainPartial = 0;
/* Loop the partial descriptors */
Partial = FullList->PartialResourceList.PartialDescriptors;
@@ -101,8 +106,8 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
/* Check if we were supposed to drain a partial due to device data */
if (DrainPartial)
{
/* Draining complete, move on to the next descriptor then */
DrainPartial--;
Partial = CmiGetNextPartialDescriptor(Partial);
continue;
}
@@ -122,9 +127,22 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
break;
}
/* Set it as the base */
ASSERT(BaseResource == NULL);
BaseResource = Partial;
/*
* The assigned descriptors come back in the order the
* requirements list asked for them, so walking the limits
* in that same order says which BAR this one satisfies.
*/
if (PciResources)
{
while ((BarIndex < RTL_NUMBER_OF(ResourceArray)) &&
(PciResources->Limit[BarIndex].Type == CmResourceTypeNull))
{
BarIndex++;
}
if (BarIndex < RTL_NUMBER_OF(ResourceArray))
ResourceArray[BarIndex++] = *Partial;
}
break;
}
/* Interrupt resource */
@@ -167,10 +185,7 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
/* A drain request */
case 3:
/* Shouldn't be a base resource, this is a drain */
ASSERT(BaseResource == NULL);
DrainPartial = Partial->u.DevicePrivate.Data[1];
ASSERT(DrainPartial == TRUE);
break;
}
break;
@@ -181,34 +196,25 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
}
/* We should be starting a new list now */
ASSERT(BaseResource == NULL);
FullList = (PVOID)Partial;
}
/* Check the current assigned PCI resources */
PciResources = PdoExtension->Resources;
/* A function with no discovered resources has nothing to update */
if (!PciResources) return FALSE;
//if... // MISSING CODE
UNIMPLEMENTED;
DPRINT1("Missing sanity checking code!\n");
/* Loop all the PCI function resources */
for (i = 0; i < 7; i++)
for (i = 0; i < RTL_NUMBER_OF(ResourceArray); i++)
{
/* Get the current function resource descriptor, and the new one */
CurrentDescriptor = &PciResources->Current[i];
Partial = &ResourceArray[i];
/* Previous is current during the first loop iteration */
PreviousDescriptor = &PciResources->Current[(i == 0) ? (0) : (i - 1)];
/* Check if this new descriptor is different than the old one */
if (((Partial->Type != CurrentDescriptor->Type) ||
(Partial->Type != CmResourceTypeNull)) &&
((Partial->u.Generic.Start.QuadPart !=
CurrentDescriptor->u.Generic.Start.QuadPart) ||
(Partial->u.Generic.Length != CurrentDescriptor->u.Generic.Length)))
if ((Partial->Type != CurrentDescriptor->Type) ||
((Partial->Type != CmResourceTypeNull) &&
((Partial->u.Generic.Start.QuadPart !=
CurrentDescriptor->u.Generic.Start.QuadPart) ||
(Partial->u.Generic.Length != CurrentDescriptor->u.Generic.Length))))
{
/* Record a change */
RangeChange = TRUE;
@@ -232,9 +238,8 @@ PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
/* Update to new range */
CurrentDescriptor->Type = Partial->Type;
PreviousDescriptor->u.Generic.Start = Partial->u.Generic.Start;
PreviousDescriptor->u.Generic.Length = Partial->u.Generic.Length;
CurrentDescriptor = PreviousDescriptor;
CurrentDescriptor->u.Generic.Start = Partial->u.Generic.Start;
CurrentDescriptor->u.Generic.Length = Partial->u.Generic.Length;
}
}
@@ -562,10 +567,35 @@ PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension,
OUT PIO_RESOURCE_REQUIREMENTS_LIST* Buffer)
{
PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
PIO_RESOURCE_DESCRIPTOR Descriptor, Limit;
PCI_CONFIGURATOR_CONTEXT Context;
ULONG Count, i;
BOOLEAN HaveInterrupt;
UNREFERENCED_PARAMETER(PdoExtension);
UNREFERENCED_PARAMETER(PciData);
PAGED_CODE();
/* Count the BAR limits that resource discovery found for this function */
Count = 0;
if (PdoExtension->Resources)
{
for (i = 0; i < (PCI_TYPE0_ADDRESSES + 1); i++)
{
if (PdoExtension->Resources->Limit[i].Type != CmResourceTypeNull)
Count++;
}
}
/* A device with an interrupt pin also needs a line routed to it */
HaveInterrupt = (PdoExtension->InterruptPin) &&
!(PdoExtension->HackFlags & PCI_HACK_NO_ENUM_AT_ALL);
if (HaveInterrupt)
Count++;
/* And a bridge with legacy decodes enabled needs those ranges locked down */
Count += PdoExtension->AdditionalResourceCount;
/* Check if the function turned out to need nothing after all */
if (!Count)
{
/* There aren't, so use the zero descriptor */
RequirementsList = PciZeroIoResourceRequirements;
@@ -579,11 +609,57 @@ PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension,
if (!PciZeroIoResourceRequirements) return STATUS_INSUFFICIENT_RESOURCES;
}
/* Return the zero requirements list to the caller */
*Buffer = RequirementsList;
DPRINT1("PCI - build resource reqs - early out, 0 resources\n");
return STATUS_SUCCESS;
}
RequirementsList = PciAllocateIoRequirementsList(Count,
PdoExtension->ParentFdoExtension->BaseBus,
PdoExtension->Slot.u.AsULONG);
if (!RequirementsList)
return STATUS_INSUFFICIENT_RESOURCES;
Descriptor = RequirementsList->List[0].Descriptors;
/* Emit one descriptor per BAR that decoded something during discovery */
if (PdoExtension->Resources)
{
Limit = PdoExtension->Resources->Limit;
for (i = 0; i < (PCI_TYPE0_ADDRESSES + 1); i++)
{
/* Skip the BARs this function does not implement */
if (Limit[i].Type == CmResourceTypeNull)
continue;
/* A BAR decodes for one function only, so it cannot be shared */
*Descriptor = Limit[i];
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor++;
}
}
if (HaveInterrupt)
{
Descriptor->Type = CmResourceTypeInterrupt;
Descriptor->ShareDisposition = CmResourceShareShared;
Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
Descriptor->u.Interrupt.MinimumVector = 0;
Descriptor->u.Interrupt.MaximumVector = MAXULONG;
Descriptor++;
}
/* And finally any extra ranges this kind of function decodes on the side */
if (PdoExtension->AdditionalResourceCount)
{
RtlZeroMemory(&Context, sizeof(Context));
Context.PdoExtension = PdoExtension;
Context.Current = PciData;
PciConfigurators[PdoExtension->HeaderType].
GetAdditionalResourceDescriptors(&Context, PciData, Descriptor);
}
*Buffer = RequirementsList;
return STATUS_SUCCESS;
}
@@ -1470,8 +1546,8 @@ PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
IoDescriptor--;
if (IoDescriptor->Type != CmResourceTypeNull) break;
/* This is a null descriptor, is it the last one? */
if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1])
/* This is a null descriptor, have all of them been scanned now? */
if (IoDescriptor == &PdoExtension->Resources->Limit[0])
{
/* This means the descriptor is NULL, which means discovery failed */
DPRINT1("PCI Resources fail!\n");