Support PCI device resource dicsovery for limit and current now, so bridge + device...
[reactos.git] / reactos / drivers / bus / pcix / utils.c
index 6d53e5a..f450a26 100644 (file)
@@ -1041,6 +1041,49 @@ PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension,
     return !(HackFlags & PCI_HACK_NO_PM_CAPS);
 }
 
+PCI_DEVICE_TYPES
+NTAPI
+PciClassifyDeviceType(IN PPCI_PDO_EXTENSION PdoExtension)
+{
+    ASSERT(PdoExtension->ExtensionType == PciPdoExtensionType);
+
+    /* Differenriate between devices and bridges */
+    if (PdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) return PciTypeDevice;
+
+    /* The PCI Bus driver handles only CardBus and PCI bridges (plus host) */
+    if (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) return PciTypeHostBridge;
+    if (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) return PciTypePciBridge;
+    if (PdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS) return PciTypeCardbusBridge;
+
+    /* Any other kind of bridge is treated like a device */
+    return PciTypeDevice;
+}
+
+ULONG_PTR
+NTAPI
+PciExecuteCriticalSystemRoutine(IN ULONG_PTR IpiContext)
+{
+    PPCI_IPI_CONTEXT Context = (PPCI_IPI_CONTEXT)IpiContext;
+
+    /* Check if the IPI is already running */
+    if (!InterlockedDecrement(&Context->RunCount))
+    {
+        /* Nope, this is the first instance, so execute the IPI function */
+        Context->Function(Context->PdoExtension, Context->Context);
+
+        /* Notify anyone that was spinning that they can stop now */
+        Context->Barrier = 0;
+    }
+    else
+    {
+        /* Spin until it has finished running */
+        while (Context->Barrier);
+    }
+
+    /* Done */
+    return 0;
+}
+
 BOOLEAN
 NTAPI
 PciIsSlotPresentInParentMethod(IN PPCI_PDO_EXTENSION PdoExtension,
@@ -1105,6 +1148,115 @@ PciIsSlotPresentInParentMethod(IN PPCI_PDO_EXTENSION PdoExtension,
     return FoundSlot;
 }
 
+ULONG
+NTAPI
+PciGetLengthFromBar(IN ULONG Bar)
+{
+    ULONG Length;
+
+    /* I/O addresses vs. memory addresses start differently due to alignment */
+    Length = 1 << ((Bar & PCI_ADDRESS_IO_SPACE) ? 2 : 4);
+
+    /* Keep going until a set bit */
+    while (!(Length & Bar) && (Length)) Length <<= 1;
+
+    /* Return the length (might be 0 on 64-bit because it's the low-word) */
+    if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) != PCI_TYPE_64BIT) ASSERT(Length);
+    return Length;
+}
+
+BOOLEAN
+NTAPI
+PciCreateIoDescriptorFromBarLimit(PIO_RESOURCE_DESCRIPTOR ResourceDescriptor,
+                                  IN PULONG BarArray,
+                                  IN BOOLEAN Rom)
+{
+    ULONG CurrentBar, BarLength, BarMask;
+    BOOLEAN Is64BitBar = FALSE;
+
+    /* Check if the BAR is nor I/O nor memory */
+    CurrentBar = BarArray[0];
+    if (!(CurrentBar & ~PCI_ADDRESS_IO_SPACE))
+    {
+        /* Fail this descriptor */
+        ResourceDescriptor->Type = CmResourceTypeNull;
+        return FALSE;
+    }
+
+    /* Set default flag and clear high words */
+    ResourceDescriptor->Flags = 0;
+    ResourceDescriptor->u.Generic.MaximumAddress.HighPart = 0;
+    ResourceDescriptor->u.Generic.MinimumAddress.LowPart = 0;
+    ResourceDescriptor->u.Generic.MinimumAddress.HighPart = 0;
+
+    /* Check for ROM Address */
+    if (Rom)
+    {
+        /* Clean up the BAR to get just the address */
+        CurrentBar &= PCI_ADDRESS_ROM_ADDRESS_MASK;
+        if (!CurrentBar)
+        {
+            /* Invalid ar, fail this descriptor */
+            ResourceDescriptor->Type = CmResourceTypeNull;
+            return FALSE;
+        }
+
+        /* ROM Addresses are always read only */
+        ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
+    }
+
+    /* Compute the length, assume it's the alignment for now */
+    BarLength = PciGetLengthFromBar(CurrentBar);
+    ResourceDescriptor->u.Generic.Length = BarLength;
+    ResourceDescriptor->u.Generic.Alignment = BarLength;
+
+    /* Check what kind of BAR this is */
+    if (CurrentBar & PCI_ADDRESS_IO_SPACE)
+    {
+        /* Use correct mask to decode the address */
+        BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
+
+        /* Set this as an I/O Port descriptor */
+        ResourceDescriptor->Type = CmResourceTypePort;
+        ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
+    }
+    else
+    {
+        /* Use correct mask to decode the address */
+        BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
+
+        /* Set this as a memory descriptor */
+        ResourceDescriptor->Type = CmResourceTypeMemory;
+
+        /* Check if it's 64-bit or 20-bit decode */
+        if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
+        {
+            /* The next BAR has the high word, read it */
+            ResourceDescriptor->u.Port.MaximumAddress.HighPart = BarArray[1];
+            Is64BitBar = TRUE;
+        }
+        else if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
+        {
+            /* Use the correct mask to decode the address */
+            BarMask = ~0xFFF0000F;
+        }
+
+        /* Check if the BAR is listed as prefetchable memory */
+        if (CurrentBar & PCI_ADDRESS_MEMORY_PREFETCHABLE)
+        {
+            /* Mark the descriptor in the same way */
+            ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
+        }
+    }
+
+    /* Now write down the maximum address based on the base + length */
+    ResourceDescriptor->u.Port.MaximumAddress.QuadPart = (CurrentBar & BarMask) +
+                                                         BarLength - 1;
+
+    /* Return if this is a 64-bit BAR, so the loop code knows to skip the next one */
+    return Is64BitBar;
+}
+
 VOID
 NTAPI
 PciDecodeEnable(IN PPCI_PDO_EXTENSION PdoExtension,