📄 plxchip.c
字号:
/*******************************************************************************
* Copyright (c) 2006 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:
*
* PlxChip.c
*
* Description:
*
* This file contains functions specific to a PLX Chip.
*
* Revision History:
*
* 02-01-06 : PCI SDK v4.40
*
******************************************************************************/
#include "DriverDefs.h"
#include "PciSupport.h"
#include "PlxInterrupt.h"
#include "SupportFunc.h"
/******************************************************************************
*
* Function : PlxChipPciInterruptEnable
*
* Description: Enables the PLX Chip PCI Interrupt
*
*****************************************************************************/
BOOLEAN
PlxChipPciInterruptEnable(
DEVICE_EXTENSION *pdx
)
{
U32 RegInterrupt;
RegInterrupt =
PLX_REG_READ(
pdx,
PCI9054_INT_CTRL_STAT
);
PLX_REG_WRITE(
pdx,
PCI9054_INT_CTRL_STAT,
RegInterrupt | (1 << 8)
);
return TRUE;
}
/******************************************************************************
*
* Function : PlxChipPciInterruptDisable
*
* Description: Disables the PLX Chip PCI Interrupt
*
*****************************************************************************/
BOOLEAN
PlxChipPciInterruptDisable(
DEVICE_EXTENSION *pdx
)
{
U32 RegInterrupt;
RegInterrupt =
PLX_REG_READ(
pdx,
PCI9054_INT_CTRL_STAT
);
PLX_REG_WRITE(
pdx,
PCI9054_INT_CTRL_STAT,
RegInterrupt & ~(1 << 8)
);
return TRUE;
}
/******************************************************************************
*
* Function : PlxPciBoardReset
*
* Description: Resets a device using software reset feature of PLX chip
*
******************************************************************************/
VOID
PlxPciBoardReset(
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_REG_READ(
pdx,
PCI9054_FIFO_CTRL_STAT
);
MU_Enabled = (U8)(RegValue & (1 << 0));
// Determine if an EEPROM is present
RegValue =
PLX_REG_READ(
pdx,
PCI9054_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,
PCI9054_HS_CAP_ID,
&RegHotSwap
);
PLX_PCI_REG_READ(
pdx,
PCI9054_PM_CSR,
&RegPowerMgmnt
);
}
// Issue Software Reset to hold PLX chip in reset
PLX_REG_WRITE(
pdx,
PCI9054_EEPROM_CTRL_STAT,
RegValue | (1 << 30)
);
// Delay for a bit
Plx_sleep(100);
// Bring chip out of reset
PLX_REG_WRITE(
pdx,
PCI9054_EEPROM_CTRL_STAT,
RegValue
);
// Issue EEPROM reload in case now programmed
PLX_REG_WRITE(
pdx,
PCI9054_EEPROM_CTRL_STAT,
RegValue | (1 << 29)
);
// Delay for a bit
Plx_sleep(10);
// Clear EEPROM reload
PLX_REG_WRITE(
pdx,
PCI9054_EEPROM_CTRL_STAT,
RegValue
);
// Restore I2O Decode Enable state
if (MU_Enabled)
{
// Save state of I2O Decode Enable
RegValue =
PLX_REG_READ(
pdx,
PCI9054_FIFO_CTRL_STAT
);
PLX_REG_WRITE(
pdx,
PCI9054_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,
PCI9054_HS_CAP_ID,
RegHotSwap
);
// Mask out PM bits that can be cleared
RegPowerMgmnt &= ~(1 << 15);
PLX_PCI_REG_READ(
pdx,
PCI9054_PM_CSR,
&RegPowerMgmnt
);
}
}
/******************************************************************************
*
* Function : PlxChipSetInterruptNotifyFlags
*
* Description: Sets the interrupt notification flags of a wait object
*
******************************************************************************/
VOID
PlxChipSetInterruptNotifyFlags(
PLX_INTR *pPlxIntr,
PLX_WAIT_OBJECT *pWaitObject
)
{
// Clear notify events
pWaitObject->NotifyOnInterrupt = INTR_TYPE_NONE;
if (pPlxIntr->IopToPciInt)
pWaitObject->NotifyOnInterrupt |= INTR_TYPE_LOCAL_1;
if (pPlxIntr->PciAbort)
pWaitObject->NotifyOnInterrupt |= INTR_TYPE_PCI_ABORT;
if (pPlxIntr->PciDoorbell)
pWaitObject->NotifyOnInterrupt |= INTR_TYPE_DOORBELL;
if (pPlxIntr->OutboundPost)
pWaitObject->NotifyOnInterrupt |= INTR_TYPE_OUTBOUND_POST;
if (pPlxIntr->PciDmaChannel0)
pWaitObject->NotifyOnInterrupt |= INTR_TYPE_DMA_0;
if (pPlxIntr->PciDmaChannel1)
pWaitObject->NotifyOnInterrupt |= INTR_TYPE_DMA_1;
}
/******************************************************************************
*
* Function : PlxChipGetSpace
*
* Description: Returns the BAR index and remap register offset for a space
*
******************************************************************************/
VOID
PlxChipGetSpace(
DEVICE_EXTENSION *pdx,
IOP_SPACE IopSpace,
U8 *pBarIndex,
U16 *pOffset_RegRemap
)
{
U32 RegValue;
switch (IopSpace)
{
case IopSpace0:
*pOffset_RegRemap = PCI9054_SPACE0_REMAP;
// Check if BAR2/BAR3 are shifted to BAR0/BAR1
RegValue =
PLX_REG_READ(
pdx,
PCI9054_ENDIAN_DESC
);
if ((RegValue & 0x300) == 0x200)
{
*pBarIndex = 1;
}
else
{
*pBarIndex = 2;
}
break;
case IopSpace1:
*pOffset_RegRemap = PCI9054_SPACE1_REMAP;
/*********************************************************************
* Note: Space 1 is a special case. If the I2O Decode Enable bit
* is set, BAR3 is moved to BAR0.
********************************************************************/
RegValue =
PLX_REG_READ(
pdx,
PCI9054_FIFO_CTRL_STAT
);
if (RegValue & (1 << 0))
{
// I2O Decode is enbled, use BAR0 for Space 1
*pBarIndex = 0;
}
else
{
// Check if BAR2/BAR3 are shifted to BAR0/BAR1
RegValue =
PLX_REG_READ(
pdx,
PCI9054_ENDIAN_DESC
);
if ((RegValue & 0x300) == 0x200)
{
*pBarIndex = 2;
}
else
{
*pBarIndex = 3;
}
}
break;
default:
*pBarIndex = (U8)-1;
DebugPrintf(("ERROR - Invalid Space\n"));
break;
}
}
/******************************************************************************
*
* Function : PlxChipPostCommonBufferProperties
*
* Description: Post the common buffer properties to the device
*
******************************************************************************/
VOID
PlxChipPostCommonBufferProperties(
DEVICE_EXTENSION *pdx,
U32 PhysicalAddress,
U32 Size
)
{
// Write the Physical Address
PLX_REG_WRITE(
pdx,
PCI9054_MAILBOX3,
PhysicalAddress
);
// Write the Size
PLX_REG_WRITE(
pdx,
PCI9054_MAILBOX4,
Size
);
}
/******************************************************************************
*
* Function : PlxIsPowerLevelSupported
*
* Description: Verify that the power level is supported
*
******************************************************************************/
BOOLEAN
PlxIsPowerLevelSupported(
DEVICE_EXTENSION *pdx,
PLX_POWER_LEVEL PowerLevel
)
{
U32 RegisterValue;
// Check if New capabilities are enabled
if (PlxIsNewCapabilityEnabled(
pdx,
CAPABILITY_POWER_MANAGEMENT
) == FALSE)
{
return FALSE;
}
// Verify that the Power State is supported
switch (PowerLevel)
{
case D0:
case D3Hot:
break;
case D1:
case D2:
// Get the Power Control/Status
PLX_PCI_REG_READ(
pdx,
PCI9054_PM_CAP_ID,
&RegisterValue
);
if ((PowerLevel == D1) && !(RegisterValue & (1 << 25)))
return FALSE;
if ((PowerLevel == D2) && !(RegisterValue & (1 << 26)))
return FALSE;
break;
case D0Uninitialized: // D0Uninitialized cannot be set by software
case D3Cold: // D3Cold cannot be set by software
default:
return FALSE;
}
return TRUE;
}
/******************************************************************************
*
* Function : PlxIsNewCapabilityEnabled
*
* Description: Verifies access to the new Capabilities registers
*
******************************************************************************/
BOOLEAN
PlxIsNewCapabilityEnabled(
DEVICE_EXTENSION *pdx,
U8 CapabilityToVerify
)
{
U32 RegisterValue;
U32 RegisterPmCapability;
U32 RegisterHsCapability;
U32 RegisterVpdCapability;
// Check if New capabilities are enabled
PLX_PCI_REG_READ(
pdx,
PCI9054_COMMAND,
&RegisterValue
);
if ((RegisterValue & (1 << 20)) == 0)
return FALSE;
// Get capabilities pointer
PLX_PCI_REG_READ(
pdx,
PCI9054_CAP_PTR,
&RegisterValue
);
// Mask non-relevant bits
RegisterValue = RegisterValue & 0xFF;
if (RegisterValue == 0)
return FALSE;
// Get PM capabilities pointer
PLX_PCI_REG_READ(
pdx,
PCI9054_PM_CAP_ID,
&RegisterPmCapability
);
// Mask non-relevant bits
RegisterPmCapability = (RegisterPmCapability >> 8) & 0xFF;
// Get HS capabilities pointer
PLX_PCI_REG_READ(
pdx,
PCI9054_HS_CAP_ID,
&RegisterHsCapability
);
// Mask non-relevant bits
RegisterHsCapability = (RegisterHsCapability >> 8) & 0xFF;
// Get VPD capabilities pointer
PLX_PCI_REG_READ(
pdx,
PCI9054_VPD_CAP_ID,
&RegisterVpdCapability
);
// Mask non-relevant bits
RegisterVpdCapability = (RegisterVpdCapability >> 8) & 0xFF;
if (CapabilityToVerify & CAPABILITY_POWER_MANAGEMENT)
{
if ( (RegisterValue != PCI9054_PM_CAP_ID) &&
(RegisterPmCapability != PCI9054_PM_CAP_ID) &&
(RegisterHsCapability != PCI9054_PM_CAP_ID) &&
(RegisterVpdCapability != PCI9054_PM_CAP_ID) )
{
return FALSE;
}
}
if (CapabilityToVerify & CAPABILITY_HOT_SWAP)
{
if ( (RegisterValue != PCI9054_HS_CAP_ID) &&
(RegisterPmCapability != PCI9054_HS_CAP_ID) &&
(RegisterHsCapability != PCI9054_HS_CAP_ID) &&
(RegisterVpdCapability != PCI9054_HS_CAP_ID) )
{
return FALSE;
}
}
if (CapabilityToVerify & CAPABILITY_VPD)
{
if ( (RegisterValue != PCI9054_VPD_CAP_ID) &&
(RegisterPmCapability != PCI9054_VPD_CAP_ID) &&
(RegisterHsCapability != PCI9054_VPD_CAP_ID) &&
(RegisterVpdCapability != PCI9054_VPD_CAP_ID) )
{
return FALSE;
}
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -