📄 plxchipapi.c
字号:
*
* 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 + -