Files
yttrium-virtio-gpu/NetKVM/Common/ParaNdis-AbstractPath.h
T
Yuri Benditovich 8a7005b1cf netkvm: Fix functionality with single MSIX vector
https://bugzilla.redhat.com/show_bug.cgi?id=1666940
Set clear and simple rule for assignment of vectors to queues
and translation of MSIX messages to queues:
in case of one or two vectors they are assigned
to TX/RX queues and CX reuses the last vector. In this case
we do not spawn DPC for CX and process it during regular
RX/TX processing. For case of 3 and more vectors the processing
is the same as before.

Signed-off-by: Yuri Benditovich <[email protected]>
2019-01-30 12:47:35 +02:00

147 lines
3.1 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();
}
void Renew()
{
m_pVirtQueue->Renew();
}
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 == SupriseRemoved || message == NeedsReset)
{
m_VirtQueue.DoNotTouchHardware();
}
else if (PoweredOn)
{
m_VirtQueue.AllowTouchHardware();
}
}
// this default implementation is for RX/TX queues
// CX queue shall redefine it
bool FireDPC(ULONG messageId) override
{
#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;
};