📄 p9054_lib.c
字号:
htod32((dwStartOfChain + sizeof(DMA_LIST)*(dwPageNumber+1))
| BIT0 | (fIsRead ? BIT3 : 0));
dwMemoryCopied += hDma->dma.Page[dwPageNumber].dwBytes;
}
pList[dwPageNumber - 1].dwDPR |= htod32(BIT1); // mark end of chain
dwDMAMODE |= BIT9; // chain transfer
dwDMADPR = dwStartOfChain | BIT0;
P9054_WriteReg (hPlx, P9054_DMAMODE + dwChannelShift, dwDMAMODE);
P9054_WriteReg (hPlx, P9054_DMADPR + dwChannelShift, dwDMADPR);
}
return hDma;
Exit:
if (hDma!=NULL)
P9054_DMAClose(hPlx,hDma);
return NULL;
}
void P9054_DMAClose (P9054_HANDLE hPlx, P9054_DMA_HANDLE hDma)
{
if (hDma->dma.hDma)
WD_DMAUnlock(hPlx->hWD, &hDma->dma);
if (hDma->dmaList.hDma)
WD_DMAUnlock(hPlx->hWD, &hDma->dmaList);
free (hDma);
}
BOOL P9054_DMAIsDone (P9054_HANDLE hPlx, P9054_DMA_HANDLE hDma)
{
return (P9054_ReadByte(hPlx, P9054_ADDR_REG, P9054_DMACSR +
hDma->dmaChannel) & (BYTE)BIT4) == (BYTE)BIT4;
}
void P9054_DMAStart (P9054_HANDLE hPlx, P9054_DMA_HANDLE hDma, BOOL fBlocking)
{
P9054_WriteByte (hPlx, P9054_ADDR_REG, P9054_DMACSR + hDma->dmaChannel,
BIT0 | BIT1);
//Busy wait for plx to finish transfer
if (fBlocking)
while (!P9054_DMAIsDone(hPlx, hDma))
;
}
BOOL P9054_DMAReadWriteBlock (P9054_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf,
DWORD dwBytes, BOOL fIsRead, P9054_MODE mode, P9054_DMA_CHANNEL dmaChannel)
{
P9054_DMA_HANDLE hDma;
DWORD dwOptions = fIsRead ? DMA_READ_FROM_DEVICE : DMA_WRITE_TO_DEVICE;
if (dwBytes==0)
return TRUE;
// Initiate Scatter/Gather DMA:
hDma = P9054_DMAOpen(hPlx, dwLocalAddr, &buf, dwOptions, dwBytes, mode, dmaChannel);
if (!hDma)
return FALSE;
P9054_DMAStart(hPlx, hDma, TRUE);
P9054_DMAClose(hPlx, hDma);
return TRUE;
}
BOOL P9054_EEPROMPresent(P9054_HANDLE hPlx)
{
return (P9054_ReadReg(hPlx, P9054_CNTRL) & BIT28)==BIT28;
}
BOOL P9054_EEPROMValid(P9054_HANDLE hPlx)
{
WD_PCI_CONFIG_DUMP pciCnf;
BYTE bVal;
// check that a blank or programmed serial EEPROM is present
sprintf(P9054_ErrorString, "serial EEPROM is not present\n");
if (!P9054_EEPROMPresent(hPlx))
return FALSE;
// check next capability pointers.
sprintf(P9054_ErrorString, "capability pointers are incorrect\n");
BZERO (pciCnf);
pciCnf.pciSlot = hPlx->pciSlot;
pciCnf.pBuffer = &bVal;
pciCnf.fIsRead = TRUE;
pciCnf.dwBytes = 1;
pciCnf.dwOffset = PCI_CAP;
WD_PciConfigDump(hPlx->hWD, &pciCnf);
if (bVal != (BYTE)P9054_PMCAPID)
return FALSE;
pciCnf.dwOffset = P9054_PMNEXT;
WD_PciConfigDump(hPlx->hWD, &pciCnf);
if (bVal != (BYTE)P9054_HS_CNTL)
return FALSE;
pciCnf.dwOffset = P9054_HS_NEXT;
WD_PciConfigDump(hPlx->hWD, &pciCnf);
if (bVal != (BYTE)P9054_VPD_CNTL)
return FALSE;
pciCnf.dwOffset = P9054_VPD_NEXT;
WD_PciConfigDump(hPlx->hWD, &pciCnf);
if (bVal != 0)
return FALSE;
P9054_ErrorString[0] = '\0';
return TRUE;
}
BOOL P9054_EEPROMReadWord(P9054_HANDLE hPlx, DWORD dwOffset, PWORD pwData)
{
UINT32 dwData;
DWORD dwAddr;
if (dwOffset % 2)
{
sprintf(P9054_ErrorString, "The offset is not even\n");
return FALSE;
}
dwAddr = dwOffset - (dwOffset % 4);
if (!P9054_EEPROMReadDWord(hPlx, dwAddr, &dwData))
return FALSE;
*pwData = (WORD) (dwData >> ((dwOffset % 4)*8));
return TRUE;
}
BOOL P9054_EEPROMWriteWord(P9054_HANDLE hPlx, DWORD dwOffset, WORD wData)
{
UINT32 dwData;
DWORD dwAddr;
dwAddr = dwOffset - (dwOffset % 4);
if (!P9054_EEPROMReadDWord(hPlx, dwAddr, &dwData))
return FALSE;
switch (dwOffset % 4)
{
case 0:
dwData = (dwData & 0xffff0000) | wData;
break;
case 2:
dwData = (dwData & 0x0000ffff) | (wData << 16);
break;
default:
sprintf(P9054_ErrorString, "The offset is not even\n");
return FALSE;
}
return P9054_EEPROMWriteDWord(hPlx, dwAddr, dwData);
}
void P9054_Sleep(P9054_HANDLE hPlx, DWORD dwMicroSeconds)
{
WD_SLEEP sleep;
BZERO (sleep);
sleep.dwOptions = SLEEP_NON_BUSY;
sleep.dwMicroSeconds = dwMicroSeconds;
WD_Sleep( hPlx->hWD, &sleep);
}
static BYTE P9054_EEPROMRemoveWriteProtection(P9054_HANDLE hPlx, WORD addr)
{
BYTE old_val;
old_val = P9054_ReadByte(hPlx, P9054_ADDR_REG, P9054_PROT_AREA);
addr /= 4;
addr &= 0x7f;
P9054_WriteByte(hPlx, P9054_ADDR_REG, P9054_PROT_AREA, (BYTE)addr);
return old_val * 4; //expand from dwords to bytes
}
static void P9054_EEPROMRestoreWriteProtection(P9054_HANDLE hPlx, WORD addr)
{
P9054_WriteByte(hPlx, P9054_ADDR_REG, P9054_PROT_AREA, (BYTE)addr);
}
static void P9054_EEPROMDataReadWrite(P9054_HANDLE hPlx, BOOL fIsRead, UINT32 *pdwData)
{
WD_PCI_CONFIG_DUMP pciCnf;
BZERO (pciCnf);
pciCnf.pciSlot = hPlx->pciSlot;
pciCnf.pBuffer = pdwData;
pciCnf.dwOffset = P9054_VPD_DATA;
pciCnf.dwBytes = 4;
pciCnf.fIsRead = fIsRead;
WD_PciConfigDump(hPlx->hWD,&pciCnf);
}
static void P9054_EEPROMAddrReadWrite(P9054_HANDLE hPlx, BOOL fIsRead, PWORD pwAddr)
{
WD_PCI_CONFIG_DUMP pciCnf;
BZERO (pciCnf);
pciCnf.pciSlot = hPlx->pciSlot;
pciCnf.pBuffer = pwAddr;
pciCnf.dwOffset = P9054_VPD_ADDR;
pciCnf.dwBytes = 2;
pciCnf.fIsRead = fIsRead;
WD_PciConfigDump(hPlx->hWD,&pciCnf);
}
BOOL P9054_EEPROMReadDWord(P9054_HANDLE hPlx, DWORD dwOffset, UINT32 *pdwData)
{
WORD wVal = 0;
WORD wAddr;
int i;
if (dwOffset % 4)
{
sprintf(P9054_ErrorString, "The offset is not a multiple of 4\n");
return FALSE;
}
// Write a destination serial EEPROM address and flag of operation, value of 0.
wAddr = (WORD)(dwOffset & ~BIT15);
P9054_EEPROMAddrReadWrite(hPlx, FALSE, &wAddr);
// Probe a flag of operation until it changes to a 1 to ensure the Read data is available.
for (i=0; i<10; i++)
{
P9054_Sleep(hPlx, P9054_EEPROM_DELAY);
P9054_EEPROMAddrReadWrite(hPlx, TRUE, &wVal);
if (wVal & BIT15)
break;
}
if (i==10)
{
sprintf(P9054_ErrorString, "Acknowledge to EEPROM read was not received\n");
return FALSE;
}
// Read back the requested data from PVPDATA register
P9054_EEPROMDataReadWrite(hPlx, TRUE, pdwData);
return TRUE;
}
BOOL P9054_EEPROMWriteDWord(P9054_HANDLE hPlx, DWORD dwOffset, UINT32 dwData)
{
UINT32 dwReadback;
WORD wAddr;
WORD wVal;
int i;
BOOL fRet;
BOOL fReadOk = FALSE;
BYTE bEnableOffset;
if (dwOffset % 4)
{
sprintf(P9054_ErrorString, "The offset is not a multiple of 4\n");
return FALSE;
}
wAddr = (WORD)dwOffset;
bEnableOffset = P9054_EEPROMRemoveWriteProtection(hPlx, wAddr);
P9054_Sleep(hPlx, P9054_EEPROM_DELAY);
// Write desired data to PVPDATA register
P9054_EEPROMDataReadWrite(hPlx, FALSE, &dwData);
// Write a destination serial EEPROM address and flag of operation, value of 1.
wAddr = (WORD)(wAddr | BIT15);
P9054_EEPROMAddrReadWrite(hPlx, FALSE, &wAddr);
// Probe a flag of operation until it changes to a 0 to ensure the write completes.
for (i=0; i<10; i++)
{
P9054_Sleep(hPlx, P9054_EEPROM_DELAY);
P9054_EEPROMAddrReadWrite(hPlx, TRUE, &wVal);
if ((wVal & BIT15) == 0)
break;
}
P9054_EEPROMRestoreWriteProtection(hPlx, bEnableOffset);
fReadOk = P9054_EEPROMReadDWord(hPlx, dwOffset, &dwReadback);
if (fReadOk && dwReadback==dwData)
fRet = TRUE;
else
{
fRet = FALSE;
if (fReadOk)
sprintf(P9054_ErrorString, "Write 0x%08x, Read 0x%08x\n",dwData, dwReadback);
else
sprintf(P9054_ErrorString, "Error reading EEPROM\n");
}
return fRet;
}
// definition of abort bits in commad register (PCI_CR) for PLX 9054
#define P9054_CR_ABORT_BITS (\
BIT24 /* Detected Master Data Parity Error */ \
| BIT27 /* Signaled Target Abort */ \
| BIT28 /* Received Target Abort */ \
| BIT29 /* Received Master Abort */ \
| BIT30 /* Signaled System Error */ \
| BIT31 /* Detected Parity Error on PCI bus */ \
)
// software reset for PLX 9054 compatible boards
void P9054_reset(P9054_HANDLE hPlx)
{
BOOL fMUEnabled;
BOOL fEepromPresent;
UINT32 temp;
UINT32 RegCtrl = 0;
UINT32 RegInterrupt = 0;
UINT32 RegMailbox0 = 0;
UINT32 RegMailbox1 = 0;
UINT32 RegHotSwap = 0;
UINT32 RegPowerMgmnt = 0;
// Clear any PCI errors
RegCtrl = P9054_ReadPCIReg(hPlx, PCI_CR);
if (RegCtrl & P9054_CR_ABORT_BITS)
{
// Write value back to clear aborts
P9054_WritePCIReg(hPlx, PCI_CR, RegCtrl);
}
// Save state of I2O Decode Enable
temp = P9054_ReadReg(hPlx, P9054_QSR);
fMUEnabled = temp & BIT0 ? TRUE : FALSE;
// Determine if an EEPROM is present
fEepromPresent = P9054_EEPROMPresent(hPlx);
// Make sure S/W Reset & EEPROM reload bits are clear
RegCtrl = P9054_ReadReg(hPlx, P9054_CNTRL);
RegCtrl &= ~(BIT30 | BIT29);
// Save some registers if EEPROM present
if (fEepromPresent)
{
// run-time registers
RegMailbox0 = P9054_ReadReg(hPlx, P9054_MBOX0);
RegMailbox1 = P9054_ReadReg(hPlx, P9054_MBOX1);
// PCI configuration registers
RegInterrupt = P9054_ReadPCIReg(hPlx, PCI_ILR);
RegHotSwap = P9054_ReadPCIReg(hPlx, P9054_HS_CNTL);
RegPowerMgmnt = P9054_ReadPCIReg(hPlx, P9054_PMCSR);
}
// Issue Software Reset to hold PLX chip in reset
P9054_WriteReg(hPlx, P9054_CNTRL, RegCtrl | BIT30);
// Bring chip out of reset
P9054_Sleep(hPlx, P9054_SOFT_RESET_DELAY);
P9054_WriteReg(hPlx, P9054_CNTRL, RegCtrl);
// Issue EEPROM reload in case now programmed
P9054_WriteReg(hPlx, P9054_CNTRL, RegCtrl | BIT29);
// Clear EEPROM reload
P9054_Sleep(hPlx, P9054_SOFT_RESET_DELAY);
P9054_WriteReg(hPlx, P9054_CNTRL, RegCtrl);
// Restore I2O Decode Enable state
if (fMUEnabled)
{
temp = P9054_ReadReg(hPlx, P9054_QSR);
P9054_WriteReg(hPlx, P9054_QSR, temp | BIT0);
}
// If EEPROM was present, restore registers
if (fEepromPresent)
{
// run-time registers
P9054_WriteReg(hPlx, P9054_MBOX0, RegMailbox0);
P9054_WriteReg(hPlx, P9054_MBOX1, RegMailbox1);
// PCI configuration registers
P9054_WritePCIReg(hPlx, PCI_ILR, RegInterrupt);
// Mask out HS bits that can be cleared
RegHotSwap &= ~(BIT23 | BIT22 | BIT17);
P9054_WritePCIReg(hPlx, P9054_HS_CNTL, RegHotSwap);
// Mask out PM bits that can be cleared
RegPowerMgmnt &= ~BIT15;
P9054_WritePCIReg(hPlx, P9054_PMCSR, RegPowerMgmnt);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -