⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 plxchipapi.c

📁 PCI接口产品中桥芯片PLX6000、PLX8000、PLX9000和PLXsrv驱动模块源码
💻 C
📖 第 1 页 / 共 3 页
字号:
     *
     *        Additionally, there is no way to determine the 9054
     *        version from the Host/PCI side.  To solve this, the
     *        PCI Revision ID is used to "tell" the host which
     *        version the 9054 is.  This value is either set by the
     *        EEPROM or the local CPU, which has the ability to
     *        determine the 9054 version.  The protocol is:
     *
     *          if (Hard-coded RevisionID != 0xA)  // Chip is not AA or AB
     *              Use EEPROM Control Register
     *          else
     *          {
     *              if (PCIRevisionID == 0xb)
     *                  Use EEPROM Control Register
     *              else
     *                  Use VPD access
     *          }
     ***************************************************************/

    // Default to VPD access
    bUseVpd = TRUE;

    // Get hard-coded revision ID
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9054_REVISION_ID
            );

    // Check if chip is other than AA or AB
    if (RegValue != 0xA)
    {
        bUseVpd = FALSE;
    }
    else
    {
        // Get PCI Revision ID
        PLX_PCI_REG_READ(
            pdx,
            PCI9054_REV_ID,
            &RegValue
            );

        // Check reported 9054 Version
        if ((RegValue & 0xFF) == 0xB)
        {
            // 9054 AB version is reported
            bUseVpd = FALSE;
        }
    }

    // Access the EEPROM
    if (bUseVpd == FALSE)
    {
        // 9054 AB or newer revision, so use EEPROM register

        // Read EEPROM
        Plx9000_EepromReadByOffset(
            pdx,
            Eeprom93CS56,
            offset,
            pValue
            );
    }
    else
    {
        // 9054 AA or unspecified version, so use VPD access

        // Check if New capabilities are enabled
        if (PlxGetExtendedCapabilityOffset(
                pdx,
                CAP_ID_VPD
                ) == 0)
        {
            return ApiVPDNotSupported;
        }

        // Read EEPROM value
        rc =
            PlxPciVpdRead(
                pdx,
                offset,
                pValue
                );

        if (rc != ApiSuccess)
            return ApiFailed;
    }

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxChip_EepromWriteByOffset
 *
 * Description:  Write a 32-bit value to the EEPROM at a specified offset
 *
 ******************************************************************************/
RETURN_CODE
PlxChip_EepromWriteByOffset(
    DEVICE_EXTENSION *pdx,
    U16               offset,
    U32               value
    )
{
    U32         RegValue;
    U32         RegisterSave;
    BOOLEAN     bUseVpd;
    RETURN_CODE rc;


    // Verify the offset
    if ((offset & 0x3) || (offset > 0x200))
    {
        DebugPrintf(("ERROR - Invalid EEPROM offset\n"));
        return ApiInvalidOffset;
    }

    // Unprotect the EEPROM for write access
    RegisterSave =
        PLX_9000_REG_READ(
            pdx,
            PCI9054_ENDIAN_DESC
            );

    PLX_9000_REG_WRITE(
        pdx,
        PCI9054_ENDIAN_DESC,
        RegisterSave & ~(0xFF << 16)
        );

    /****************************************************************
     * Note:  In the 9054, the EEPROM can be accessed either
     *        through the VPD or by the EEPROM control register.
     *
     *        However, the EEPROM control register does not work
     *        in the 9054 AA version and VPD access often fails.
     *        The 9054 AB version fixes the EEPROM control register
     *        access, but VPD may still fail.
     *
     *        As a result, PLX software does the following:
     *
     *          if (AB or newer chip)
     *              Use EEPROM Control Register
     *          else
     *              Use VPD access
     *
     *        Additionally, there is no way to determine the 9054
     *        version from the Host/PCI side.  To solve this, the
     *        PCI Revision ID is used to "tell" the host which
     *        version the 9054 is.  This value is either set by the
     *        EEPROM or the local CPU, which has the ability to
     *        determine the 9054 version.  The protocol is:
     *
     *          if (Hard-coded RevisionID != 0xA)  // Chip is not AA or AB
     *              Use EEPROM Control Register
     *          else
     *          {
     *              if (PCIRevisionID == 0xb)
     *                  Use EEPROM Control Register
     *              else
     *                  Use VPD access
     *          }
     ***************************************************************/

    // Default to VPD access
    bUseVpd = TRUE;

    // Get hard-coded revision ID
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9054_REVISION_ID
            );

    // Check if chip is other than AA or AB
    if (RegValue != 0xA)
    {
        bUseVpd = FALSE;
    }
    else
    {
        // Get PCI Revision ID
        PLX_PCI_REG_READ(
            pdx,
            PCI9054_REV_ID,
            &RegValue
            );

        // Check reported 9054 Version
        if ((RegValue & 0xFF) == 0xB)
        {
            // 9054 AB version is reported
            bUseVpd = FALSE;
        }
    }

    // Access the EEPROM
    if (bUseVpd == FALSE)
    {
        // 9054 AB or newer revision, so use EEPROM register

        // Write to EEPROM
        Plx9000_EepromWriteByOffset(
            pdx,
            Eeprom93CS56,
            offset,
            value
            );
    }
    else
    {
        // 9054 AA or unspecified version, so use VPD access

        // Check if New capabilities are enabled
        if (PlxGetExtendedCapabilityOffset(
                pdx,
                CAP_ID_VPD
                ) == 0)
        {
            return ApiVPDNotSupported;
        }

        // Write value to the EEPROM
        rc =
            PlxPciVpdWrite(
                pdx,
                offset,
                value
                );

        if (rc != ApiSuccess)
        {
            // Restore EEPROM Write-Protected Address Boundary
            PLX_9000_REG_WRITE(
                pdx,
                PCI9054_ENDIAN_DESC,
                RegisterSave
                );

            return ApiFailed;
        }
    }

    // Restore EEPROM Write-Protected Address Boundary
    PLX_9000_REG_WRITE(
        pdx,
        PCI9054_ENDIAN_DESC,
        RegisterSave
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxChip_DmaControl
 *
 * Description:  Control the DMA engine
 *
 ******************************************************************************/
RETURN_CODE
PlxChip_DmaControl(
    DEVICE_EXTENSION *pdx,
    U8                channel,
    PLX_DMA_COMMAND   command
    )
{
    U8  i;
    U8  shift;
    U32 RegValue;


    // Verify valid DMA channel
    switch (channel)
    {
        case 0:
        case 1:
            i     = channel;
            shift = (channel * 8);
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    switch (command)
    {
        case DmaPause:
            // Pause the DMA Channel
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            PLX_9000_REG_WRITE(
                pdx,
                PCI9054_DMA_COMMAND_STAT,
                RegValue & ~((1 << 0) << shift)
                );

            // Check if the transfer has completed
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            if (RegValue & ((1 << 4) << shift))
                return ApiDmaDone;
            break;

        case DmaResume:
            // Verify that the DMA Channel is paused
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            if ((RegValue & (((1 << 4) | (1 << 0)) << shift)) == 0)
            {
                PLX_9000_REG_WRITE(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT,
                    RegValue | ((1 << 0) << shift)
                    );
            }
            else
            {
                return ApiDmaInProgress;
            }
            break;

        case DmaAbort:
            // Pause the DMA Channel
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            PLX_9000_REG_WRITE(
                pdx,
                PCI9054_DMA_COMMAND_STAT,
                RegValue & ~((1 << 0) << shift)
                );

            // Check if the transfer has completed
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            if (RegValue & ((1 << 4) << shift))
                return ApiDmaDone;

            // Abort the transfer (should cause an interrupt)
            PLX_9000_REG_WRITE(
                pdx,
                PCI9054_DMA_COMMAND_STAT,
                RegValue | ((1 << 2) << shift)
                );
            break;

        default:
            return ApiDmaCommandInvalid;
    }

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxChip_DmaStatus
 *
 * Description:  Get status of a DMA channel
 *
 ******************************************************************************/
RETURN_CODE
PlxChip_DmaStatus(
    DEVICE_EXTENSION *pdx,
    U8                channel
    )
{
    U32 RegValue;


    // Verify valid DMA channel
    switch (channel)
    {
        case 0:
        case 1:
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    // Return the current DMA status
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9054_DMA_COMMAND_STAT
            );

    // Shift status for channel 1
    if (channel == 1)
        RegValue = RegValue >> 8;

    if ((RegValue & ((1 << 4) | (1 << 0))) == 0)
        return ApiDmaPaused;

    if (RegValue & (1 << 4))
        return ApiDmaDone;

    return ApiDmaInProgress;
}




/******************************************************************************
 *
 * Function   :  PlxChip_DmaChannelOpen
 *
 * Description:  Open a DMA channel
 *
 ******************************************************************************/
RETURN_CODE
PlxChip_DmaChannelOpen(
    DEVICE_EXTENSION *pdx,
    U8                channel,
    PLX_DMA_PROP     *pProp,
    VOID             *pOwner
    )
{
    U8           i;
    U32          RegValue;
    KIRQL        OriginalIrqL;
    PLX_REG_DATA RegData;


    // Verify valid DMA channel
    switch (channel)
    {
        case 0:
        case 1:
            i = channel;
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    KeAcquireSpinLock(
        &(pdx->Lock_DmaChannel),
        &OriginalIrqL
        );

    // Verify that we can open the channel
    if (pdx->DmaInfo[i].bOpen)
    {
        DebugPrintf(("ERROR - DMA channel already opened\n"));

        KeReleaseSpinLock(
            &(pdx->Lock_DmaChannel),
            OriginalIrqL
            );

        return ApiDmaChannelUnavailable;
    }

    // Open the channel
    pdx->DmaInfo[i].bOpen = TRUE;

    // Record the Owner
    pdx->DmaInfo[i].pOwner = pOwner;

    // No SGL DMA is pending
    pdx->DmaInfo[i].bSglPending = FALSE;

    KeReleaseSpinLock(
        &(pdx->Lock_DmaChannel),
        OriginalIrqL
        );

    // Setup for synchronized access to Interrupt register
    RegData.pdx         = pdx;
    RegData.offset      = PCI9054_INT_CTRL_STAT;
    RegData.BitsToClear = 0;

    KeAcquireSpinLock(
        &(pdx->Lock_HwAccess),
        &OriginalIrqL
        );

    // Setup DMA properties
    RegValue =
        (0 <<  9) |                  // Disable chaining
        (1 << 10) |                  // Enable DMA done interrupt
        (1 << 17) |                  // Route interrupt to PCI
        (0 << 18) |                  // Disable Dual-Addressing
        (pProp->LocalBusWidth    <<  0) |
        (pProp->WaitStates       <<  2) |
        (pProp->ReadyInput       <<  6) |
        (pProp->BurstInfinite    <<  7) |
        (pProp->Burst            <<  8) |
        (pProp->LocalAddrConst   << 11) |
        (pProp->DemandMode       << 12) |
        (pProp->WriteInvalidMode << 13) |

⌨️ 快捷键说明

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