Files
yttrium-virtio-gpu/NetKVM/Common/ParaNdis-AbstractPath.h
T
Yuri Benditovich 5f5540a3cd netkvm: fix BSOD if some queue fails to renew
https://issues.redhat.com/browse/RHEL-68725
https://github.com/virtio-win/kvm-guest-drivers-windows/issues/1197
In such case we do not have any other option than request to
unload the driver. This can happen in 2 flows: power up (during
fast startup) or reset, both with driver verifier that simulates
low resources.
In reset flow we need to request driver unload explicitly.
Power up flow works in SET_POWER, so it will do it automatically.

Signed-off-by: Yuri Benditovich <[email protected]>
2024-12-11 11:57:39 +01:00

157 lines
3.5 KiB
C++

#pragma once
#include "ParaNdis-VirtQueue.h"
#include "Parandis_DesignPatterns.h"
class CParaNdisAbstractPath
{
public:
#if NDIS_SUPPORT_NDIS620
CParaNdisAbstractPath()
{
memset(&DPCAffinity, 0, sizeof(DPCAffinity));
}
#else
CParaNdisAbstractPath() : DPCTargetProcessor(0) {}
#endif
bool WasInterruptReported()
{
return m_interruptReported;
}
void ClearInterruptReport()
{
m_interruptReported = false;
}
void ReportInterrupt() {
m_interruptReported = true;
}
UINT getMessageIndex() {
return m_messageIndex;
}
UINT getQueueIndex() {
return m_queueIndex;
}
virtual NDIS_STATUS SetupMessageIndex(u16 vector);
/* TODO - Path classes should inherit from CVirtQueue*/
virtual void DisableInterrupts()
{
m_pVirtQueue->DisableInterrupts();
}
void EnableInterrupts()
{
m_pVirtQueue->EnableInterrupts();
}
bool Renew()
{
m_pVirtQueue->Renew();
return m_pVirtQueue->IsValid();
}
ULONG getCPUIndex();
VOID SetLastInterruptTimestamp(LARGE_INTEGER timestamp)
{
m_LastInterruptTimeStamp = timestamp;
}
#if NDIS_SUPPORT_NDIS620
GROUP_AFFINITY DPCAffinity;
#else
KAFFINITY DPCTargetProcessor = 0;
#endif
virtual bool FireDPC(ULONG messageId) = 0;
protected:
PPARANDIS_ADAPTER m_Context;
CVirtQueue *m_pVirtQueue;
LARGE_INTEGER m_LastInterruptTimeStamp;
u16 m_messageIndex = (u16)-1;
u16 m_queueIndex = (u16)-1;
bool m_interruptReported;
};
template <class VQ> class CParaNdisTemplatePath : public CParaNdisAbstractPath, public CObserver<SMNotifications>{
public:
CParaNdisTemplatePath() : m_ObserverAdded(false) {
m_pVirtQueue = &m_VirtQueue;
}
bool CreatePath()
{
m_ObserverAdded = m_Context->m_StateMachine.Add(this) > 0;
return true;
}
~CParaNdisTemplatePath() {
if (m_ObserverAdded)
{
m_Context->m_StateMachine.Remove(this);
}
}
void Shutdown()
{
TPassiveSpinLocker LockedContext(m_Lock);
m_VirtQueue.Shutdown();
}
static BOOLEAN _Function_class_(MINIPORT_SYNCHRONIZE_INTERRUPT)
RestartQueueSynchronously(PVOID ctx)
{
auto This = static_cast<CParaNdisTemplatePath<VQ>*>(ctx);
return !This->m_VirtQueue.Restart();
}
/* We get notified by the state machine on suprise removal or when the
device needs a reset*/
void Notify(SMNotifications message) override
{
if (message == SMNotifications::SupriseRemoved || message == SMNotifications::NeedsReset)
{
m_VirtQueue.DoNotTouchHardware();
}
else if (message == SMNotifications::PoweredOn)
{
m_VirtQueue.AllowTouchHardware();
}
}
// this default implementation is for RX/TX queues
// CX queue shall redefine it
bool FireDPC(ULONG messageId) override
{
#if PARANDIS_SUPPORT_POLL
if (m_Context->bPollModeEnabled)
{
//rx index is 2*n, tx index is 2*n+1
ParaNdisPollNotify(m_Context, m_queueIndex / 2, (m_queueIndex % 2) ? "TX" : "RX");
return TRUE;
}
#endif
#if NDIS_SUPPORT_NDIS620
if (DPCAffinity.Mask)
{
NdisMQueueDpcEx(m_Context->InterruptHandle, messageId, &DPCAffinity, NULL);
return TRUE;
}
#endif
return FALSE;
}
protected:
CNdisSpinLock m_Lock;
bool m_ObserverAdded;
VQ m_VirtQueue;
};