temp
This commit is contained in:
1 parent
d36f19509c
commit
30d20457f0
309 files changed
+121746
-1963
No files matched your search
+297
-65
@@ -26,6 +26,7 @@ static uint32_t gPciDeviceCount;
|
||||
#define PCI_MMIO_VA_LIMIT 0xFFFF980000000000ULL
|
||||
|
||||
static uintptr_t gPciMmioNext = PCI_MMIO_VA_BASE;
|
||||
static SPINLOCK gPciMmioLock = SPINLOCK_INIT;
|
||||
|
||||
// Implements the align Up64 operation.
|
||||
static uint64_t PciAlignUp64(uint64_t value, uint64_t alignment) {
|
||||
@@ -43,13 +44,15 @@ static KSTATUS PciAllocateMmioVa(uint64_t length, uintptr_t* outVa) {
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
uint64_t alignedLength = PciAlignUp64(length, NTL_DDK_PAGE_SIZE);
|
||||
uintptr_t cookie = KeAcquireSpinlock(&gPciMmioLock);
|
||||
uintptr_t va = (uintptr_t)PciAlignUp64((uint64_t)gPciMmioNext, NTL_DDK_PAGE_SIZE);
|
||||
if (va < PCI_MMIO_VA_BASE || va >= PCI_MMIO_VA_LIMIT)
|
||||
if (va < PCI_MMIO_VA_BASE || va >= PCI_MMIO_VA_LIMIT ||
|
||||
alignedLength > (uint64_t)(PCI_MMIO_VA_LIMIT - va)) {
|
||||
KeReleaseSpinlock(&gPciMmioLock, cookie);
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
if (alignedLength > (uint64_t)(PCI_MMIO_VA_LIMIT - va))
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
|
||||
}
|
||||
gPciMmioNext = va + (uintptr_t)alignedLength;
|
||||
KeReleaseSpinlock(&gPciMmioLock, cookie);
|
||||
*outVa = va;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
@@ -601,77 +604,306 @@ static uint8_t PciFindCapability(PCI_PDO_EXTENSION* ext, uint8_t capId) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Enables msi.
|
||||
__declspec(dllexport) KSTATUS PciEnableMsi(DEVICE_OBJECT* pdo, uint8_t irqSlot) {
|
||||
// PCI owns message programming, while the kernel owns CPU/vector placement.
|
||||
typedef struct PCI_MESSAGE_CONTEXT {
|
||||
DEVICE_OBJECT* Pdo;
|
||||
uint32_t TableOffset;
|
||||
uint16_t Capability;
|
||||
uint8_t Msix;
|
||||
uint8_t Reserved;
|
||||
} PCI_MESSAGE_CONTEXT;
|
||||
|
||||
static KSTATUS PciUpdateMessageRoute(void* opaque,
|
||||
KE_INTERRUPT_MESSAGE_OPERATION operation, const NTL_DDK_MSI_MESSAGE* message) {
|
||||
PCI_MESSAGE_CONTEXT* ctx = (PCI_MESSAGE_CONTEXT*)opaque;
|
||||
PCI_PDO_EXTENSION* ext;
|
||||
if (!PciIsPdo(pdo, &ext))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (irqSlot >= 24u)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
uint8_t cap = PciFindCapability(ext, PCI_CAP_ID_MSI);
|
||||
if (!cap)
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
|
||||
uint8_t bus = ext->Info.Address.Bus;
|
||||
uint8_t dev = ext->Info.Address.Device;
|
||||
if (!ctx || !PciIsPdo(ctx->Pdo, &ext)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
|
||||
uint8_t fn = ext->Info.Address.Function;
|
||||
|
||||
uint16_t control = PciRawRead16(bus, dev, fn, (uint16_t)(cap + 2u));
|
||||
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
|
||||
bool pvm = (control & PCI_MSI_CTRL_PVM) != 0;
|
||||
NTL_DDK_MSI_MESSAGE message;
|
||||
KSTATUS messageStatus = KeIrqComposeMsiMessage(irqSlot, &message);
|
||||
if (!KSUCCESS(messageStatus))
|
||||
return messageStatus;
|
||||
|
||||
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 4u), (uint32_t)message.Address);
|
||||
if (is64) {
|
||||
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 8u), (uint32_t)(message.Address >> 32));
|
||||
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 12u), (uint16_t)message.Data);
|
||||
if (pvm)
|
||||
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 16u), 0);
|
||||
} else {
|
||||
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 8u), (uint16_t)message.Data);
|
||||
if (pvm)
|
||||
PciRawWrite32(bus, dev, fn, (uint16_t)(cap + 12u), 0);
|
||||
if (ctx->Msix) {
|
||||
if (!ext->MsixTable || ctx->TableOffset > ext->MsixMappedLength ||
|
||||
ext->MsixMappedLength - ctx->TableOffset < 16u)
|
||||
return NTLSTATUS_DEVICE_ERROR;
|
||||
volatile uint32_t* entry = (volatile uint32_t*)(ext->MsixTable + ctx->TableOffset);
|
||||
if (operation == KeInterruptMessageQuiesce) {
|
||||
entry[3] = 1u;
|
||||
} else if (operation == KeInterruptMessageProgram && message) {
|
||||
entry[0] = (uint32_t)message->Address;
|
||||
entry[1] = (uint32_t)(message->Address >> 32);
|
||||
entry[2] = message->Data;
|
||||
} else if (operation == KeInterruptMessageResume) {
|
||||
entry[3] = 0u;
|
||||
} else return NTLSTATUS_INVALID_PARAMETER;
|
||||
(void)entry[3];
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
control &= (uint16_t)~PCI_MSI_CTRL_MME_MASK;
|
||||
control |= PCI_MSI_CTRL_ENABLE;
|
||||
PciRawWrite16(bus, dev, fn, (uint16_t)(cap + 2u), control);
|
||||
|
||||
uint16_t cmd = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
|
||||
cmd |= PCI_COMMAND_INTX_DISABLE;
|
||||
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, cmd);
|
||||
|
||||
DbgPrint("pci: MSI enabled %02x:%02x.%u cap=0x%02x vector=0x%02x irqslot=%u %s\n",
|
||||
bus, dev, fn, cap, (unsigned)(message.Data & 0xFFu), irqSlot, is64 ? "64-bit" : "32-bit");
|
||||
uint16_t control = PciRawRead16(bus, dev, fn, ctx->Capability + 2u);
|
||||
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
|
||||
// MSI per-vector masking preserves pending messages during retargeting.
|
||||
// Devices without PVM retain their initial affinity until disconnect.
|
||||
if (!(control & PCI_MSI_CTRL_PVM)) return NTLSTATUS_NOT_SUPPORTED;
|
||||
uint16_t maskOffset = ctx->Capability + (is64 ? 16u : 12u);
|
||||
if (operation == KeInterruptMessageQuiesce) {
|
||||
uint32_t mask = PciRawRead32(bus, dev, fn, maskOffset);
|
||||
PciRawWrite32(bus, dev, fn, maskOffset, mask | 1u);
|
||||
(void)PciRawRead32(bus, dev, fn, maskOffset);
|
||||
} else if (operation == KeInterruptMessageProgram && message) {
|
||||
PciRawWrite32(bus, dev, fn, ctx->Capability + 4u, (uint32_t)message->Address);
|
||||
if (is64) {
|
||||
PciRawWrite32(bus, dev, fn, ctx->Capability + 8u,
|
||||
(uint32_t)(message->Address >> 32));
|
||||
PciRawWrite16(bus, dev, fn, ctx->Capability + 12u, (uint16_t)message->Data);
|
||||
} else PciRawWrite16(bus, dev, fn, ctx->Capability + 8u, (uint16_t)message->Data);
|
||||
} else if (operation == KeInterruptMessageResume) {
|
||||
uint32_t mask = PciRawRead32(bus, dev, fn, maskOffset);
|
||||
PciRawWrite32(bus, dev, fn, maskOffset, mask & ~1u);
|
||||
(void)PciRawRead32(bus, dev, fn, maskOffset);
|
||||
} else return NTLSTATUS_INVALID_PARAMETER;
|
||||
(void)PciRawRead16(bus, dev, fn, ctx->Capability + 2u);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Enables a single MSI vector, allocating the nt-lite IRQ slot internally.
|
||||
__declspec(dllexport) KSTATUS PciEnableMsiAuto(DEVICE_OBJECT* pdo, uint8_t* outIrqSlot) {
|
||||
PCI_PDO_EXTENSION* ext;
|
||||
if (!outIrqSlot || !PciIsPdo(pdo, &ext))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
if (!PciFindCapability(ext, PCI_CAP_ID_MSI))
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
|
||||
uint8_t irq = 0xFFu;
|
||||
KSTATUS st = KeIrqAllocateMsiVector(&irq);
|
||||
if (!KSUCCESS(st))
|
||||
static KSTATUS PciBindMessage(DEVICE_OBJECT* pdo, PCI_INTERRUPT_REQUEST* request,
|
||||
uint8_t msix, uint16_t capability, uint32_t tableOffset) {
|
||||
PCI_MESSAGE_CONTEXT* ctx = (PCI_MESSAGE_CONTEXT*)MmAllocatePool(sizeof(*ctx));
|
||||
if (!ctx) return NTLSTATUS_NO_MEMORY;
|
||||
ctx->Pdo = pdo;
|
||||
ctx->Msix = msix;
|
||||
ctx->Capability = capability;
|
||||
ctx->TableOffset = tableOffset;
|
||||
ctx->Reserved = 0;
|
||||
KSTATUS st = KeInterruptBindMessageSource(request->Interrupt, PciUpdateMessageRoute, ctx);
|
||||
if (!KSUCCESS(st)) {
|
||||
MmFreePool(ctx);
|
||||
return st;
|
||||
|
||||
st = PciEnableMsi(pdo, irq);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
*outIrqSlot = irq;
|
||||
}
|
||||
request->BusContext = ctx;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Programs a pre-allocated interrupt group. All routes exist before device delivery begins.
|
||||
static KSTATUS PciConnectMsix(DEVICE_OBJECT* pdo, PCI_PDO_EXTENSION* ext,
|
||||
PCI_INTERRUPT_REQUEST* requests, uint32_t count) {
|
||||
uint8_t cap = PciFindCapability(ext, PCI_CAP_ID_MSIX);
|
||||
if (!cap) return NTLSTATUS_NOT_SUPPORTED;
|
||||
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
|
||||
uint8_t fn = ext->Info.Address.Function;
|
||||
uint16_t control = PciRawRead16(bus, dev, fn, cap + 2u);
|
||||
uint32_t size = (control & 0x7FFu) + 1u;
|
||||
if (count > size) return NTLSTATUS_NOT_SUPPORTED;
|
||||
uint32_t table = PciRawRead32(bus, dev, fn, cap + 4u);
|
||||
uint32_t bir = table & 7u, offset = table & ~7u;
|
||||
if (bir >= PCI_MAX_BARS) return NTLSTATUS_DEVICE_ERROR;
|
||||
PCI_BAR bar;
|
||||
KSTATUS st = PciGetBar(pdo, (uint8_t)bir, &bar);
|
||||
if (!KSUCCESS(st) || (bar.Type != PciBarMemory32 && bar.Type != PciBarMemory64) ||
|
||||
bar.Length < offset || count > (bar.Length - offset) / 16u)
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
uint16_t command = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
|
||||
if (!(command & PCI_COMMAND_MEMORY_SPACE)) {
|
||||
DbgPrint("pci: MSI-X requires enabled memory decoding at %02x:%02x.%u\n",
|
||||
bus, dev, fn);
|
||||
return NTLSTATUS_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (!ext->MsixTable) {
|
||||
volatile uint8_t* mapped = (volatile uint8_t*)0;
|
||||
uint64_t mappedLength = 0;
|
||||
st = PciMapBar(pdo, (uint8_t)bir,
|
||||
NTL_DDK_PAGE_PRESENT | NTL_DDK_PAGE_WRITE | NTL_DDK_PAGE_CACHE_UC | NTL_DDK_PAGE_NX,
|
||||
(void**)&mapped, &mappedLength);
|
||||
if (!KSUCCESS(st)) return st;
|
||||
ext->MsixTable = mapped;
|
||||
ext->MsixMappedLength = mappedLength;
|
||||
ext->MsixBarIndex = (uint8_t)bir;
|
||||
}
|
||||
// A persistent per-PDO mapping prevents repeated BAR allocations on reconnect.
|
||||
if (ext->MsixBarIndex != bir || ext->MsixMappedLength < offset ||
|
||||
count > (ext->MsixMappedLength - offset) / 16u)
|
||||
return NTLSTATUS_DEVICE_ERROR;
|
||||
volatile uint8_t* mapped = ext->MsixTable;
|
||||
|
||||
// Mask the function and turn off stale firmware MSI before programming MSI-X.
|
||||
PciRawWrite16(bus, dev, fn, cap + 2u, (control | 0x4000u) & ~0x8000u);
|
||||
uint8_t msiCap = PciFindCapability(ext, PCI_CAP_ID_MSI);
|
||||
if (msiCap) {
|
||||
uint16_t msiControl = PciRawRead16(bus, dev, fn, msiCap + 2u);
|
||||
PciRawWrite16(bus, dev, fn, msiCap + 2u,
|
||||
msiControl & (uint16_t)~PCI_MSI_CTRL_ENABLE);
|
||||
}
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
st = KeInterruptReserveMessage(requests[i].Affinity, requests[i].Routine,
|
||||
requests[i].Context, &requests[i].Interrupt);
|
||||
if (!KSUCCESS(st)) goto failed;
|
||||
NTL_DDK_MSI_MESSAGE msg;
|
||||
st = KeInterruptComposeMessage(requests[i].Interrupt, &msg);
|
||||
if (!KSUCCESS(st)) goto failed;
|
||||
st = PciBindMessage(pdo, &requests[i], 1u, cap, offset + 16u * i);
|
||||
if (!KSUCCESS(st)) goto failed;
|
||||
volatile uint32_t* entry = (volatile uint32_t*)(mapped + offset + 16u * i);
|
||||
entry[3] = 1u;
|
||||
entry[0] = (uint32_t)msg.Address;
|
||||
entry[1] = (uint32_t)(msg.Address >> 32);
|
||||
entry[2] = msg.Data;
|
||||
entry[3] = 0u;
|
||||
// Read back the entry to drain posted MMIO writes before enabling MSI-X.
|
||||
(void)entry[3];
|
||||
}
|
||||
PciRawWrite16(bus, dev, fn, cap + 2u, (control | 0x8000u) & ~0x4000u);
|
||||
(void)PciRawRead16(bus, dev, fn, cap + 2u);
|
||||
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, command | PCI_COMMAND_INTX_DISABLE);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
st = KeInterruptActivateMessage(requests[i].Interrupt);
|
||||
if (!KSUCCESS(st)) goto failed;
|
||||
}
|
||||
return NTLSTATUS_SUCCESS;
|
||||
failed:
|
||||
PciRawWrite16(bus, dev, fn, cap + 2u, control & ~0x8000u);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (requests[i].Interrupt) {
|
||||
KeInterruptDisconnect(requests[i].Interrupt);
|
||||
requests[i].Interrupt = (KE_INTERRUPT*)0;
|
||||
}
|
||||
if (requests[i].BusContext) {
|
||||
MmFreePool(requests[i].BusContext);
|
||||
requests[i].BusContext = 0;
|
||||
}
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
static KSTATUS PciConnectMsi(DEVICE_OBJECT* pdo, PCI_PDO_EXTENSION* ext,
|
||||
PCI_INTERRUPT_REQUEST* request) {
|
||||
uint8_t cap = PciFindCapability(ext, PCI_CAP_ID_MSI);
|
||||
if (!cap) return NTLSTATUS_NOT_SUPPORTED;
|
||||
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
|
||||
uint8_t fn = ext->Info.Address.Function;
|
||||
KSTATUS st = KeInterruptReserveMessage(request->Affinity, request->Routine,
|
||||
request->Context, &request->Interrupt);
|
||||
if (!KSUCCESS(st)) return st;
|
||||
NTL_DDK_MSI_MESSAGE msg;
|
||||
st = KeInterruptComposeMessage(request->Interrupt, &msg);
|
||||
if (!KSUCCESS(st)) goto failed;
|
||||
st = PciBindMessage(pdo, request, 0u, cap, 0);
|
||||
if (!KSUCCESS(st)) goto failed;
|
||||
uint8_t msixCap = PciFindCapability(ext, PCI_CAP_ID_MSIX);
|
||||
if (msixCap) {
|
||||
uint16_t msixControl = PciRawRead16(bus, dev, fn, msixCap + 2u);
|
||||
PciRawWrite16(bus, dev, fn, msixCap + 2u,
|
||||
(msixControl | 0x4000u) & (uint16_t)~0x8000u);
|
||||
}
|
||||
uint16_t control = PciRawRead16(bus, dev, fn, cap + 2u);
|
||||
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
|
||||
bool pvm = (control & PCI_MSI_CTRL_PVM) != 0;
|
||||
PciRawWrite32(bus, dev, fn, cap + 4u, (uint32_t)msg.Address);
|
||||
if (is64) {
|
||||
PciRawWrite32(bus, dev, fn, cap + 8u, (uint32_t)(msg.Address >> 32));
|
||||
PciRawWrite16(bus, dev, fn, cap + 12u, (uint16_t)msg.Data);
|
||||
if (pvm) PciRawWrite32(bus, dev, fn, cap + 16u, 0);
|
||||
} else {
|
||||
PciRawWrite16(bus, dev, fn, cap + 8u, (uint16_t)msg.Data);
|
||||
if (pvm) PciRawWrite32(bus, dev, fn, cap + 12u, 0);
|
||||
}
|
||||
control = (control & ~(uint16_t)PCI_MSI_CTRL_MME_MASK) | PCI_MSI_CTRL_ENABLE;
|
||||
PciRawWrite16(bus, dev, fn, cap + 2u, control);
|
||||
uint16_t command = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
|
||||
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, command | PCI_COMMAND_INTX_DISABLE);
|
||||
st = KeInterruptActivateMessage(request->Interrupt);
|
||||
if (!KSUCCESS(st)) goto failed;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
failed:
|
||||
{
|
||||
uint16_t previous = PciRawRead16(bus, dev, fn, cap + 2u);
|
||||
PciRawWrite16(bus, dev, fn, cap + 2u,
|
||||
previous & (uint16_t)~PCI_MSI_CTRL_ENABLE);
|
||||
}
|
||||
KeInterruptDisconnect(request->Interrupt);
|
||||
request->Interrupt = (KE_INTERRUPT*)0;
|
||||
if (request->BusContext) {
|
||||
MmFreePool(request->BusContext);
|
||||
request->BusContext = 0;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS PciConnectInterrupts(DEVICE_OBJECT* pdo,
|
||||
PCI_INTERRUPT_REQUEST* requests, uint32_t count, bool* usingMessages) {
|
||||
PCI_PDO_EXTENSION* ext;
|
||||
if (!PciIsPdo(pdo, &ext) || !requests || !count || !usingMessages)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*usingMessages = false;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!requests[i].Routine) return NTLSTATUS_INVALID_PARAMETER;
|
||||
requests[i].Interrupt = (KE_INTERRUPT*)0;
|
||||
requests[i].BusContext = 0;
|
||||
}
|
||||
KSTATUS st = PciConnectMsix(pdo, ext, requests, count);
|
||||
if (KSUCCESS(st)) { *usingMessages = true; return st; }
|
||||
if (count > 1u) return st;
|
||||
st = PciConnectMsi(pdo, ext, requests);
|
||||
if (KSUCCESS(st)) { *usingMessages = true; return st; }
|
||||
uint8_t line = ext->Info.InterruptLine;
|
||||
uint8_t pin = ext->Info.InterruptPin;
|
||||
if (pin < 1u || pin > 4u || line == 0u || line == 0xFFu) {
|
||||
DbgPrint("pci: INTx resource unavailable for %02x:%02x.%u pin=%u line=%u\n",
|
||||
ext->Info.Address.Bus, ext->Info.Address.Device,
|
||||
ext->Info.Address.Function, pin, line);
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
// The Interrupt Line register is a firmware hint until PCI _PRT routing is available.
|
||||
DbgPrint("pci: INTx legacy route %02x:%02x.%u pin=%u line=%u\n",
|
||||
ext->Info.Address.Bus, ext->Info.Address.Device,
|
||||
ext->Info.Address.Function, pin, line);
|
||||
if (line < 16u)
|
||||
st = KeInterruptConnectIsa(line, 0x0Fu, requests[0].Affinity,
|
||||
requests[0].Routine, requests[0].Context, &requests[0].Interrupt);
|
||||
else
|
||||
st = KeInterruptConnectGsi(line, 0x0Fu, requests[0].Affinity,
|
||||
requests[0].Routine, requests[0].Context, &requests[0].Interrupt);
|
||||
if (KSUCCESS(st)) {
|
||||
uint16_t command = PciRawRead16(ext->Info.Address.Bus,
|
||||
ext->Info.Address.Device, ext->Info.Address.Function, PCI_REG_COMMAND_STATUS);
|
||||
PciRawWrite16(ext->Info.Address.Bus, ext->Info.Address.Device,
|
||||
ext->Info.Address.Function, PCI_REG_COMMAND_STATUS,
|
||||
command & (uint16_t)~PCI_COMMAND_INTX_DISABLE);
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
__declspec(dllexport) void PciDisconnectInterrupts(DEVICE_OBJECT* pdo,
|
||||
PCI_INTERRUPT_REQUEST* requests, uint32_t count) {
|
||||
PCI_PDO_EXTENSION* ext;
|
||||
if (!PciIsPdo(pdo, &ext) || !requests) return;
|
||||
// Close every route before disabling PCI delivery so an affinity update
|
||||
// cannot resume the device after its disconnect has begun.
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
if (requests[i].Interrupt) KeInterruptBeginDisconnect(requests[i].Interrupt);
|
||||
uint8_t bus = ext->Info.Address.Bus, dev = ext->Info.Address.Device;
|
||||
uint8_t fn = ext->Info.Address.Function;
|
||||
uint8_t msi = PciFindCapability(ext, PCI_CAP_ID_MSI);
|
||||
uint8_t msix = PciFindCapability(ext, PCI_CAP_ID_MSIX);
|
||||
if (msi) {
|
||||
uint16_t control = PciRawRead16(bus, dev, fn, msi + 2u);
|
||||
PciRawWrite16(bus, dev, fn, msi + 2u, control & ~PCI_MSI_CTRL_ENABLE);
|
||||
}
|
||||
if (msix) {
|
||||
uint16_t control = PciRawRead16(bus, dev, fn, msix + 2u);
|
||||
PciRawWrite16(bus, dev, fn, msix + 2u, (control | 0x4000u) & ~0x8000u);
|
||||
}
|
||||
uint16_t command = PciRawRead16(bus, dev, fn, PCI_REG_COMMAND_STATUS);
|
||||
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, command | PCI_COMMAND_INTX_DISABLE);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (requests[i].Interrupt) {
|
||||
KeInterruptDisconnect(requests[i].Interrupt);
|
||||
requests[i].Interrupt = (KE_INTERRUPT*)0;
|
||||
}
|
||||
if (requests[i].BusContext) {
|
||||
MmFreePool(requests[i].BusContext);
|
||||
requests[i].BusContext = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static KSTATUS DriverInitialize(NTL_MODULE* module) {
|
||||
(void)module;
|
||||
|
||||
|
||||
Reference in new issue
Block a user