pciinit.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,086 行 · 第 1/2 页

C
1,086
字号
    ULONG NumberOfRegs,
    PULONG pMemSize,
    PULONG pIoSize
    )
 
/*++
 
Routine Description:
 
    Read base address registers
 
Arguments:
 
    None.
 
Return Value:
 
    None.
 
--*/

{
    ULONG Offset;
    ULONG i;
    ULONG BaseAddress;
    ULONG Size;
    ULONG Type;
    BOOL  LimitMem = FALSE;
    BOOL  SetExpROM = FALSE;
    ULONG nRomSize = 0;

    Offset = 0x10;
    for (i = 0; i < NumberOfRegs; i++) {

        PCIConfig_Write(Bus,Device,Function,Offset,0xFFFFFFFF);
        BaseAddress = PCIConfig_Read(Bus,Device,Function,Offset);

        if (BaseAddress & 1) {

            //
            // IO space
            //

            Size = ~(BaseAddress & 0xFFFFFFFC);
            Type = PCI_TYPE_IO;

        } else {

            //
            // memory space
            // BUGBUG - don't properly handle the MEM20 case
            //

            Size = ~(BaseAddress & 0xFFFFFFF0);
            Type = PCI_TYPE_MEM;

        }

        //
        // check that the register is valid format
        // should have consecutive high 1's and consecutive low 0's
        //

        if ((BaseAddress != 0) &&
            (BaseAddress != 0xFFFFFFFF) &&
            ((Size + 1) & Size) == 0) {

            // ***************************************************************
            //
            // Permedia3 hack
            //
            // The card asks for a lot of PCI memory.  Limit the total memory 
            // allocated since we don't have much to dole out.  We'll allow the 
            // smaller mappings (card registers, etc.) and at least one 
            // reasonably-sized mapping for the framebuffer/aperature.  Any
            // additional large mappings will be located outside the system
            // bridge-reachable range (effectively disabling the mapping).  This
            // means the video driver must take steps to not use that range of
            // PCI memory addresses.  Because the driver need be aware of the
            // situation, this code is card-specific.
            // 

            if (PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_ID) == PERM3_VENDEVID)
            {

                if (LimitMem)
                {
                    PCIConfig_Write(Bus,Device,Function,Offset,0xFFFFFFFF);
                    goto NextDev;
                }
           
                // Let's consider anything above 32MB large and assume that 
                // all the smaller buffers were first in the BAR line-up.
                // After this, we'll "disable" any BARs that request PCI memory.
                if (Size > (32 * 1024 * 1024))
                    LimitMem = TRUE; 

                // The Permedia3 needs a card-specific 64KB mapping for the 
                // expansion ROM (details the cards memory setup sequence).
                if (!SetExpROM)
                {
                    SetExpROM = TRUE;

                    // Determine the required ROM expansion mapping size.
                    //
                    PCIConfig_Write(Bus,Device,Function,0x30,0xFFFFFFFF);
                    BaseAddress = PCIConfig_Read(Bus,Device,Function,Offset);
                    nRomSize = ~(BaseAddress & 0xFFFFFFF0);

                    SpaceDesc[nSpaceDesc].Bus      = Bus;
                    SpaceDesc[nSpaceDesc].Device   = Device;
                    SpaceDesc[nSpaceDesc].Function = Function;
                    SpaceDesc[nSpaceDesc].Offset   = 0x30;   // Exp ROM Offset
                    SpaceDesc[nSpaceDesc].Bridge   = 0;
                    SpaceDesc[nSpaceDesc].IoSize   = 0;
                    SpaceDesc[nSpaceDesc].MemSize  = nRomSize;

                    *pMemSize += nRomSize + 1;

                    ++nSpaceDesc;
                    if (nSpaceDesc == MAX_SPACE) 
                        return FALSE;
                }
            }

            //
            // Add to list so allocate space later
            //

            SpaceDesc[nSpaceDesc].Bus = Bus;
            SpaceDesc[nSpaceDesc].Device = Device;
            SpaceDesc[nSpaceDesc].Function = Function;
            SpaceDesc[nSpaceDesc].Offset = Offset;
            SpaceDesc[nSpaceDesc].Bridge = 0;
            SpaceDesc[nSpaceDesc].IoSize = 0;
            SpaceDesc[nSpaceDesc].MemSize = 0;

            if (Type == PCI_TYPE_IO) {
                *pIoSize += Size + 1;
                SpaceDesc[nSpaceDesc].IoSize = Size + 1;
            } else {
                *pMemSize += Size + 1;
                SpaceDesc[nSpaceDesc].MemSize = Size + 1;
            }
            pci_printf("BAR %d %d %d 0x%x %d 0x%X %s\r\n",Bus,Device,Function,Offset,Type,Size+1,(Type == PCI_TYPE_IO)? "IO":"MEM");
            nSpaceDesc++;
            if (nSpaceDesc == MAX_SPACE) {
                return FALSE;
            }
        }

NextDev:
        //
        // check for 64 bit device - BAR is twice as big
        //

        if ((BaseAddress & 0x7) == 0x4) {

            //
            // 64 bit device - BAR is twice as wide - zero out high part
            //

            Offset += 4;
            PCIConfig_Write(Bus,Device,Function,Offset,0x0);
        }
        Offset += 4;
    }

    return TRUE;
}


BOOL
PciInitAllocateIoSpace(
    ULONG IoUpperBound,
    ULONG IoLowerBound,
    ULONG Bus
    )
 
/*++
 
Routine Description:
 
    Description.
 
Arguments:
 
    None.
 
Return Value:
 
    None.
 
--*/


{
    ULONG i;
    ULONG j;
    ULONG IoBase;
    PSPACE_DESC pSpace;

    pci_printf("AllocateIo %d %X %X\r\n",Bus,IoUpperBound,IoLowerBound);
    //
    // Sort the space descriptors for a given bus by size
    //

    for (i = 31; i >= 1; i--) {

        for (j = 0; j < nSpaceDesc; j++) {

            pSpace = &SpaceDesc[j];
            if ((pSpace->Bus == Bus) && ((pSpace->IoSize) & (1 << i))) {

                if (pSpace->Bridge == 0) {

                    IoUpperBound -= pSpace->IoSize;
                    PCIConfig_Write(pSpace->Bus,
                                    pSpace->Device,
                                    pSpace->Function,
                                    pSpace->Offset,
                                    IoUpperBound);
                    pSpace->IoBase = IoUpperBound;
                    pSpace->SortOrder = SortOrder++;
                    pci_printf("AllocateIO %d %d %d %x %x (%X)\r\n",pSpace->Bus, pSpace->Device, pSpace->Function, pSpace->Offset, IoUpperBound,pSpace->IoSize);

                } else {

                    if (!PciInitAllocateIoSpace(
                        IoUpperBound,
                        IoUpperBound - pSpace->IoSize,
                        pSpace->SecondaryBus)) {

                        return FALSE;
                    }

                    //
                    // init I/O base and limit registers
                    //

                    IoBase = PCIConfig_Read(pSpace->Bus,
                                             pSpace->Device,
                                             pSpace->Function,
                                             PCIBRIDGE_IO);

                    ((PBRIDGE_IO)(&IoBase))->IoLimit.Address =
                        (BYTE)(((IoUpperBound - 1) & 0xF000) >> 12);
                    //((PBRIDGE_IO)(&IoBase))->IoLimit.DecodeType = Something;
                    IoUpperBound -= pSpace->IoSize;
                    ((PBRIDGE_IO)(&IoBase))->IoBase.Address =
                        (BYTE)(((IoUpperBound) & 0xF000) >> 12);
                    //((PBRIDGE_IO)(&IoBase))->IoBase.DecodeType = Something;
                    pci_printf("AllocateIOLimit %d %d %d %x %x (%X)\r\n",pSpace->Bus, pSpace->Device, pSpace->Function, pSpace->Offset, IoBase,pSpace->IoSize);

                    PCIConfig_Write(pSpace->Bus,
                                    pSpace->Device,
                                    pSpace->Function,
                                    PCIBRIDGE_IO,
                                    IoBase);
                    pSpace->IoBase = IoBase;
                    pSpace->SortOrder = SortOrder++;
                }
            }

            if (IoUpperBound < IoLowerBound) {

                return FALSE;
            }
        }
    }

    return TRUE;
}


BOOL
PciInitAllocateMemSpace(
    ULONG MemUpperBound,
    ULONG MemLowerBound,
    ULONG Bus
    )
 
/*++
 
Routine Description:
 
    Description.
 
Arguments:
 
    None.
 
Return Value:
 
    None.
 
--*/


{
    ULONG i;
    ULONG j;
    ULONG MemBase;
    PSPACE_DESC pSpace;

    pci_printf("AllocateMem %d %X %X\r\n",Bus,MemUpperBound,MemLowerBound);

    //
    // Sort the space descriptors for a given bus by size
    //

    for (i = 31; i >= 1; i--) {

        for (j = 0; j < nSpaceDesc; j++) {

            pSpace = &SpaceDesc[j];
            if ((pSpace->Bus == Bus) && ((pSpace->MemSize) & (1 << i))) {

                if (pSpace->Bridge == 0) {

                    MemUpperBound -= pSpace->MemSize;
                    PCIConfig_Write(pSpace->Bus,
                                    pSpace->Device,
                                    pSpace->Function,
                                    pSpace->Offset,
                                    MemUpperBound);
                    pSpace->MemBase = MemUpperBound;
                    pSpace->SortOrder = SortOrder++;
                    pci_printf("AllocateMem %d %d %d %x %x (%X)\r\n",pSpace->Bus, pSpace->Device, pSpace->Function, pSpace->Offset, MemUpperBound,pSpace->MemSize);

                } else {

                    if (!PciInitAllocateMemSpace(
                        MemUpperBound,
                        MemUpperBound - pSpace->MemSize,
                        pSpace->SecondaryBus)) {

                        return FALSE;
                    }

                    //
                    // Init mem base and limit registers
                    //

                    ((PBRIDGE_MEM)(&MemBase))->MemoryLimit.Address =
                        (WORD)(((MemUpperBound - 1) & 0xFFF00000) >> 20);
                    //((PBRIDGE_MEM)(&MemBase))->MemoryLimit.DecodeType = Something;
                    MemUpperBound -= pSpace->MemSize;
                    ((PBRIDGE_MEM)(&MemBase))->MemoryBase.Address =
                        (WORD)(((MemUpperBound) & 0xFFF00000) >> 20);
                    //((PBRIDGE_MEM)(&MemBase))->MemoryBase.DecodeType = Something;
                    pci_printf("AllocateMemLimit %d %d %d %x %x (%X)\r\n",pSpace->Bus, pSpace->Device, pSpace->Function, pSpace->Offset, MemBase,pSpace->MemSize);

                    PCIConfig_Write(pSpace->Bus,
                                    pSpace->Device,
                                    pSpace->Function,
                                    PCIBRIDGE_MEMORY,
                                    MemBase);
                    pSpace->MemBase = MemBase;
                    pSpace->SortOrder = SortOrder++;

                }
            }

            if (MemUpperBound < MemLowerBound) {

                return FALSE;
            }
        }
    }

    return TRUE;
}


VOID
PciInitListDevices(
    )
 
/*++
 
Routine Description:
 
    Routine to list all PCI devices found
 
Arguments:
 
    None.
 
Return Value:
 
    None.
 
--*/

{
    ULONG i,j;


    EdbgOutputDebugString("\n\rList of Detected PCI Devices");
    EdbgOutputDebugString("\n\r-----------------------------------------------------------\n\r");

    for (i = 0; i < nDev; i++) {

        EdbgOutputDebugString("ID:%X  Bus:%X  IDSEL:%d  Funct:%d  Class:%X  IRQ:%X  ",
            pDev[i].VendorID,
            pDev[i].Bus,
            pDev[i].Device,
            pDev[i].Function,
            PCIConfig_Read(pDev[i].Bus,
                           pDev[i].Device,
                           pDev[i].Function,
                           PCI_CONFIG_CLASS_REVISION),
            PCIConfig_Read(pDev[i].Bus,
                           pDev[i].Device,
                           pDev[i].Function,
                           PCI_CONFIG_INTERRUPT) & 0xff);

        if (pDev[i].Bus == 0) {
            switch (pDev[i].Device) {
                case IDSEL_SLOT1:
                    EdbgOutputDebugString("PCI_PCI Bridge");
                    break;
                case IDSEL_SLOT2:
                    EdbgOutputDebugString("PCI Slot #3");
                    break;
                case IDSEL_SLOT3:
                    EdbgOutputDebugString("PCI Slot #4");
                    break;
                case IDSEL_VRC5074:
                    EdbgOutputDebugString("Vrc5476");
                    break;
                case IDSEL_ENET:
                    EdbgOutputDebugString("Ethernet");
                    break;
                case IDSEL_M1543:
                    EdbgOutputDebugString("ISA Bridge");
                    break;
                case IDSEL_IDE:
                    EdbgOutputDebugString("IDE Controller");
                    break;
                case IDSEL_PMU:
                    EdbgOutputDebugString("PMU Controller");
                    break;
                case IDSEL_USB:
                    EdbgOutputDebugString("USB Controller");
                    break;
            }
        }
        EdbgOutputDebugString("\r\n");

        if ( PCIConfig_Read(pDev[i].Bus,
                            pDev[i].Device,
                            pDev[i].Function,
                            PCI_CONFIG_HEAD) & 0x00010000) {

            EdbgOutputDebugString("BARs %X  %X  MemBase: %X  IoBase: %X",
                    PCIConfig_Read(pDev[i].Bus,
                                   pDev[i].Device,
                                   pDev[i].Function,
                                   PCI_CONFIG_BASE0),
                    PCIConfig_Read(pDev[i].Bus,
                                   pDev[i].Device,
                                   pDev[i].Function,
                                   PCI_CONFIG_BASE1),
                    PCIConfig_Read(pDev[i].Bus,
                                   pDev[i].Device,
                                   pDev[i].Function,
                                   PCIBRIDGE_MEMORY),
                    PCIConfig_Read(pDev[i].Bus,
                                   pDev[i].Device,
                                   pDev[i].Function,
                                   PCIBRIDGE_IO));
        } else {
            EdbgOutputDebugString("BARs:");
            for (j = PCI_CONFIG_BASE0; j <= PCI_CONFIG_BASE5; j += 4 ) {
                //EdbgOutputDebugString(" %08lx",
                EdbgOutputDebugString(" %x",
                    PCIConfig_Read(pDev[i].Bus,
                                   pDev[i].Device,
                                   pDev[i].Function,
                                   j));
            }
        }
        EdbgOutputDebugString("\n\r\n\r");

    }
    EdbgOutputDebugString("Bus Dev Fnct Off   MemBase  MemSize  IoBase   IoSize\r\n");
    for (i = 0; i < SortOrder; i++) {
        for (j = 0; j < nSpaceDesc; j++) {
            if (SpaceDesc[j].SortOrder == i) {
                EdbgOutputDebugString("%d  %d  %d   %X   %X %X %X %X\r\n",
                    SpaceDesc[j].Bus,
                    SpaceDesc[j].Device,
                    SpaceDesc[j].Function,
                    SpaceDesc[j].Offset,
                    SpaceDesc[j].MemBase,
                    SpaceDesc[j].MemSize,
                    SpaceDesc[j].IoBase,
                    SpaceDesc[j].IoSize);
            }
        }
    }
}


BOOL
PciInitSearchForDevice(
    ULONG VendorID,
    PULONG Bus,
    PULONG Device,
    PULONG Function
    )
 
/*++
 
Routine Description:
 
    Search for device by vendorId
 
Arguments:
 
    VendorId - supplies key for search
 
Return Value:
 
    Bus,Device,Function return location of device
 
--*/

{
    ULONG i;
    for (i = 0; i < nDev; i++) {
        if (pDev[i].VendorID == VendorID) {
            *Bus = pDev[i].Bus;
            *Device = pDev[i].Device;
            *Function = pDev[i].Function;
            return TRUE;
        }
    }
    return FALSE;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?