Files
nt-lite/code/drivers/net/rtl816x/rtl816x_pci.c
T

127 lines
3.8 KiB
C

// rtl816x_pci.c - PCI BAR/MMIO front-end for rtl816x.
#include "rtl816x.h"
bool RtlFindDevice(uint8_t* outBus, uint8_t* outDev, uint8_t* outFn, uint16_t* outDeviceId) {
if (gHal->Pci.FindDevice(RTL_VENDOR_REALTEK, RTL_DEVICE_8168, outBus, outDev, outFn)) {
*outDeviceId = RTL_DEVICE_8168;
return true;
}
if (gHal->Pci.FindDevice(RTL_VENDOR_REALTEK, RTL_DEVICE_8169, outBus, outDev, outFn)) {
*outDeviceId = RTL_DEVICE_8169;
return true;
}
return false;
}
bool RtlReadBar(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t index, RTL_BAR* out) {
uint8_t reg = (uint8_t)(PCI_REG_BAR0 + index * 4u);
uint32_t lo = gHal->Pci.Read32(bus, dev, fn, reg);
out->Kind = RtlBarNone;
out->Base = 0;
out->Index = index;
if (lo == 0 || lo == 0xFFFFFFFFu)
return false;
if (lo & 1u) {
uint32_t base = lo & ~0x3u;
if (!base) return false;
out->Kind = RtlBarIo;
out->Base = base;
return true;
}
uint64_t base = (uint64_t)(lo & ~0xFu);
uint32_t type = (lo >> 1) & 0x3u;
if (type == 0x2u && index < 5) {
uint32_t hi = gHal->Pci.Read32(bus, dev, fn, (uint8_t)(reg + 4u));
base |= ((uint64_t)hi << 32);
}
if (!base) return false;
out->Kind = RtlBarMmio;
out->Base = base;
return true;
}
KSTATUS RtlMapMmio(uint64_t physBase, volatile uint8_t** outMmio) {
uint64_t pageBase = physBase & PAGE_MASK;
uint64_t pageOff = physBase - pageBase;
for (uint32_t i = 0; i < RTL_MMIO_PAGES; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys);
KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st))
return st;
}
*outMmio = (volatile uint8_t*)((uintptr_t)gHal->PhysToVirt(pageBase) + pageOff);
return STATUS_SUCCESS;
}
KSTATUS RtlSelectRegisterBar(RTL816X_DEVICE* r) {
RTL_BAR best = { RtlBarNone, 0, 0 };
RTL_BAR fallback = { RtlBarNone, 0, 0 };
for (uint8_t i = 0; i < 6; i++) {
RTL_BAR bar;
if (!RtlReadBar(r->Bus, r->Dev, r->Fn, i, &bar))
continue;
if (bar.Kind == RtlBarMmio) {
best = bar;
break;
}
if (bar.Kind == RtlBarIo && fallback.Kind == RtlBarNone)
fallback = bar;
// Skip the high dword of 64-bit memory BARs.
if (bar.Kind == RtlBarMmio) {
uint32_t lo = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, (uint8_t)(PCI_REG_BAR0 + i * 4u));
if (((lo >> 1) & 0x3u) == 0x2u)
i++;
}
}
if (best.Kind == RtlBarNone)
best = fallback;
if (best.Kind == RtlBarMmio) {
KSTATUS st = RtlMapMmio(best.Base, &r->Mmio);
if (!KSUCCESS(st))
return st;
r->UseMmio = true;
DbgPrint("RTL816X: BAR%u MMIO base=0x%016llX virt=0x%016llX\n",
best.Index, (unsigned long long)best.Base, r->Mmio);
return STATUS_SUCCESS;
}
if (best.Kind == RtlBarIo) {
if (best.Base > 0xFFFFu)
return STATUS_NOT_SUPPORTED;
r->IoBase = (uint16_t)best.Base;
r->UseMmio = false;
DbgPrint("RTL816X: BAR%u I/O base=0x%04x\n", best.Index, r->IoBase);
return STATUS_SUCCESS;
}
return STATUS_NOT_FOUND;
}
void RtlEnablePci(RTL816X_DEVICE* r) {
uint32_t cmd = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND);
cmd |= PCI_COMMAND_MASTER;
if (r->UseMmio) cmd |= PCI_COMMAND_MEMORY;
else cmd |= PCI_COMMAND_IO;
cmd &= ~PCI_COMMAND_INTX_DISABLE;
gHal->Pci.Write32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND, cmd);
}