www.pudn.com > PlxSdk.rar > PlxChipApi.c
/*******************************************************************************
* Copyright (c) 2007 PLX Technology, Inc.
*
* PLX Technology Inc. licenses this software under specific terms and
* conditions. Use of any of the software or derviatives thereof in any
* product without a PLX Technology chip is strictly prohibited.
*
* PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY,
* EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. PLX makes no guarantee
* or representations regarding the use of, or the results of the use of,
* the software and documentation in terms of correctness, accuracy,
* reliability, currentness, or otherwise; and you rely on the software,
* documentation and results solely at your own risk.
*
* IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
* LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
* OF ANY KIND. IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM
* PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER.
*
******************************************************************************/
/******************************************************************************
*
* File Name:
*
* PlxChipApi.c
*
* Description:
*
* Implements chip-specific API functions
*
* Revision History:
*
* 06-01-07 : PLX SDK v5.10
*
******************************************************************************/
#include "Eep_9000.h"
#include "PciSupport.h"
#include "PlxChipApi.h"
#include "SupportFunc.h"
/******************************************************************************
*
* Function : PlxChip_BoardReset
*
* Description: Resets a device using software reset feature of PLX chip
*
******************************************************************************/
RETURN_CODE
PlxChip_BoardReset(
DEVICE_EXTENSION *pdx
)
{
U8 MU_Enabled;
U8 EepromPresent;
U32 RegValue;
U32 RegInterrupt;
U32 RegHotSwap;
U32 RegPowerMgmnt;
// Clear any PCI errors
PLX_PCI_REG_READ(
pdx,
CFG_COMMAND,
&RegValue
);
if (RegValue & (0xf8 << 24))
{
// Write value back to clear aborts
PLX_PCI_REG_WRITE(
pdx,
CFG_COMMAND,
RegValue
);
}
// Save state of I2O Decode Enable
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_FIFO_CTRL_STAT
);
MU_Enabled = (U8)(RegValue & (1 << 0));
// Determine if an EEPROM is present
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_EEPROM_CTRL_STAT
);
// Make sure S/W Reset & EEPROM reload bits are clear
RegValue &= ~((1 << 30) | (1 << 29));
// Remember if EEPROM is present
EepromPresent = (U8)((RegValue >> 28) & (1 << 0));
// Save interrupt line
PLX_PCI_REG_READ(
pdx,
CFG_INT_LINE,
&RegInterrupt
);
// Save some registers if EEPROM present
if (EepromPresent)
{
PLX_PCI_REG_READ(
pdx,
PCI8311_HS_CAP_ID,
&RegHotSwap
);
PLX_PCI_REG_READ(
pdx,
PCI8311_PM_CSR,
&RegPowerMgmnt
);
}
// Issue Software Reset to hold PLX chip in reset
PLX_9000_REG_WRITE(
pdx,
PCI8311_EEPROM_CTRL_STAT,
RegValue | (1 << 30)
);
// Delay for a bit
Plx_sleep(100);
// Bring chip out of reset
PLX_9000_REG_WRITE(
pdx,
PCI8311_EEPROM_CTRL_STAT,
RegValue
);
// Issue EEPROM reload in case now programmed
PLX_9000_REG_WRITE(
pdx,
PCI8311_EEPROM_CTRL_STAT,
RegValue | (1 << 29)
);
// Delay for a bit
Plx_sleep(10);
// Clear EEPROM reload
PLX_9000_REG_WRITE(
pdx,
PCI8311_EEPROM_CTRL_STAT,
RegValue
);
// Restore I2O Decode Enable state
if (MU_Enabled)
{
// Save state of I2O Decode Enable
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_FIFO_CTRL_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_FIFO_CTRL_STAT,
RegValue | (1 << 0)
);
}
// Restore interrupt line
PLX_PCI_REG_WRITE(
pdx,
CFG_INT_LINE,
RegInterrupt
);
// If EEPROM was present, restore registers
if (EepromPresent)
{
// Mask out HS bits that can be cleared
RegHotSwap &= ~((1 << 23) | (1 << 22) | (1 << 17));
PLX_PCI_REG_WRITE(
pdx,
PCI8311_HS_CAP_ID,
RegHotSwap
);
// Mask out PM bits that can be cleared
RegPowerMgmnt &= ~(1 << 15);
PLX_PCI_REG_READ(
pdx,
PCI8311_PM_CSR,
&RegPowerMgmnt
);
}
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_InterruptEnable
*
* Description: Enables specific interupts of the PLX Chip
*
******************************************************************************/
RETURN_CODE
PlxChip_InterruptEnable(
DEVICE_EXTENSION *pdx,
PLX_INTERRUPT *pPlxIntr
)
{
U32 QueueCsr;
U32 QueueCsr_Original;
U32 RegValue;
PLX_REG_DATA RegData;
// Setup to synchronize access to Interrupt Control/Status Register
RegData.pdx = pdx;
RegData.offset = PCI8311_INT_CTRL_STAT;
RegData.BitsToSet = 0;
RegData.BitsToClear = 0;
if (pPlxIntr->PciMain)
RegData.BitsToSet |= (1 << 8);
if (pPlxIntr->PciAbort)
RegData.BitsToSet |= (1 << 10);
if (pPlxIntr->TargetRetryAbort)
RegData.BitsToSet |= (1 << 12);
if (pPlxIntr->LocalToPci_1)
RegData.BitsToSet |= (1 << 11);
if (pPlxIntr->Doorbell)
RegData.BitsToSet |= (1 << 9);
if (pPlxIntr->PowerManagement)
RegData.BitsToSet |= (1 << 4);
if (pPlxIntr->DmaChannel_0)
{
RegData.BitsToSet |= (1 << 18);
// Make sure DMA done interrupt is enabled & routed to PCI
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA0_MODE
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA0_MODE,
RegValue | (1 << 17) | (1 << 10)
);
}
if (pPlxIntr->DmaChannel_1)
{
RegData.BitsToSet |= (1 << 19);
// Make sure DMA done interrupt is enabled & routed to PCI
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA1_MODE
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA1_MODE,
RegValue | (1 << 17) | (1 << 10)
);
}
// Inbound Post Queue Interrupt Control/Status Register
QueueCsr_Original =
PLX_9000_REG_READ(
pdx,
PCI8311_FIFO_CTRL_STAT
);
QueueCsr = QueueCsr_Original;
if (pPlxIntr->MuOutboundPost)
{
PLX_9000_REG_WRITE(
pdx,
PCI8311_OUTPOST_INT_MASK,
0
);
}
if (pPlxIntr->MuInboundPost)
QueueCsr &= ~(1 << 4);
if (pPlxIntr->MuOutboundOverflow)
{
RegData.BitsToSet |= (1 << 1);
QueueCsr &= ~(1 << 6);
}
// Write register values if they have changed
if (RegData.BitsToSet != 0)
{
// Synchronize write of Interrupt Control/Status Register
PlxSynchronizedRegisterModify(
&RegData
);
}
if (QueueCsr != QueueCsr_Original)
{
PLX_9000_REG_WRITE(
pdx,
PCI8311_FIFO_CTRL_STAT,
QueueCsr
);
}
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_InterruptDisable
*
* Description: Disables specific interrupts of the PLX Chip
*
******************************************************************************/
RETURN_CODE
PlxChip_InterruptDisable(
DEVICE_EXTENSION *pdx,
PLX_INTERRUPT *pPlxIntr
)
{
U32 QueueCsr;
U32 QueueCsr_Original;
U32 RegValue;
PLX_REG_DATA RegData;
// Setup to synchronize access to Interrupt Control/Status Register
RegData.pdx = pdx;
RegData.offset = PCI8311_INT_CTRL_STAT;
RegData.BitsToSet = 0;
RegData.BitsToClear = 0;
if (pPlxIntr->PciMain)
RegData.BitsToClear |= (1 << 8);
if (pPlxIntr->PciAbort)
RegData.BitsToClear |= (1 << 10);
if (pPlxIntr->TargetRetryAbort)
RegData.BitsToClear |= (1 << 12);
if (pPlxIntr->LocalToPci_1)
RegData.BitsToClear |= (1 << 11);
if (pPlxIntr->Doorbell)
RegData.BitsToClear |= (1 << 9);
if (pPlxIntr->PowerManagement)
RegData.BitsToClear |= (1 << 4);
if (pPlxIntr->DmaChannel_0)
{
// Check if DMA interrupt is routed to PCI
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA0_MODE
);
if (RegValue & (1 << 17))
{
RegData.BitsToClear |= (1 << 18);
// Disable DMA interrupt enable
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA0_MODE,
RegValue & ~(1 << 10)
);
}
}
if (pPlxIntr->DmaChannel_1)
{
// Check if DMA interrupt is routed to PCI
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA1_MODE
);
if (RegValue & (1 << 17))
{
RegData.BitsToClear |= (1 << 19);
// Disable DMA interrupt enable
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA1_MODE,
RegValue & ~(1 << 10)
);
}
}
// Inbound Post Queue Interrupt Control/Status Register
QueueCsr_Original =
PLX_9000_REG_READ(
pdx,
PCI8311_FIFO_CTRL_STAT
);
QueueCsr = QueueCsr_Original;
if (pPlxIntr->MuOutboundPost)
{
PLX_9000_REG_WRITE(
pdx,
PCI8311_OUTPOST_INT_MASK,
(1 << 3)
);
}
if (pPlxIntr->MuInboundPost)
QueueCsr |= (1 << 4);
if (pPlxIntr->MuOutboundOverflow)
QueueCsr |= (1 << 6);
// Write register values if they have changed
if (RegData.BitsToClear != 0)
{
// Synchronize write of Interrupt Control/Status Register
PlxSynchronizedRegisterModify(
&RegData
);
}
if (QueueCsr != QueueCsr_Original)
{
PLX_9000_REG_WRITE(
pdx,
PCI8311_FIFO_CTRL_STAT,
QueueCsr
);
}
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_EepromReadByOffset
*
* Description: Read a 32-bit value from the EEPROM at a specified offset
*
******************************************************************************/
RETURN_CODE
PlxChip_EepromReadByOffset(
DEVICE_EXTENSION *pdx,
U16 offset,
U32 *pValue
)
{
// Verify the offset
if ((offset & 0x3) || (offset > 0x200))
{
DebugPrintf(("ERROR - Invalid EEPROM offset\n"));
return ApiInvalidOffset;
}
// Read EEPROM
Plx9000_EepromReadByOffset(
pdx,
Eeprom93CS56,
offset,
pValue
);
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 RegisterSave;
// 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,
PCI8311_ENDIAN_DESC
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_ENDIAN_DESC,
RegisterSave & ~(0xFF << 16)
);
// Write to EEPROM
Plx9000_EepromWriteByOffset(
pdx,
Eeprom93CS56,
offset,
value
);
// Restore EEPROM Write-Protected Address Boundary
PLX_9000_REG_WRITE(
pdx,
PCI8311_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,
PCI8311_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA_COMMAND_STAT,
RegValue & ~((1 << 0) << shift)
);
// Check if the transfer has completed
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_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,
PCI8311_DMA_COMMAND_STAT
);
if ((RegValue & (((1 << 4) | (1 << 0)) << shift)) == 0)
{
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
}
else
{
return ApiDmaInProgress;
}
break;
case DmaAbort:
// Pause the DMA Channel
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA_COMMAND_STAT,
RegValue & ~((1 << 0) << shift)
);
// Check if the transfer has completed
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA_COMMAND_STAT
);
if (RegValue & ((1 << 4) << shift))
return ApiDmaDone;
// Abort the transfer (should cause an interrupt)
PLX_9000_REG_WRITE(
pdx,
PCI8311_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,
PCI8311_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;
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;
}
spin_lock(
&(pdx->Lock_DmaChannel)
);
// Verify that we can open the channel
if (pdx->DmaInfo[i].bOpen)
{
DebugPrintf(("ERROR - DMA channel already opened\n"));
spin_unlock(
&(pdx->Lock_DmaChannel)
);
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;
spin_unlock(
&(pdx->Lock_DmaChannel)
);
// Setup for synchronized access to Interrupt register
RegData.pdx = pdx;
RegData.offset = PCI8311_INT_CTRL_STAT;
RegData.BitsToClear = 0;
spin_lock(
&(pdx->Lock_HwAccess)
);
// 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
(0 << 20) | // Disable Valid mode
(pProp->LocalBusWidth << 0) |
(pProp->WaitStates << 2) |
(pProp->ReadyInput << 6) |
(pProp->BurstInfinite << 7) |
(pProp->Burst << 8) |
(pProp->LocalAddrConst << 11) |
(pProp->DemandMode << 12) |
(pProp->WriteInvalidMode << 13) |
(pProp->EOTPin << 14) |
(pProp->StopTransferMode << 15);
if (channel == 0)
{
// Write DMA mode
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA0_MODE,
RegValue
);
// Clear Dual Address cycle register
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA0_PCI_DAC,
0
);
// Enable DMA channel interrupt
RegData.BitsToSet = (1 << 18);
}
else
{
// Write DMA mode
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA1_MODE,
RegValue
);
// Clear Dual Address cycle register
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA1_PCI_DAC,
0
);
// Enable DMA channel interrupt
RegData.BitsToSet = (1 << 19);
}
// Update interrupt register
PlxSynchronizedRegisterModify(
&RegData
);
spin_unlock(
&(pdx->Lock_HwAccess)
);
DebugPrintf((
"Opened DMA channel %d\n",
channel
));
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaTransferBlock
*
* Description: Performs DMA block transfer
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaTransferBlock(
DEVICE_EXTENSION *pdx,
U8 channel,
PLX_DMA_PARAMS *pParams
)
{
U8 shift;
U16 OffsetDmaMode;
U32 RegValue;
// Verify DMA channel & setup register offsets
switch (channel)
{
case 0:
OffsetDmaMode = PCI8311_DMA0_MODE;
break;
case 1:
OffsetDmaMode = PCI8311_DMA1_MODE;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Set shift for status register
shift = (channel * 8);
// Verify that DMA is not in progress
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA_COMMAND_STAT
);
if ((RegValue & ((1 << 4) << shift)) == 0)
{
DebugPrintf(("ERROR - DMA channel is currently active\n"));
return ApiDmaInProgress;
}
spin_lock(
&(pdx->Lock_DmaChannel)
);
// Verify DMA channel was opened
if (pdx->DmaInfo[channel].bOpen == FALSE)
{
DebugPrintf(("ERROR - DMA channel has not been opened\n"));
spin_unlock(
&(pdx->Lock_DmaChannel)
);
return ApiDmaChannelUnavailable;
}
spin_unlock(
&(pdx->Lock_DmaChannel)
);
spin_lock(
&(pdx->Lock_HwAccess)
);
// Get DMA mode
RegValue =
PLX_9000_REG_READ(
pdx,
OffsetDmaMode
);
// Disable DMA chaining
RegValue &= ~(1 << 9);
// Enable interrupt & route interrupt to PCI
RegValue |= (1 << 10) | (1 << 17);
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode,
RegValue
);
// Write PCI Address
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x4,
pParams->u.PciAddrLow
);
// Write Local Address
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x8,
pParams->LocalAddr
);
// Write Transfer Count
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0xc,
pParams->ByteCount
);
// Write Descriptor Pointer
RegValue = (pParams->TerminalCountIntr << 2) |
(pParams->LocalToPciDma << 3);
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x10,
RegValue
);
// Enable DMA channel
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
spin_unlock(
&(pdx->Lock_HwAccess)
);
DebugPrintf(("Starting DMA transfer...\n"));
// Start DMA
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA_COMMAND_STAT,
RegValue | (((1 << 0) | (1 << 1)) << shift)
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaTransferUserBuffer
*
* Description: Transfers a user-mode buffer using SGL DMA
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaTransferUserBuffer(
DEVICE_EXTENSION *pdx,
U8 channel,
PLX_DMA_PARAMS *pParams
)
{
U8 i;
U8 shift;
U16 OffsetDmaMode;
U32 RegValue;
U32 SglPciAddress;
RETURN_CODE rc;
// Verify DMA channel & setup register offsets
switch (channel)
{
case 0:
OffsetDmaMode = PCI8311_DMA0_MODE;
break;
case 1:
OffsetDmaMode = PCI8311_DMA1_MODE;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// For code readability
i = channel;
// Set shift for status register
shift = (channel * 8);
// Verify that DMA is not in progress
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA_COMMAND_STAT
);
if ((RegValue & ((1 << 4) << shift)) == 0)
{
DebugPrintf(("ERROR - DMA channel is currently active\n"));
return ApiDmaInProgress;
}
spin_lock(
&(pdx->Lock_DmaChannel)
);
// Verify DMA channel was opened
if (pdx->DmaInfo[i].bOpen == FALSE)
{
DebugPrintf(("ERROR - DMA channel has not been opened\n"));
spin_unlock(
&(pdx->Lock_DmaChannel)
);
return ApiDmaChannelUnavailable;
}
// Verify an SGL DMA transfer is not pending
if (pdx->DmaInfo[i].bSglPending)
{
DebugPrintf(("ERROR - An SGL DMA transfer is currently pending\n"));
spin_unlock(
&(pdx->Lock_DmaChannel)
);
return ApiDmaInProgress;
}
// Set the SGL DMA pending flag
pdx->DmaInfo[i].bSglPending = TRUE;
spin_unlock(
&(pdx->Lock_DmaChannel)
);
// Get DMA mode
RegValue =
PLX_9000_REG_READ(
pdx,
OffsetDmaMode
);
// Keep track if local address should remain constant
if (RegValue & (1 << 11))
pdx->DmaInfo[i].bLocalAddrConstant = TRUE;
else
pdx->DmaInfo[i].bLocalAddrConstant = FALSE;
// Enable DMA chaining, interrupt, & route interrupt to PCI
RegValue |= (1 << 9) | (1 << 10) | (1 << 17);
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode,
RegValue
);
// Page-lock user buffer & build SGL
rc =
PlxLockBufferAndBuildSgl(
pdx,
i,
pParams,
&SglPciAddress
);
if (rc != ApiSuccess)
{
DebugPrintf(("ERROR - Unable to lock buffer and build SGL list\n"));
pdx->DmaInfo[i].bSglPending = FALSE;
return rc;
}
spin_lock(
&(pdx->Lock_HwAccess)
);
// Write SGL physical address & set descriptors in PCI space
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x10,
SglPciAddress | (1 << 0)
);
// Enable DMA channel
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
spin_unlock(
&(pdx->Lock_HwAccess)
);
DebugPrintf(("Starting DMA transfer...\n"));
// Start DMA
PLX_9000_REG_WRITE(
pdx,
PCI8311_DMA_COMMAND_STAT,
RegValue | (((1 << 0) | (1 << 1)) << shift)
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaChannelClose
*
* Description: Close a previously opened channel
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaChannelClose(
DEVICE_EXTENSION *pdx,
U8 channel,
BOOLEAN bCheckInProgress
)
{
U8 i;
U32 RegValue;
DebugPrintf((
"Closing DMA channel %d...\n",
channel
));
// Verify valid DMA channel
switch (channel)
{
case 0:
case 1:
i = channel;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Verify DMA channel was opened
if (pdx->DmaInfo[i].bOpen == FALSE)
{
DebugPrintf(("ERROR - DMA channel has not been opened\n"));
return ApiDmaChannelUnavailable;
}
// Check DMA status
RegValue =
PLX_9000_REG_READ(
pdx,
PCI8311_DMA_COMMAND_STAT
);
// Shift status for channel 1
if (channel == 1)
RegValue = RegValue >> 8;
// Verify DMA is not in progress
if ((RegValue & (1 << 4)) == 0)
{
// DMA is still in progress
if (bCheckInProgress)
{
if (RegValue & (1 << 0))
return ApiDmaInProgress;
else
return ApiDmaPaused;
}
DebugPrintf(("DMA in progress, aborting...\n"));
// Force DMA abort, which may generate a DMA done interrupt
PlxChip_DmaControl(
pdx,
channel,
DmaAbort
);
}
spin_lock(
&(pdx->Lock_DmaChannel)
);
// Close the channel
pdx->DmaInfo[i].bOpen = FALSE;
// Clear owner information
pdx->DmaInfo[i].pOwner = NULL;
spin_unlock(
&(pdx->Lock_DmaChannel)
);
// If DMA is hung, an SGL transfer could be pending, so release user buffer
if (pdx->DmaInfo[i].bSglPending)
{
PlxSglDmaTransferComplete(
pdx,
i
);
}
// Release memory previously used for SGL descriptors
if (pdx->DmaInfo[i].SglBuffer.pKernelVa != NULL)
{
DebugPrintf((
"Releasing memory used for SGL descriptors...\n"
));
Plx_dma_buffer_free(
pdx,
&pdx->DmaInfo[i].SglBuffer
);
}
return ApiSuccess;
}