Hello,
I have a problem with my driver. My problem only occurs when running on a multi-core processor. I have two process accessing my driver at the same time. When one process triggers an interrupt, the ISR routine modifies the PCI I/O adress 0x8, used to decide witch module to reroute to.
I implemented a spin lock in the IOControl function to prevent calling of two I/O at same time. This seems to prevent the double I/O access.
I implemented another spin lock in the ISR and in the Read/Write functions I use to prevent this adress to being changed but I end up having a deadlock and system crashing after a while.
My main problem here is that I want to prevent the ISR running on one processor when a Read or Write is being done on another processor. Basicly a system to say: *Stop all instructions on the processors and wait till I finish with the ISR before doing anything else*
Any suggestion?
bool OnIsr(PKINTERRUPT Interrupt, PVOID ServContext)
{
ISR_DATA * ptr = (ISR_DATA *)ServContext;
PUCHAR RealOffset = (PUCHAR) (ptr->pBaseAddress);
UCHAR ucSource = 0;
bool ReturnValue;
KIRQL Irql;
KeAcquireSpinLock(ptr->pLock,&Irql);
if( RealInterrupt)
{
// Do READ_PORT here… and WRITE_PORT here…
KeInsertQueueDpc((PRKDPC)ptr->pDBC,ptr,NULL);
ReturnValue = true;
}
else
{
ReturnValue = false;
}
KeReleaseSpinLock(ptr->pLock,Irql);
return ReturnValue;
}
Here is an example of my function that is called WriteByte:
void CIoRange::AcquireIsrSafe()
{
// Raise IRQ to Interrupt IRQL so I don’t have deadlock when ISR pops
KeRaiseIrql(m_IntIrql,&m_OldIrql);
KeAcquireSpinLock(&m_InISRLock,&m_OldIrql);
}
void CIoRange::ReleaseIsrSafe()
{
// Let Lock go
KeReleaseSpinLock(&m_InISRLock,m_OldIrql);
// Lower IRQL
KeLowerIrql(m_OldIrql);
}
void CIoRange::WriteByte(ULONG Offset, UCHAR Value)
{
if(Offset < m_Size && m_BaseAddress != NULL)
{
// Prevent ISR to change something on PCI card when I will do my Write.
AcquireIsrSafe();
PUCHAR RealOffset;
if(m_Type == MEMORY)
{
RealOffset = (PUCHAR) ((PUCHAR) (m_BaseAddress) + Offset);
WRITE_REGISTER_UCHAR(RealOffset,Value);
ERR0((“Write Byte @ 0x%X => 0x%X (0x%X)”,RealOffset,Value,*RealOffset));
}
else
{
RealOffset = (PUCHAR) ((PUCHAR) (m_PhysicalBaseAddress.LowPart) + Offset);
WRITE_PORT_UCHAR(RealOffset,Value);
ERR0((“Write Byte @ 0x%X => 0x%X (0x%X)”,RealOffset,Value,READ_PORT_UCHAR(RealOffset)));
}
// Critiical Section Over…
ReleaseIsrSafe();
}
}
=====================
In case you are wondering what my Connect Interrupt looks like:
KeInitializeDpc( m_pDPC,(PKDEFERRED_ROUTINE)OnDpc, this);
IsrData = new(NonPagedPool)ISR_DATA;
IsrData->pBaseAddress = (PUCHAR)m_Io.GetPhysicalBaseAddress().LowPart;
IsrData->pDBC= m_pDPC;
IsrData->pLock = m_Io.GetLock(); // Returns IoRange::m_InISRLock address
status = IoConnectInterrupt(&m_pInterrupt,
(PKSERVICE_ROUTINE)OnIsr,
(PVOID)IsrData,
NULL,
pPartialDescriptor->u.Interrupt.Vector,
(KIRQL)pPartialDescriptor->u.Interrupt.Level,
(KIRQL)pPartialDescriptor->u.Interrupt.Level,
(pPartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive,
(pPartialDescriptor->ShareDisposition == CmResourceShareShared),
pPartialDescriptor->u.Interrupt.Affinity,
FALSE);
Express yourself with free Messenger emoticons. Get them today!
http://www.freemessengeremoticons.ca/?icid=EMENCA122