/****************************************************************************** * * 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; }
/****************************************************************************** * * 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; }