/******************************************************************************
 *
 * Function   :  PlxDmaSglTransfer
 *
 * Description:  Performs a DMA SGL transfer
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaSglTransfer(
    DEVICE_EXTENSION     *pdx,
    DMA_CHANNEL           channel,
    DMA_TRANSFER_ELEMENT *pDmaData,
    VOID                 *pIrp
    )
{
    U8    i;
    U8    shift;
    U16   OffsetDesc;
    U32   RegValue;
    PVOID SglPciAddress;


    // Verify valid DMA channel
    switch (channel)
    {
        case PrimaryPciChannel0:
            i          = 0;
            shift      = 0;
            OffsetDesc = PCI9080_DMA0_DESC_PTR;
            break;

        case PrimaryPciChannel1:
            i          = 1;
            shift      = 8;
            OffsetDesc = PCI9080_DMA1_DESC_PTR;
            break;

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

    // Verify that DMA is not in progress
    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9080_DMA0_COMMAND_STAT
            );

    if ((RegValue & ((1 << 4) << shift)) == 0)
    {
        DebugPrintf(("ERROR - DmaTransfer() Channel is active\n"));
        return ApiDmaInProgress;
    }

    spin_lock(
        &(pdx->Lock_DmaChannel)
        );

    // Verify DMA Channel was opened correctly
    if (pdx->DmaInfo[i].state != DmaStateSgl)
    {
        DebugPrintf(("ERROR - DMA channel has not been opened for SGL DMA\n"));

        spin_unlock(
            &(pdx->Lock_DmaChannel)
            );

        return ApiDmaChannelUnavailable;
    }

    // Verify a DMA transfer is not pending
    if (pdx->DmaInfo[i].bPending)
    {
        DebugPrintf((
            "ERROR - A DMA transfer is currently in progress\n"
            ));

        spin_unlock(
            &(pdx->Lock_DmaChannel)
            );

        return ApiDmaInProgress;
    }

    // Set the DMA pending flag
    pdx->DmaInfo[i].bPending = TRUE;

    spin_unlock(
        &(pdx->Lock_DmaChannel)
        );

    SglPciAddress =
        PlxLockBufferAndBuildSgl(
            pdx,
            i,
            pDmaData
            );

    if (SglPciAddress == NULL)
    {
        DebugPrintf(("ERROR - Unable to lock buffer and build SGL list\n"));
        pdx->DmaInfo[i].bPending = FALSE;
        return ApiDmaSglBuildFailed;
    }

    spin_lock(
        &(pdx->Lock_HwAccess)
        );

    // Write SGL physical address & set descriptors in PCI space
    PLX_REG_WRITE(
        pdx,
        OffsetDesc,
        (U32)SglPciAddress | (1 << 0)
        );

    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9080_DMA0_COMMAND_STAT
            );

    // Enable DMA channel
    PLX_REG_WRITE(
        pdx,
        PCI9080_DMA0_COMMAND_STAT,
        RegValue | ((1 << 0) << shift)
        );

    DebugPrintf(("Starting DMA transfer...\n"));

    // Start DMA
    PLX_REG_WRITE(
        pdx,
        PCI9080_DMA0_COMMAND_STAT,
        RegValue | (((1 << 0) | (1 << 1)) << shift)
        );

    spin_unlock(
        &(pdx->Lock_HwAccess)
        );

    return ApiSuccess;
}
Esempio n. 2
0
/******************************************************************************
 *
 * Function   :  PlxChip_DmaTransferUserBuffer
 *
 * Description:  Transfers a user-mode buffer using SGL DMA
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_DmaTransferUserBuffer(
    DEVICE_EXTENSION *pdx,
    U8                channel,
    PLX_DMA_PARAMS   *pParams,
    VOID             *pOwner
    )
{
    U8         shift;
    U16        OffsetMode;
    U32        RegValue;
    U32        SglPciAddress;
    BOOLEAN    bBits64;
    PLX_STATUS rc;


    // Verify DMA channel & setup register offsets
    switch (channel)
    {
        case 0:
            OffsetMode = PCI9056_DMA0_MODE;
            break;

        case 1:
            OffsetMode = PCI9056_DMA1_MODE;
            break;

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

    // Verify owner
    if (pdx->DmaInfo[channel].pOwner != pOwner)
    {
        DebugPrintf(("ERROR - DMA owned by different process\n"));
        return ApiDeviceInUse;
    }

    // Set shift for status register
    shift = (channel * 8);

    // Verify that DMA is not in progress
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_DMA_COMMAND_STAT
            );

    if ((RegValue & ((1 << 4) << shift)) == 0)
    {
        DebugPrintf(("ERROR - DMA channel is currently active\n"));
        return ApiDmaInProgress;
    }

    spin_lock(
        &(pdx->Lock_Dma[channel])
        );

    // Verify DMA channel was opened
    if (pdx->DmaInfo[channel].bOpen == FALSE)
    {
        DebugPrintf(("ERROR - DMA channel has not been opened\n"));

        spin_unlock(
            &(pdx->Lock_Dma[channel])
            );

        return ApiDmaChannelUnavailable;
    }

    // Verify an SGL DMA transfer is not pending
    if (pdx->DmaInfo[channel].bSglPending)
    {
        DebugPrintf(("ERROR - An SGL DMA transfer is currently pending\n"));

        spin_unlock(
            &(pdx->Lock_Dma[channel])
            );

        return ApiDmaInProgress;
    }

    // Set the SGL DMA pending flag
    pdx->DmaInfo[channel].bSglPending = TRUE;

    spin_unlock(
        &(pdx->Lock_Dma[channel])
        );

    // Get DMA mode
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            OffsetMode
            );

    // Keep track if local address should remain constant
    if (RegValue & (1 << 11))
        pdx->DmaInfo[channel].bConstAddrLocal = TRUE;
    else
        pdx->DmaInfo[channel].bConstAddrLocal = FALSE;

    // Page-lock user buffer & build SGL
    rc =
        PlxLockBufferAndBuildSgl(
            pdx,
            channel,
            pParams,
            &SglPciAddress,
            &bBits64
            );

    if (rc != ApiSuccess)
    {
        DebugPrintf(("ERROR - Unable to lock buffer and build SGL list\n"));
        pdx->DmaInfo[channel].bSglPending = FALSE;
        return rc;
    }

    spin_lock(
        &(pdx->Lock_Dma[channel])
        );

    // Disable valid mode
    RegValue &= ~(1 << 20);

    // Enable DMA chaining, interrupt, & route interrupt to PCI
    RegValue |= (1 << 9) | (1 << 10) | (1 << 17);

    // Enable dual-addressing DMA if 64-bit DMA is required
    if (bBits64)
        RegValue |= (1 << 18);
    else
        RegValue &= ~(1 << 18);

    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode,
        RegValue
        );

    // Clear DAC upper 32-bit PCI address in case it contains non-zero value
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA0_PCI_DAC + (channel * sizeof(U32)),
        0
        );

    // Write SGL physical address & set descriptors in PCI space
    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode + 0x10,
        SglPciAddress | (1 << 0)
        );

    // Enable DMA channel
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_DMA_COMMAND_STAT
            );

    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA_COMMAND_STAT,
        RegValue | ((1 << 0) << shift)
        );

    spin_unlock(
        &(pdx->Lock_Dma[channel])
        );

    DebugPrintf(("Starting DMA transfer...\n"));

    // Start DMA
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA_COMMAND_STAT,
        RegValue | (((1 << 0) | (1 << 1)) << shift)
        );

    return ApiSuccess;
}