📄 plxinterrupt.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:
*
* PlxInterrupt.c
*
* Description:
*
* This file handles interrupts for the PLX device
*
* Notes:
*
* This driver handles interrupt sharing with other PCI device drivers.
* The PLX chip is checked to see if it is the true source of an interrupt.
* If an interrupt is truly active, the interrupt source is cleared and
* any waiting user-mode applications are notified.
*
* Revision History:
*
* 02-01-06 : PCI SDK v4.40
*
******************************************************************************/
#include "DriverDefs.h"
#include "PlxInterrupt.h"
#include "PciSupport.h"
#include "SupportFunc.h"
/******************************************************************************
*
* Function : OnInterrupt
*
* Description: The Interrupt Service Routine for the PLX device
*
******************************************************************************/
BOOLEAN
OnInterrupt(
PKINTERRUPT pInterrupt,
PVOID ServiceContext
)
{
U32 RegValue;
U32 RegPciInt;
U32 InterruptSource;
DEVICE_EXTENSION *pdx;
// Get the device extension
pdx = (DEVICE_EXTENSION *)ServiceContext;
// Read interrupt status register
RegPciInt =
PLX_REG_READ(
pdx,
PCI9054_INT_CTRL_STAT
);
/****************************************************
* If the chip is in a low power state, then local
* register reads are disabled and will always return
* 0xFFFFFFFF. If the PLX chip's interrupt is shared
* with another PCI device, the PXL ISR may continue
* to be called. This case is handled to avoid
* erroneous reporting of an active interrupt.
***************************************************/
if (RegPciInt == 0xFFFFFFFF)
return FALSE;
// Check for master PCI interrupt enable
if ((RegPciInt & (1 << 8)) == 0)
return FALSE;
// Verify that an interrupt is truly active
// Clear the interrupt type flag
InterruptSource = INTR_TYPE_NONE;
// Check if PCI Doorbell Interrupt is active and not masked
if ((RegPciInt & (1 << 13)) && (RegPciInt & (1 << 9)))
{
InterruptSource |= INTR_TYPE_DOORBELL;
}
// Check if PCI Abort Interrupt is active and not masked
if ((RegPciInt & (1 << 14)) && (RegPciInt & (1 << 10)))
{
InterruptSource |= INTR_TYPE_PCI_ABORT;
}
// Check if Local->PCI Interrupt is active and not masked
if ((RegPciInt & (1 << 15)) && (RegPciInt & (1 << 11)))
{
InterruptSource |= INTR_TYPE_LOCAL_1;
}
// Check if DMA Channel 0 Interrupt is active and not masked
if ((RegPciInt & (1 << 21)) && (RegPciInt & (1 << 18)))
{
// Verify the DMA interrupt is routed to PCI
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA0_MODE
);
if (RegValue & (1 << 17))
{
InterruptSource |= INTR_TYPE_DMA_0;
}
}
// Check if DMA Channel 1 Interrupt is active and not masked
if ((RegPciInt & (1 << 22)) && (RegPciInt & (1 << 19)))
{
// Verify the DMA interrupt is routed to PCI
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA1_MODE
);
if (RegValue & (1 << 17))
{
InterruptSource |= INTR_TYPE_DMA_1;
}
}
// Check if MU Outbound Post interrupt is active
RegValue =
PLX_REG_READ(
pdx,
PCI9054_OUTPOST_INT_STAT
);
if (RegValue & (1 << 3))
{
// Check if MU Outbound Post interrupt is not masked
RegValue =
PLX_REG_READ(
pdx,
PCI9054_OUTPOST_INT_MASK
);
if ((RegValue & (1 << 3)) == 0)
{
InterruptSource |= INTR_TYPE_OUTBOUND_POST;
}
}
// Return if no interrupts are active
if (InterruptSource == INTR_TYPE_NONE)
return FALSE;
// At this point, the device interrupt is verified
// Mask the PCI Interrupt
PLX_REG_WRITE(
pdx,
PCI9054_INT_CTRL_STAT,
RegPciInt & ~(1 << 8)
);
//
// Schedule deferred procedure (DPC) to complete interrupt processing
//
KeInsertQueueDpc(
&(pdx->DpcForIsr),
(VOID *)(PLX_UINT_PTR)InterruptSource,
NULL
);
return TRUE;
}
/******************************************************************************
*
* Function : DpcForIsr
*
* Description: This routine will be triggered by the ISR to service an interrupt.
*
******************************************************************************/
VOID
DpcForIsr(
PKDPC pDpc,
PVOID pContext,
PVOID pArg1,
PVOID pArg2
)
{
U32 RegValue;
U32 IntSource;
PLX_REG_DATA RegData;
DEVICE_EXTENSION *pdx;
// Get the device extension
pdx = (DEVICE_EXTENSION *)pContext;
// Get interrupt source
IntSource = PtrToUlong(pArg1);
KeAcquireSpinLockAtDpcLevel(
&(pdx->Lock_HwAccess)
);
// Local Interrupt 1
if (IntSource & INTR_TYPE_LOCAL_1)
{
// Synchronize access to Interrupt Control/Status Register
RegData.pdx = pdx;
RegData.offset = PCI9054_INT_CTRL_STAT;
RegData.BitsToSet = 0;
RegData.BitsToClear = (1 << 11);
// Mask local interrupt 1 since true source is unknown
KeSynchronizeExecution(
pdx->pInterruptObject,
PlxSynchronizedRegisterModify,
(VOID *)&RegData
);
}
// Doorbell Interrupt
if (IntSource & INTR_TYPE_DOORBELL)
{
// Get Doorbell register
RegValue =
PLX_REG_READ(
pdx,
PCI9054_PCI_DOORBELL
);
// Clear Doorbell interrupt
PLX_REG_WRITE(
pdx,
PCI9054_PCI_DOORBELL,
RegValue
);
// Save this value in case it is requested later
pdx->IntrDoorbellValue = RegValue;
}
// PCI Abort interrupt
if (IntSource & INTR_TYPE_PCI_ABORT)
{
// Get the PCI Command register
PLX_PCI_REG_READ(
pdx,
CFG_COMMAND,
&RegValue
);
// Write to back to clear PCI Abort
PLX_PCI_REG_WRITE(
pdx,
CFG_COMMAND,
RegValue
);
}
// DMA Channel 0 interrupt
if (IntSource & INTR_TYPE_DMA_0)
{
// Get DMA Control/Status
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
// Clear DMA interrupt
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | (1 << 3)
);
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA0_MODE
);
// Check if SGL is enabled & cleanup
if (RegValue & (1 << 9))
{
PlxSglDmaTransferComplete(
pdx,
0
);
}
}
// DMA Channel 1 interrupt
if (IntSource & INTR_TYPE_DMA_1)
{
// Get DMA Control/Status
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
// Clear DMA interrupt
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | (1 << 11)
);
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA1_MODE
);
// Check if SGL is enabled & cleanup
if (RegValue & (1 << 9))
{
PlxSglDmaTransferComplete(
pdx,
1
);
}
}
// Outbound post FIFO interrupt
if (IntSource & INTR_TYPE_OUTBOUND_POST)
{
// Mask Outbound Post interrupt
PLX_REG_WRITE(
pdx,
PCI9054_OUTPOST_INT_MASK,
(1 << 3)
);
}
// Save the interrupt sources
pdx->InterruptSource = IntSource;
KeReleaseSpinLockFromDpcLevel(
&(pdx->Lock_HwAccess)
);
// Signal any objects waiting for notification
PlxSignalNotifications(
pdx,
IntSource
);
// Re-enable the PCI interrupt
KeSynchronizeExecution(
pdx->pInterruptObject,
PlxChipPciInterruptEnable,
pdx
);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -